1 /* 2 * This file is part of the WebKit project. 3 * 4 * Copyright (C) 2006 Apple Computer, Inc. 5 * Copyright (C) 2008, 2009 Google, Inc. 6 * Copyright (C) 2009 Kenneth Rohde Christiansen 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 21 * Boston, MA 02111-1307, USA. 22 * 23 */ 24 25 #include "config.h" 26 #include "RenderThemeChromiumWin.h" 27 28 #include <windows.h> 29 #include <uxtheme.h> 30 #include <vssym32.h> 31 32 #include "ChromiumBridge.h" 33 #include "CSSValueKeywords.h" 34 #include "FontSelector.h" 35 #include "FontUtilsChromiumWin.h" 36 #include "GraphicsContext.h" 37 #include "HTMLMediaElement.h" 38 #include "HTMLNames.h" 39 #include "MediaControlElements.h" 40 #include "RenderBox.h" 41 #include "RenderSlider.h" 42 #include "ScrollbarTheme.h" 43 #include "TransparencyWin.h" 44 #include "WindowsVersion.h" 45 46 // FIXME: This dependency should eventually be removed. 47 #include <skia/ext/skia_utils_win.h> 48 49 #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \ 50 offsetof(structName, member) + \ 51 (sizeof static_cast<structName*>(0)->member) 52 #define NONCLIENTMETRICS_SIZE_PRE_VISTA \ 53 SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) 54 55 namespace WebCore { 56 57 namespace { 58 class ThemePainter : public TransparencyWin { 59 public: 60 ThemePainter(GraphicsContext* context, const IntRect& r) 61 { 62 TransformMode transformMode = getTransformMode(context->getCTM()); 63 init(context, getLayerMode(context, transformMode), transformMode, r); 64 } 65 66 ~ThemePainter() 67 { 68 composite(); 69 } 70 71 private: 72 static bool canvasHasMultipleLayers(const SkCanvas* canvas) 73 { 74 SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false); 75 iter.next(); // There is always at least one layer. 76 return !iter.done(); // There is > 1 layer if the the iterator can stil advance. 77 } 78 79 static LayerMode getLayerMode(GraphicsContext* context, TransformMode transformMode) 80 { 81 if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background. 82 return WhiteLayer; 83 else if (canvasHasMultipleLayers(context->platformContext()->canvas())) // Needs antialiasing help. 84 return OpaqueCompositeLayer; 85 else // Nothing interesting. 86 return transformMode == KeepTransform ? NoLayer : OpaqueCompositeLayer; 87 } 88 89 static TransformMode getTransformMode(const AffineTransform& matrix) 90 { 91 if (matrix.b() != 0 || matrix.c() != 0) // Skew. 92 return Untransform; 93 else if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale. 94 return ScaleTransform; 95 else // Nothing interesting. 96 return KeepTransform; 97 } 98 }; 99 100 } // namespace 101 102 static void getNonClientMetrics(NONCLIENTMETRICS* metrics) 103 { 104 static UINT size = WebCore::isVistaOrNewer() ? 105 sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; 106 metrics->cbSize = size; 107 bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0); 108 ASSERT(success); 109 } 110 111 static FontDescription smallSystemFont; 112 static FontDescription menuFont; 113 static FontDescription labelFont; 114 115 // Internal static helper functions. We don't put them in an anonymous 116 // namespace so they have easier access to the WebCore namespace. 117 118 static bool supportsFocus(ControlPart appearance) 119 { 120 switch (appearance) { 121 case PushButtonPart: 122 case ButtonPart: 123 case DefaultButtonPart: 124 case SearchFieldPart: 125 case TextFieldPart: 126 case TextAreaPart: 127 return true; 128 } 129 return false; 130 } 131 132 // Return the height of system font |font| in pixels. We use this size by 133 // default for some non-form-control elements. 134 static float systemFontSize(const LOGFONT& font) 135 { 136 float size = -font.lfHeight; 137 if (size < 0) { 138 HFONT hFont = CreateFontIndirect(&font); 139 if (hFont) { 140 HDC hdc = GetDC(0); // What about printing? Is this the right DC? 141 if (hdc) { 142 HGDIOBJ hObject = SelectObject(hdc, hFont); 143 TEXTMETRIC tm; 144 GetTextMetrics(hdc, &tm); 145 SelectObject(hdc, hObject); 146 ReleaseDC(0, hdc); 147 size = tm.tmAscent; 148 } 149 DeleteObject(hFont); 150 } 151 } 152 153 // The "codepage 936" bit here is from Gecko; apparently this helps make 154 // fonts more legible in Simplified Chinese where the default font size is 155 // too small. 156 // 157 // FIXME: http://b/1119883 Since this is only used for "small caption", 158 // "menu", and "status bar" objects, I'm not sure how much this even 159 // matters. Plus the Gecko patch went in back in 2002, and maybe this 160 // isn't even relevant anymore. We should investigate whether this should 161 // be removed, or perhaps broadened to be "any CJK locale". 162 // 163 return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size; 164 } 165 166 // Converts |points| to pixels. One point is 1/72 of an inch. 167 static float pointsToPixels(float points) 168 { 169 static float pixelsPerInch = 0.0f; 170 if (!pixelsPerInch) { 171 HDC hdc = GetDC(0); // What about printing? Is this the right DC? 172 if (hdc) { // Can this ever actually be NULL? 173 pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY); 174 ReleaseDC(0, hdc); 175 } else { 176 pixelsPerInch = 96.0f; 177 } 178 } 179 180 static const float pointsPerInch = 72.0f; 181 return points / pointsPerInch * pixelsPerInch; 182 } 183 184 static double querySystemBlinkInterval(double defaultInterval) 185 { 186 UINT blinkTime = GetCaretBlinkTime(); 187 if (blinkTime == 0) 188 return defaultInterval; 189 if (blinkTime == INFINITE) 190 return 0; 191 return blinkTime / 1000.0; 192 } 193 194 PassRefPtr<RenderTheme> RenderThemeChromiumWin::create() 195 { 196 return adoptRef(new RenderThemeChromiumWin); 197 } 198 199 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) 200 { 201 static RenderTheme* rt = RenderThemeChromiumWin::create().releaseRef(); 202 return rt; 203 } 204 205 bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const 206 { 207 // Let webkit draw one of its halo rings around any focused element, 208 // except push buttons. For buttons we use the windows PBS_DEFAULTED 209 // styling to give it a blue border. 210 return style->appearance() == ButtonPart 211 || style->appearance() == PushButtonPart; 212 } 213 214 Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const 215 { 216 if (ChromiumBridge::layoutTestMode()) 217 return Color(0x00, 0x00, 0xff); // Royal blue. 218 COLORREF color = GetSysColor(COLOR_HIGHLIGHT); 219 return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); 220 } 221 222 Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const 223 { 224 if (ChromiumBridge::layoutTestMode()) 225 return Color(0x99, 0x99, 0x99); // Medium gray. 226 COLORREF color = GetSysColor(COLOR_GRAYTEXT); 227 return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); 228 } 229 230 Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const 231 { 232 if (ChromiumBridge::layoutTestMode()) 233 return Color(0xff, 0xff, 0xcc); // Pale yellow. 234 COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT); 235 return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); 236 } 237 238 Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const 239 { 240 return Color::white; 241 } 242 243 Color RenderThemeChromiumWin::platformActiveTextSearchHighlightColor() const 244 { 245 return Color(0xff, 0x96, 0x32); // Orange. 246 } 247 248 Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const 249 { 250 return Color(0xff, 0xff, 0x96); // Yellow. 251 } 252 253 void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescription) const 254 { 255 // This logic owes much to RenderThemeSafari.cpp. 256 FontDescription* cachedDesc = 0; 257 AtomicString faceName; 258 float fontSize = 0; 259 switch (propId) { 260 case CSSValueSmallCaption: 261 cachedDesc = &smallSystemFont; 262 if (!smallSystemFont.isAbsoluteSize()) { 263 NONCLIENTMETRICS metrics; 264 getNonClientMetrics(&metrics); 265 faceName = AtomicString(metrics.lfSmCaptionFont.lfFaceName, wcslen(metrics.lfSmCaptionFont.lfFaceName)); 266 fontSize = systemFontSize(metrics.lfSmCaptionFont); 267 } 268 break; 269 case CSSValueMenu: 270 cachedDesc = &menuFont; 271 if (!menuFont.isAbsoluteSize()) { 272 NONCLIENTMETRICS metrics; 273 getNonClientMetrics(&metrics); 274 faceName = AtomicString(metrics.lfMenuFont.lfFaceName, wcslen(metrics.lfMenuFont.lfFaceName)); 275 fontSize = systemFontSize(metrics.lfMenuFont); 276 } 277 break; 278 case CSSValueStatusBar: 279 cachedDesc = &labelFont; 280 if (!labelFont.isAbsoluteSize()) { 281 NONCLIENTMETRICS metrics; 282 getNonClientMetrics(&metrics); 283 faceName = metrics.lfStatusFont.lfFaceName; 284 fontSize = systemFontSize(metrics.lfStatusFont); 285 } 286 break; 287 case CSSValueWebkitMiniControl: 288 case CSSValueWebkitSmallControl: 289 case CSSValueWebkitControl: 290 faceName = defaultGUIFont(); 291 // Why 2 points smaller? Because that's what Gecko does. 292 fontSize = defaultFontSize - pointsToPixels(2); 293 break; 294 default: 295 faceName = defaultGUIFont(); 296 fontSize = defaultFontSize; 297 break; 298 } 299 300 if (!cachedDesc) 301 cachedDesc = &fontDescription; 302 303 if (fontSize) { 304 cachedDesc->firstFamily().setFamily(faceName); 305 cachedDesc->setIsAbsoluteSize(true); 306 cachedDesc->setGenericFamily(FontDescription::NoFamily); 307 cachedDesc->setSpecifiedSize(fontSize); 308 cachedDesc->setWeight(FontWeightNormal); 309 cachedDesc->setItalic(false); 310 } 311 fontDescription = *cachedDesc; 312 } 313 314 // Map a CSSValue* system color to an index understood by GetSysColor(). 315 static int cssValueIdToSysColorIndex(int cssValueId) 316 { 317 switch (cssValueId) { 318 case CSSValueActiveborder: return COLOR_ACTIVEBORDER; 319 case CSSValueActivecaption: return COLOR_ACTIVECAPTION; 320 case CSSValueAppworkspace: return COLOR_APPWORKSPACE; 321 case CSSValueBackground: return COLOR_BACKGROUND; 322 case CSSValueButtonface: return COLOR_BTNFACE; 323 case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT; 324 case CSSValueButtonshadow: return COLOR_BTNSHADOW; 325 case CSSValueButtontext: return COLOR_BTNTEXT; 326 case CSSValueCaptiontext: return COLOR_CAPTIONTEXT; 327 case CSSValueGraytext: return COLOR_GRAYTEXT; 328 case CSSValueHighlight: return COLOR_HIGHLIGHT; 329 case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT; 330 case CSSValueInactiveborder: return COLOR_INACTIVEBORDER; 331 case CSSValueInactivecaption: return COLOR_INACTIVECAPTION; 332 case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT; 333 case CSSValueInfobackground: return COLOR_INFOBK; 334 case CSSValueInfotext: return COLOR_INFOTEXT; 335 case CSSValueMenu: return COLOR_MENU; 336 case CSSValueMenutext: return COLOR_MENUTEXT; 337 case CSSValueScrollbar: return COLOR_SCROLLBAR; 338 case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW; 339 case CSSValueThreedface: return COLOR_3DFACE; 340 case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT; 341 case CSSValueThreedlightshadow: return COLOR_3DLIGHT; 342 case CSSValueThreedshadow: return COLOR_3DSHADOW; 343 case CSSValueWindow: return COLOR_WINDOW; 344 case CSSValueWindowframe: return COLOR_WINDOWFRAME; 345 case CSSValueWindowtext: return COLOR_WINDOWTEXT; 346 default: return -1; // Unsupported CSSValue 347 } 348 } 349 350 Color RenderThemeChromiumWin::systemColor(int cssValueId) const 351 { 352 int sysColorIndex = cssValueIdToSysColorIndex(cssValueId); 353 if (ChromiumBridge::layoutTestMode() || (sysColorIndex == -1)) 354 return RenderTheme::systemColor(cssValueId); 355 356 COLORREF color = GetSysColor(sysColorIndex); 357 return Color(GetRValue(color), GetGValue(color), GetBValue(color)); 358 } 359 360 void RenderThemeChromiumWin::adjustSliderThumbSize(RenderObject* o) const 361 { 362 // These sizes match what WinXP draws for various menus. 363 const int sliderThumbAlongAxis = 11; 364 const int sliderThumbAcrossAxis = 21; 365 if (o->style()->appearance() == SliderThumbHorizontalPart) { 366 o->style()->setWidth(Length(sliderThumbAlongAxis, Fixed)); 367 o->style()->setHeight(Length(sliderThumbAcrossAxis, Fixed)); 368 } else if (o->style()->appearance() == SliderThumbVerticalPart) { 369 o->style()->setWidth(Length(sliderThumbAcrossAxis, Fixed)); 370 o->style()->setHeight(Length(sliderThumbAlongAxis, Fixed)); 371 } else 372 RenderThemeChromiumSkia::adjustSliderThumbSize(o); 373 } 374 375 bool RenderThemeChromiumWin::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 376 { 377 return paintButton(o, i, r); 378 } 379 bool RenderThemeChromiumWin::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 380 { 381 return paintButton(o, i, r); 382 } 383 384 bool RenderThemeChromiumWin::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 385 { 386 const ThemeData& themeData = getThemeData(o); 387 388 WebCore::ThemePainter painter(i.context, r); 389 ChromiumBridge::paintButton(painter.context(), 390 themeData.m_part, 391 themeData.m_state, 392 themeData.m_classicState, 393 painter.drawRect()); 394 return false; 395 } 396 397 bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 398 { 399 return paintTextFieldInternal(o, i, r, true); 400 } 401 402 bool RenderThemeChromiumWin::paintSliderTrack(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 403 { 404 const ThemeData& themeData = getThemeData(o); 405 406 WebCore::ThemePainter painter(i.context, r); 407 ChromiumBridge::paintTrackbar(painter.context(), 408 themeData.m_part, 409 themeData.m_state, 410 themeData.m_classicState, 411 painter.drawRect()); 412 return false; 413 } 414 415 bool RenderThemeChromiumWin::paintSliderThumb(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 416 { 417 return paintSliderTrack(o, i, r); 418 } 419 420 // Used to paint unstyled menulists (i.e. with the default border) 421 bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) 422 { 423 if (!o->isBox()) 424 return false; 425 426 const RenderBox* box = toRenderBox(o); 427 int borderRight = box->borderRight(); 428 int borderLeft = box->borderLeft(); 429 int borderTop = box->borderTop(); 430 int borderBottom = box->borderBottom(); 431 432 // If all the borders are 0, then tell skia not to paint the border on the 433 // textfield. FIXME: http://b/1210017 Figure out how to get Windows to not 434 // draw individual borders and then pass that to skia so we can avoid 435 // drawing any borders that are set to 0. For non-zero borders, we draw the 436 // border, but webkit just draws over it. 437 bool drawEdges = !(borderRight == 0 && borderLeft == 0 && borderTop == 0 && borderBottom == 0); 438 439 paintTextFieldInternal(o, i, r, drawEdges); 440 441 // Take padding and border into account. If the MenuList is smaller than 442 // the size of a button, make sure to shrink it appropriately and not put 443 // its x position to the left of the menulist. 444 const int buttonWidth = GetSystemMetrics(SM_CXVSCROLL); 445 int spacingLeft = borderLeft + box->paddingLeft(); 446 int spacingRight = borderRight + box->paddingRight(); 447 int spacingTop = borderTop + box->paddingTop(); 448 int spacingBottom = borderBottom + box->paddingBottom(); 449 450 int buttonX; 451 if (r.right() - r.x() < buttonWidth) 452 buttonX = r.x(); 453 else 454 buttonX = o->style()->direction() == LTR ? r.right() - spacingRight - buttonWidth : r.x() + spacingLeft; 455 456 // Compute the rectangle of the button in the destination image. 457 IntRect rect(buttonX, 458 r.y() + spacingTop, 459 std::min(buttonWidth, r.right() - r.x()), 460 r.height() - (spacingTop + spacingBottom)); 461 462 // Get the correct theme data for a textfield and paint the menu. 463 WebCore::ThemePainter painter(i.context, rect); 464 ChromiumBridge::paintMenuList(painter.context(), 465 CP_DROPDOWNBUTTON, 466 determineState(o), 467 determineClassicState(o), 468 painter.drawRect()); 469 return false; 470 } 471 472 // static 473 void RenderThemeChromiumWin::setDefaultFontSize(int fontSize) 474 { 475 RenderThemeChromiumSkia::setDefaultFontSize(fontSize); 476 477 // Reset cached fonts. 478 smallSystemFont = menuFont = labelFont = FontDescription(); 479 } 480 481 double RenderThemeChromiumWin::caretBlinkIntervalInternal() const 482 { 483 // This involves a system call, so we cache the result. 484 static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval()); 485 return blinkInterval; 486 } 487 488 unsigned RenderThemeChromiumWin::determineState(RenderObject* o) 489 { 490 unsigned result = TS_NORMAL; 491 ControlPart appearance = o->style()->appearance(); 492 if (!isEnabled(o)) 493 result = TS_DISABLED; 494 else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance || SearchFieldPart == appearance)) 495 result = ETS_READONLY; // Readonly is supported on textfields. 496 else if (isPressed(o)) // Active overrides hover and focused. 497 result = TS_PRESSED; 498 else if (supportsFocus(appearance) && isFocused(o)) 499 result = ETS_FOCUSED; 500 else if (isHovered(o)) 501 result = TS_HOT; 502 if (isChecked(o)) 503 result += 4; // 4 unchecked states, 4 checked states. 504 return result; 505 } 506 507 unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o) 508 { 509 unsigned result = TUS_NORMAL; 510 if (!isEnabled(o->parent())) 511 result = TUS_DISABLED; 512 else if (supportsFocus(o->style()->appearance()) && isFocused(o->parent())) 513 result = TUS_FOCUSED; 514 else if (toRenderSlider(o->parent())->inDragMode()) 515 result = TUS_PRESSED; 516 else if (isHovered(o)) 517 result = TUS_HOT; 518 return result; 519 } 520 521 unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o) 522 { 523 unsigned result = 0; 524 525 ControlPart part = o->style()->appearance(); 526 527 // Sliders are always in the normal state. 528 if (part == SliderHorizontalPart || part == SliderVerticalPart) 529 return result; 530 531 // So are readonly text fields. 532 if (isReadOnlyControl(o) && (part == TextFieldPart || part == TextAreaPart || part == SearchFieldPart)) 533 return result; 534 535 if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) { 536 if (!isEnabled(o->parent())) 537 result = DFCS_INACTIVE; 538 else if (toRenderSlider(o->parent())->inDragMode()) // Active supersedes hover 539 result = DFCS_PUSHED; 540 else if (isHovered(o)) 541 result = DFCS_HOT; 542 } else { 543 if (!isEnabled(o)) 544 result = DFCS_INACTIVE; 545 else if (isPressed(o)) // Active supersedes hover 546 result = DFCS_PUSHED; 547 else if (supportsFocus(part) && isFocused(o)) // So does focused 548 result = 0; 549 else if (isHovered(o)) 550 result = DFCS_HOT; 551 if (isChecked(o)) 552 result |= DFCS_CHECKED; 553 } 554 return result; 555 } 556 557 ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o) 558 { 559 ThemeData result; 560 switch (o->style()->appearance()) { 561 case CheckboxPart: 562 result.m_part = BP_CHECKBOX; 563 result.m_state = determineState(o); 564 result.m_classicState = DFCS_BUTTONCHECK; 565 break; 566 case RadioPart: 567 result.m_part = BP_RADIOBUTTON; 568 result.m_state = determineState(o); 569 result.m_classicState = DFCS_BUTTONRADIO; 570 break; 571 case PushButtonPart: 572 case ButtonPart: 573 result.m_part = BP_PUSHBUTTON; 574 result.m_state = determineState(o); 575 result.m_classicState = DFCS_BUTTONPUSH; 576 break; 577 case SliderHorizontalPart: 578 result.m_part = TKP_TRACK; 579 result.m_state = TRS_NORMAL; 580 break; 581 case SliderVerticalPart: 582 result.m_part = TKP_TRACKVERT; 583 result.m_state = TRVS_NORMAL; 584 break; 585 case SliderThumbHorizontalPart: 586 result.m_part = TKP_THUMBBOTTOM; 587 result.m_state = determineSliderThumbState(o); 588 break; 589 case SliderThumbVerticalPart: 590 result.m_part = TKP_THUMBVERT; 591 result.m_state = determineSliderThumbState(o); 592 break; 593 case ListboxPart: 594 case MenulistPart: 595 case MenulistButtonPart: 596 case SearchFieldPart: 597 case TextFieldPart: 598 case TextAreaPart: 599 result.m_part = EP_EDITTEXT; 600 result.m_state = determineState(o); 601 break; 602 } 603 604 result.m_classicState |= determineClassicState(o); 605 606 return result; 607 } 608 609 bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o, 610 const RenderObject::PaintInfo& i, 611 const IntRect& r, 612 bool drawEdges) 613 { 614 // Fallback to white if the specified color object is invalid. 615 // (Note ChromiumBridge::paintTextField duplicates this check). 616 Color backgroundColor(Color::white); 617 if (o->style()->backgroundColor().isValid()) 618 backgroundColor = o->style()->backgroundColor(); 619 620 // If we have background-image, don't fill the content area to expose the 621 // parent's background. Also, we shouldn't fill the content area if the 622 // alpha of the color is 0. The API of Windows GDI ignores the alpha. 623 // 624 // Note that we should paint the content area white if we have neither the 625 // background color nor background image explicitly specified to keep the 626 // appearance of select element consistent with other browsers. 627 bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha(); 628 629 if (o->style()->hasBorderRadius()) { 630 // If the style has rounded borders, setup the context to clip the 631 // background (themed or filled) appropriately. 632 // FIXME: make sure we do the right thing if css background-clip is set. 633 i.context->save(); 634 IntSize topLeft, topRight, bottomLeft, bottomRight; 635 o->style()->getBorderRadiiForRect(r, topLeft, topRight, bottomLeft, bottomRight); 636 i.context->addRoundedRectClip(r, topLeft, topRight, bottomLeft, bottomRight); 637 } 638 { 639 const ThemeData& themeData = getThemeData(o); 640 WebCore::ThemePainter painter(i.context, r); 641 ChromiumBridge::paintTextField(painter.context(), 642 themeData.m_part, 643 themeData.m_state, 644 themeData.m_classicState, 645 painter.drawRect(), 646 backgroundColor, 647 fillContentArea, 648 drawEdges); 649 // End of block commits the painter before restoring context. 650 } 651 if (o->style()->hasBorderRadius()) 652 i.context->restore(); 653 return false; 654 } 655 656 } // namespace WebCore 657