1 /* 2 * Copyright (C) 2007 Kevin Ollivier <kevino (at) theolliviers.com> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "RenderTheme.h" 28 29 #include "Document.h" 30 #include "FrameView.h" 31 #include "GraphicsContext.h" 32 #include "HostWindow.h" 33 #include "NotImplemented.h" 34 #include "PaintInfo.h" 35 #include "RenderView.h" 36 37 #include <wx/defs.h> 38 39 #include <wx/dc.h> 40 #include <wx/dcgraph.h> 41 #include <wx/renderer.h> 42 #include <wx/dcclient.h> 43 #include <wx/scrolwin.h> 44 #include <wx/settings.h> 45 46 namespace WebCore { 47 48 class RenderThemeWx : public RenderTheme { 49 private: 50 RenderThemeWx() : RenderTheme() { } 51 virtual ~RenderThemeWx(); 52 53 public: 54 static PassRefPtr<RenderTheme> create(); 55 56 // A method asking if the theme's controls actually care about redrawing when hovered. 57 virtual bool supportsHover(const RenderStyle*) const { return true; } 58 59 virtual bool paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r) 60 { 61 return paintButton(o, i, r); 62 } 63 64 virtual void setCheckboxSize(RenderStyle*) const; 65 66 virtual bool paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r) 67 { 68 return paintButton(o, i, r); 69 } 70 71 virtual void setRadioSize(RenderStyle*) const; 72 73 virtual void adjustRepaintRect(const RenderObject*, IntRect&); 74 75 virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; 76 virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&); 77 78 virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; 79 virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&); 80 81 virtual int minimumMenuListSize(RenderStyle*) const; 82 83 virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; 84 virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&); 85 86 virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; 87 virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&); 88 89 virtual bool isControlStyled(const RenderStyle*, const BorderData&, 90 const FillLayer&, const Color&) const; 91 92 virtual bool controlSupportsTints(const RenderObject*) const; 93 94 virtual void systemFont(int propId, FontDescription&) const; 95 96 virtual Color platformActiveSelectionBackgroundColor() const; 97 virtual Color platformInactiveSelectionBackgroundColor() const; 98 99 virtual Color platformActiveSelectionForegroundColor() const; 100 virtual Color platformInactiveSelectionForegroundColor() const; 101 102 virtual int popupInternalPaddingLeft(RenderStyle*) const; 103 virtual int popupInternalPaddingRight(RenderStyle*) const; 104 virtual int popupInternalPaddingTop(RenderStyle*) const; 105 virtual int popupInternalPaddingBottom(RenderStyle*) const; 106 107 private: 108 void addIntrinsicMargins(RenderStyle*) const; 109 void close(); 110 111 bool supportsFocus(ControlPart) const; 112 }; 113 114 115 // Constants 116 117 #define MINIMUM_MENU_LIST_SIZE 21 118 #define POPUP_INTERNAL_PADDING_LEFT 6 119 #define POPUP_INTERNAL_PADDING_TOP 2 120 #define POPUP_INTERNAL_PADDING_BOTTOM 2 121 122 #ifdef __WXMAC__ 123 #define POPUP_INTERNAL_PADDING_RIGHT 22 124 #else 125 #define POPUP_INTERNAL_PADDING_RIGHT 20 126 #endif 127 128 RenderThemeWx::~RenderThemeWx() 129 { 130 } 131 132 PassRefPtr<RenderTheme> RenderThemeWx::create() 133 { 134 return adoptRef(new RenderThemeWx()); 135 } 136 137 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) 138 { 139 static RenderTheme* rt = RenderThemeWx::create().releaseRef(); 140 return rt; 141 } 142 143 wxWindow* nativeWindowForRenderObject(RenderObject* o) 144 { 145 FrameView* frameView = o->view()->frameView(); 146 ASSERT(frameView); 147 ASSERT(frameView->hostWindow()); 148 return frameView->hostWindow()->platformPageClient(); 149 } 150 151 152 bool RenderThemeWx::isControlStyled(const RenderStyle* style, const BorderData& border, 153 const FillLayer& background, const Color& backgroundColor) const 154 { 155 if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart) 156 return style->border() != border; 157 158 // Normally CSS can be used to set properties of form controls (such as adding a background bitmap). 159 // However, for this to work RenderThemeWx needs to adjust uncustomized elements (e.g. buttons) to reflect the 160 // changes made by CSS. Since we don't do that right now, the native parts of form elements appear in odd places. 161 // Until we have time to implement that support, we return false here, so that we ignore customizations 162 // and always use the native theme drawing to draw form controls. 163 return false; 164 } 165 166 void RenderThemeWx::adjustRepaintRect(const RenderObject* o, IntRect& r) 167 { 168 switch (o->style()->appearance()) { 169 case MenulistPart: { 170 r.setWidth(r.width() + 100); 171 break; 172 } 173 default: 174 break; 175 } 176 } 177 178 bool RenderThemeWx::controlSupportsTints(const RenderObject* o) const 179 { 180 if (!isEnabled(o)) 181 return false; 182 183 // Checkboxes only have tint when checked. 184 if (o->style()->appearance() == CheckboxPart) 185 return isChecked(o); 186 187 // For now assume other controls have tint if enabled. 188 return true; 189 } 190 191 void RenderThemeWx::systemFont(int propId, FontDescription& fontDescription) const 192 { 193 // no-op 194 } 195 196 void RenderThemeWx::addIntrinsicMargins(RenderStyle* style) const 197 { 198 // Cut out the intrinsic margins completely if we end up using a small font size 199 if (style->fontSize() < 11) 200 return; 201 202 // Intrinsic margin value. 203 const int m = 2; 204 205 // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed. 206 if (style->width().isIntrinsicOrAuto()) { 207 if (style->marginLeft().quirk()) 208 style->setMarginLeft(Length(m, Fixed)); 209 210 if (style->marginRight().quirk()) 211 style->setMarginRight(Length(m, Fixed)); 212 } 213 214 if (style->height().isAuto()) { 215 if (style->marginTop().quirk()) 216 style->setMarginTop(Length(m, Fixed)); 217 218 if (style->marginBottom().quirk()) 219 style->setMarginBottom(Length(m, Fixed)); 220 } 221 } 222 223 void RenderThemeWx::setCheckboxSize(RenderStyle* style) const 224 { 225 // If the width and height are both specified, then we have nothing to do. 226 if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) 227 return; 228 229 // FIXME: A hard-coded size of 13 is used. This is wrong but necessary for now. It matches Firefox. 230 // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for 231 // the higher DPI. Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's 232 // metrics. 233 if (style->width().isIntrinsicOrAuto()) 234 style->setWidth(Length(13, Fixed)); 235 236 if (style->height().isAuto()) 237 style->setHeight(Length(13, Fixed)); 238 } 239 240 void RenderThemeWx::setRadioSize(RenderStyle* style) const 241 { 242 // This is the same as checkboxes. 243 setCheckboxSize(style); 244 } 245 246 bool RenderThemeWx::supportsFocus(ControlPart part) const 247 { 248 switch (part) { 249 case PushButtonPart: 250 case ButtonPart: 251 case TextFieldPart: 252 return true; 253 default: // No for all others... 254 return false; 255 } 256 } 257 258 void RenderThemeWx::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const 259 { 260 addIntrinsicMargins(style); 261 } 262 263 bool RenderThemeWx::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r) 264 { 265 wxWindow* window = nativeWindowForRenderObject(o); 266 wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); 267 int flags = 0; 268 269 IntRect rect = r; 270 271 // On Mac, wxGraphicsContext and wxDC share the same native implementation, 272 // and so transformations are available. 273 // On Win and Linux, however, this is not true and transforms are lost, 274 // so we need to restore them here. 275 #if USE(WXGC) && !defined(__WXMAC__) 276 double xtrans = 0; 277 double ytrans = 0; 278 279 wxGCDC* gcdc = static_cast<wxGCDC*>(dc); 280 wxGraphicsContext* gc = gcdc->GetGraphicsContext(); 281 gc->GetTransform().TransformPoint(&xtrans, &ytrans); 282 rect.setX(r.x() + (int)xtrans); 283 rect.setY(r.y() + (int)ytrans); 284 #endif 285 286 if (!isEnabled(o)) 287 flags |= wxCONTROL_DISABLED; 288 289 ControlPart part = o->style()->appearance(); 290 if (supportsFocus(part) && isFocused(o)) 291 flags |= wxCONTROL_FOCUSED; 292 293 if (isPressed(o)) 294 flags |= wxCONTROL_PRESSED; 295 296 if (part == PushButtonPart || part == ButtonPart) 297 wxRendererNative::Get().DrawPushButton(window, *dc, rect, flags); 298 else if(part == RadioPart) { 299 if (isChecked(o)) 300 flags |= wxCONTROL_CHECKED; 301 #if wxCHECK_VERSION(2,9,1) 302 wxRendererNative::Get().DrawRadioBitmap(window, *dc, rect, flags); 303 #elif wxCHECK_VERSION(2,9,0) 304 wxRendererNative::Get().DrawRadioButton(window, *dc, rect, flags); 305 #else 306 wxRenderer_DrawRadioButton(window, *dc, rect, flags); 307 #endif 308 } 309 else if(part == CheckboxPart) { 310 if (isChecked(o)) 311 flags |= wxCONTROL_CHECKED; 312 wxRendererNative::Get().DrawCheckBox(window, *dc, rect, flags); 313 } 314 return false; 315 } 316 317 void RenderThemeWx::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 318 { 319 320 } 321 322 bool RenderThemeWx::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r) 323 { 324 wxWindow* window = nativeWindowForRenderObject(o); 325 wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); 326 #if wxCHECK_VERSION(2,9,0) 327 wxRendererNative::Get().DrawTextCtrl(window, *dc, r, 0); 328 #else 329 wxRenderer_DrawTextCtrl(window, *dc, r, 0); 330 #endif 331 332 return false; 333 } 334 335 int RenderThemeWx::minimumMenuListSize(RenderStyle*) const 336 { 337 return MINIMUM_MENU_LIST_SIZE; 338 } 339 340 void RenderThemeWx::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 341 { 342 } 343 344 bool RenderThemeWx::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r) 345 { 346 wxWindow* window = nativeWindowForRenderObject(o); 347 wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); 348 349 int flags = 0; 350 if (!isEnabled(o)) 351 flags |= wxCONTROL_DISABLED; 352 353 if (supportsFocus(o->style()->appearance()) && isFocused(o)) 354 flags |= wxCONTROL_FOCUSED; 355 356 if (isPressed(o)) 357 flags |= wxCONTROL_PRESSED; 358 359 #if wxCHECK_VERSION(2,9,0) 360 wxRendererNative::Get().DrawChoice(window, *dc, r, flags); 361 #else 362 wxRenderer_DrawChoice(window, *dc, r, flags); 363 #endif 364 365 return false; 366 } 367 368 void RenderThemeWx::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const 369 { 370 notImplemented(); 371 } 372 373 bool RenderThemeWx::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& r) 374 { 375 wxWindow* window = nativeWindowForRenderObject(o); 376 wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); 377 378 int flags = 0; 379 if (!isEnabled(o)) 380 flags |= wxCONTROL_DISABLED; 381 382 if (supportsFocus(o->style()->appearance()) && isFocused(o)) 383 flags |= wxCONTROL_FOCUSED; 384 385 if (isPressed(o)) 386 flags |= wxCONTROL_PRESSED; 387 388 wxRendererNative::Get().DrawComboBoxDropButton(window, *dc, r, flags); 389 390 return false; 391 } 392 393 394 Color RenderThemeWx::platformActiveSelectionBackgroundColor() const 395 { 396 return wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); 397 } 398 399 Color RenderThemeWx::platformInactiveSelectionBackgroundColor() const 400 { 401 return wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW); 402 } 403 404 Color RenderThemeWx::platformActiveSelectionForegroundColor() const 405 { 406 // FIXME: Get wx to return the correct value for each platform. 407 #if __WXMAC__ 408 return Color(); 409 #else 410 return Color(255, 255, 255); 411 #endif 412 } 413 414 Color RenderThemeWx::platformInactiveSelectionForegroundColor() const 415 { 416 #if __WXMAC__ 417 return Color(); 418 #else 419 return Color(255, 255, 255); 420 #endif 421 } 422 423 int RenderThemeWx::popupInternalPaddingLeft(RenderStyle*) const 424 { 425 return POPUP_INTERNAL_PADDING_LEFT; 426 } 427 428 int RenderThemeWx::popupInternalPaddingRight(RenderStyle*) const 429 { 430 return POPUP_INTERNAL_PADDING_RIGHT; 431 } 432 433 int RenderThemeWx::popupInternalPaddingTop(RenderStyle*) const 434 { 435 return POPUP_INTERNAL_PADDING_TOP; 436 } 437 438 int RenderThemeWx::popupInternalPaddingBottom(RenderStyle*) const 439 { 440 return POPUP_INTERNAL_PADDING_BOTTOM; 441 } 442 443 } 444 445