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 "CSSValueKeywords.h" 33 #include "CurrentTime.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 "PaintInfo.h" 41 #include "PlatformBridge.h" 42 #include "RenderBox.h" 43 #include "RenderProgress.h" 44 #include "RenderSlider.h" 45 #include "ScrollbarTheme.h" 46 #include "SystemInfo.h" 47 #include "TransparencyWin.h" 48 49 // FIXME: This dependency should eventually be removed. 50 #include <skia/ext/skia_utils_win.h> 51 52 #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \ 53 offsetof(structName, member) + \ 54 (sizeof static_cast<structName*>(0)->member) 55 #define NONCLIENTMETRICS_SIZE_PRE_VISTA \ 56 SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) 57 58 namespace WebCore { 59 60 // The standard width for the menu list drop-down button when run under 61 // layout test mode. Use the value that's currently captured in most baselines. 62 static const int kStandardMenuListButtonWidth = 17; 63 64 namespace { 65 // We must not create multiple ThemePainter instances. 66 class ThemePainter { 67 public: 68 ThemePainter(GraphicsContext* context, const IntRect& r) 69 { 70 #ifndef NDEBUG 71 ASSERT(!s_hasInstance); 72 s_hasInstance = true; 73 #endif 74 TransparencyWin::TransformMode transformMode = getTransformMode(context->getCTM()); 75 m_helper.init(context, getLayerMode(context, transformMode), transformMode, r); 76 77 if (!m_helper.context()) { 78 // TransparencyWin doesn't have well-defined copy-ctor nor op=() 79 // so we re-initialize it instead of assigning a fresh istance. 80 // On the reinitialization, we fallback to use NoLayer mode. 81 // Note that the original initialization failure can be caused by 82 // a failure of an internal buffer allocation and NoLayer mode 83 // does not have such buffer allocations. 84 m_helper.~TransparencyWin(); 85 new (&m_helper) TransparencyWin(); 86 m_helper.init(context, TransparencyWin::NoLayer, transformMode, r); 87 } 88 } 89 90 ~ThemePainter() 91 { 92 m_helper.composite(); 93 #ifndef NDEBUG 94 s_hasInstance = false; 95 #endif 96 } 97 98 GraphicsContext* context() { return m_helper.context(); } 99 const IntRect& drawRect() { return m_helper.drawRect(); } 100 101 private: 102 103 static bool canvasHasMultipleLayers(const SkCanvas* canvas) 104 { 105 SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false); 106 iter.next(); // There is always at least one layer. 107 return !iter.done(); // There is > 1 layer if the the iterator can stil advance. 108 } 109 110 static TransparencyWin::LayerMode getLayerMode(GraphicsContext* context, TransparencyWin::TransformMode transformMode) 111 { 112 if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background. 113 return TransparencyWin::WhiteLayer; 114 if (canvasHasMultipleLayers(context->platformContext()->canvas())) // Needs antialiasing help. 115 return TransparencyWin::OpaqueCompositeLayer; 116 // Nothing interesting. 117 return transformMode == TransparencyWin::KeepTransform ? TransparencyWin::NoLayer : TransparencyWin::OpaqueCompositeLayer; 118 } 119 120 static TransparencyWin::TransformMode getTransformMode(const AffineTransform& matrix) 121 { 122 if (matrix.b() || matrix.c()) // Skew. 123 return TransparencyWin::Untransform; 124 if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale. 125 return TransparencyWin::ScaleTransform; 126 // Nothing interesting. 127 return TransparencyWin::KeepTransform; 128 } 129 130 TransparencyWin m_helper; 131 #ifndef NDEBUG 132 static bool s_hasInstance; 133 #endif 134 }; 135 136 #ifndef NDEBUG 137 bool ThemePainter::s_hasInstance = false; 138 #endif 139 140 } // namespace 141 142 static void getNonClientMetrics(NONCLIENTMETRICS* metrics) 143 { 144 static UINT size = (windowsVersion() >= WindowsVista) ? 145 (sizeof NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; 146 metrics->cbSize = size; 147 bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0); 148 ASSERT(success); 149 } 150 151 static FontDescription smallSystemFont; 152 static FontDescription menuFont; 153 static FontDescription labelFont; 154 155 // Internal static helper functions. We don't put them in an anonymous 156 // namespace so they have easier access to the WebCore namespace. 157 158 static bool supportsFocus(ControlPart appearance) 159 { 160 switch (appearance) { 161 case PushButtonPart: 162 case ButtonPart: 163 case DefaultButtonPart: 164 case SearchFieldPart: 165 case TextFieldPart: 166 case TextAreaPart: 167 return true; 168 } 169 return false; 170 } 171 172 // Return the height of system font |font| in pixels. We use this size by 173 // default for some non-form-control elements. 174 static float systemFontSize(const LOGFONT& font) 175 { 176 float size = -font.lfHeight; 177 if (size < 0) { 178 HFONT hFont = CreateFontIndirect(&font); 179 if (hFont) { 180 HDC hdc = GetDC(0); // What about printing? Is this the right DC? 181 if (hdc) { 182 HGDIOBJ hObject = SelectObject(hdc, hFont); 183 TEXTMETRIC tm; 184 GetTextMetrics(hdc, &tm); 185 SelectObject(hdc, hObject); 186 ReleaseDC(0, hdc); 187 size = tm.tmAscent; 188 } 189 DeleteObject(hFont); 190 } 191 } 192 193 // The "codepage 936" bit here is from Gecko; apparently this helps make 194 // fonts more legible in Simplified Chinese where the default font size is 195 // too small. 196 // 197 // FIXME: http://b/1119883 Since this is only used for "small caption", 198 // "menu", and "status bar" objects, I'm not sure how much this even 199 // matters. Plus the Gecko patch went in back in 2002, and maybe this 200 // isn't even relevant anymore. We should investigate whether this should 201 // be removed, or perhaps broadened to be "any CJK locale". 202 // 203 return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size; 204 } 205 206 // Converts |points| to pixels. One point is 1/72 of an inch. 207 static float pointsToPixels(float points) 208 { 209 static float pixelsPerInch = 0.0f; 210 if (!pixelsPerInch) { 211 HDC hdc = GetDC(0); // What about printing? Is this the right DC? 212 if (hdc) { // Can this ever actually be NULL? 213 pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY); 214 ReleaseDC(0, hdc); 215 } else { 216 pixelsPerInch = 96.0f; 217 } 218 } 219 220 static const float pointsPerInch = 72.0f; 221 return points / pointsPerInch * pixelsPerInch; 222 } 223 224 static double querySystemBlinkInterval(double defaultInterval) 225 { 226 UINT blinkTime = GetCaretBlinkTime(); 227 if (!blinkTime) 228 return defaultInterval; 229 if (blinkTime == INFINITE) 230 return 0; 231 return blinkTime / 1000.0; 232 } 233 234 PassRefPtr<RenderTheme> RenderThemeChromiumWin::create() 235 { 236 return adoptRef(new RenderThemeChromiumWin); 237 } 238 239 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) 240 { 241 static RenderTheme* rt = RenderThemeChromiumWin::create().releaseRef(); 242 return rt; 243 } 244 245 bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const 246 { 247 // Let webkit draw one of its halo rings around any focused element, 248 // except push buttons. For buttons we use the windows PBS_DEFAULTED 249 // styling to give it a blue border. 250 return style->appearance() == ButtonPart 251 || style->appearance() == PushButtonPart; 252 } 253 254 Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const 255 { 256 if (PlatformBridge::layoutTestMode()) 257 return Color(0x00, 0x00, 0xff); // Royal blue. 258 COLORREF color = GetSysColor(COLOR_HIGHLIGHT); 259 return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); 260 } 261 262 Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const 263 { 264 if (PlatformBridge::layoutTestMode()) 265 return Color(0x99, 0x99, 0x99); // Medium gray. 266 COLORREF color = GetSysColor(COLOR_GRAYTEXT); 267 return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); 268 } 269 270 Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const 271 { 272 if (PlatformBridge::layoutTestMode()) 273 return Color(0xff, 0xff, 0xcc); // Pale yellow. 274 COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT); 275 return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); 276 } 277 278 Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const 279 { 280 return Color::white; 281 } 282 283 Color RenderThemeChromiumWin::platformActiveTextSearchHighlightColor() const 284 { 285 return Color(0xff, 0x96, 0x32); // Orange. 286 } 287 288 Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const 289 { 290 return Color(0xff, 0xff, 0x96); // Yellow. 291 } 292 293 void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescription) const 294 { 295 // This logic owes much to RenderThemeSafari.cpp. 296 FontDescription* cachedDesc = 0; 297 AtomicString faceName; 298 float fontSize = 0; 299 switch (propId) { 300 case CSSValueSmallCaption: 301 cachedDesc = &smallSystemFont; 302 if (!smallSystemFont.isAbsoluteSize()) { 303 NONCLIENTMETRICS metrics; 304 getNonClientMetrics(&metrics); 305 faceName = AtomicString(metrics.lfSmCaptionFont.lfFaceName, wcslen(metrics.lfSmCaptionFont.lfFaceName)); 306 fontSize = systemFontSize(metrics.lfSmCaptionFont); 307 } 308 break; 309 case CSSValueMenu: 310 cachedDesc = &menuFont; 311 if (!menuFont.isAbsoluteSize()) { 312 NONCLIENTMETRICS metrics; 313 getNonClientMetrics(&metrics); 314 faceName = AtomicString(metrics.lfMenuFont.lfFaceName, wcslen(metrics.lfMenuFont.lfFaceName)); 315 fontSize = systemFontSize(metrics.lfMenuFont); 316 } 317 break; 318 case CSSValueStatusBar: 319 cachedDesc = &labelFont; 320 if (!labelFont.isAbsoluteSize()) { 321 NONCLIENTMETRICS metrics; 322 getNonClientMetrics(&metrics); 323 faceName = metrics.lfStatusFont.lfFaceName; 324 fontSize = systemFontSize(metrics.lfStatusFont); 325 } 326 break; 327 case CSSValueWebkitMiniControl: 328 case CSSValueWebkitSmallControl: 329 case CSSValueWebkitControl: 330 faceName = defaultGUIFont(); 331 // Why 2 points smaller? Because that's what Gecko does. 332 fontSize = defaultFontSize - pointsToPixels(2); 333 break; 334 default: 335 faceName = defaultGUIFont(); 336 fontSize = defaultFontSize; 337 break; 338 } 339 340 if (!cachedDesc) 341 cachedDesc = &fontDescription; 342 343 if (fontSize) { 344 cachedDesc->firstFamily().setFamily(faceName); 345 cachedDesc->setIsAbsoluteSize(true); 346 cachedDesc->setGenericFamily(FontDescription::NoFamily); 347 cachedDesc->setSpecifiedSize(fontSize); 348 cachedDesc->setWeight(FontWeightNormal); 349 cachedDesc->setItalic(false); 350 } 351 fontDescription = *cachedDesc; 352 } 353 354 // Map a CSSValue* system color to an index understood by GetSysColor(). 355 static int cssValueIdToSysColorIndex(int cssValueId) 356 { 357 switch (cssValueId) { 358 case CSSValueActiveborder: return COLOR_ACTIVEBORDER; 359 case CSSValueActivecaption: return COLOR_ACTIVECAPTION; 360 case CSSValueAppworkspace: return COLOR_APPWORKSPACE; 361 case CSSValueBackground: return COLOR_BACKGROUND; 362 case CSSValueButtonface: return COLOR_BTNFACE; 363 case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT; 364 case CSSValueButtonshadow: return COLOR_BTNSHADOW; 365 case CSSValueButtontext: return COLOR_BTNTEXT; 366 case CSSValueCaptiontext: return COLOR_CAPTIONTEXT; 367 case CSSValueGraytext: return COLOR_GRAYTEXT; 368 case CSSValueHighlight: return COLOR_HIGHLIGHT; 369 case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT; 370 case CSSValueInactiveborder: return COLOR_INACTIVEBORDER; 371 case CSSValueInactivecaption: return COLOR_INACTIVECAPTION; 372 case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT; 373 case CSSValueInfobackground: return COLOR_INFOBK; 374 case CSSValueInfotext: return COLOR_INFOTEXT; 375 case CSSValueMenu: return COLOR_MENU; 376 case CSSValueMenutext: return COLOR_MENUTEXT; 377 case CSSValueScrollbar: return COLOR_SCROLLBAR; 378 case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW; 379 case CSSValueThreedface: return COLOR_3DFACE; 380 case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT; 381 case CSSValueThreedlightshadow: return COLOR_3DLIGHT; 382 case CSSValueThreedshadow: return COLOR_3DSHADOW; 383 case CSSValueWindow: return COLOR_WINDOW; 384 case CSSValueWindowframe: return COLOR_WINDOWFRAME; 385 case CSSValueWindowtext: return COLOR_WINDOWTEXT; 386 default: return -1; // Unsupported CSSValue 387 } 388 } 389 390 Color RenderThemeChromiumWin::systemColor(int cssValueId) const 391 { 392 int sysColorIndex = cssValueIdToSysColorIndex(cssValueId); 393 if (PlatformBridge::layoutTestMode() || (sysColorIndex == -1)) 394 return RenderTheme::systemColor(cssValueId); 395 396 COLORREF color = GetSysColor(sysColorIndex); 397 return Color(GetRValue(color), GetGValue(color), GetBValue(color)); 398 } 399 400 void RenderThemeChromiumWin::adjustSliderThumbSize(RenderObject* o) const 401 { 402 // These sizes match what WinXP draws for various menus. 403 const int sliderThumbAlongAxis = 11; 404 const int sliderThumbAcrossAxis = 21; 405 if (o->style()->appearance() == SliderThumbHorizontalPart) { 406 o->style()->setWidth(Length(sliderThumbAlongAxis, Fixed)); 407 o->style()->setHeight(Length(sliderThumbAcrossAxis, Fixed)); 408 } else if (o->style()->appearance() == SliderThumbVerticalPart) { 409 o->style()->setWidth(Length(sliderThumbAcrossAxis, Fixed)); 410 o->style()->setHeight(Length(sliderThumbAlongAxis, Fixed)); 411 } else 412 RenderThemeChromiumSkia::adjustSliderThumbSize(o); 413 } 414 415 bool RenderThemeChromiumWin::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r) 416 { 417 return paintButton(o, i, r); 418 } 419 bool RenderThemeChromiumWin::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r) 420 { 421 return paintButton(o, i, r); 422 } 423 424 bool RenderThemeChromiumWin::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r) 425 { 426 const ThemeData& themeData = getThemeData(o); 427 428 ThemePainter painter(i.context, r); 429 PlatformBridge::paintButton(painter.context(), 430 themeData.m_part, 431 themeData.m_state, 432 themeData.m_classicState, 433 painter.drawRect()); 434 return false; 435 } 436 437 bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r) 438 { 439 return paintTextFieldInternal(o, i, r, true); 440 } 441 442 bool RenderThemeChromiumWin::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r) 443 { 444 const ThemeData& themeData = getThemeData(o); 445 446 ThemePainter painter(i.context, r); 447 PlatformBridge::paintTrackbar(painter.context(), 448 themeData.m_part, 449 themeData.m_state, 450 themeData.m_classicState, 451 painter.drawRect()); 452 return false; 453 } 454 455 bool RenderThemeChromiumWin::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r) 456 { 457 return paintSliderTrack(o, i, r); 458 } 459 460 static int menuListButtonWidth() 461 { 462 static int width = PlatformBridge::layoutTestMode() ? kStandardMenuListButtonWidth : GetSystemMetrics(SM_CXVSCROLL); 463 return width; 464 } 465 466 // Used to paint unstyled menulists (i.e. with the default border) 467 bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r) 468 { 469 if (!o->isBox()) 470 return false; 471 472 const RenderBox* box = toRenderBox(o); 473 int borderRight = box->borderRight(); 474 int borderLeft = box->borderLeft(); 475 int borderTop = box->borderTop(); 476 int borderBottom = box->borderBottom(); 477 478 // If all the borders are 0, then tell skia not to paint the border on the 479 // textfield. FIXME: http://b/1210017 Figure out how to get Windows to not 480 // draw individual borders and then pass that to skia so we can avoid 481 // drawing any borders that are set to 0. For non-zero borders, we draw the 482 // border, but webkit just draws over it. 483 bool drawEdges = !(!borderRight && !borderLeft && !borderTop && !borderBottom); 484 485 paintTextFieldInternal(o, i, r, drawEdges); 486 487 // Take padding and border into account. If the MenuList is smaller than 488 // the size of a button, make sure to shrink it appropriately and not put 489 // its x position to the left of the menulist. 490 const int buttonWidth = menuListButtonWidth(); 491 int spacingLeft = borderLeft + box->paddingLeft(); 492 int spacingRight = borderRight + box->paddingRight(); 493 int spacingTop = borderTop + box->paddingTop(); 494 int spacingBottom = borderBottom + box->paddingBottom(); 495 496 int buttonX; 497 if (r.maxX() - r.x() < buttonWidth) 498 buttonX = r.x(); 499 else 500 buttonX = o->style()->direction() == LTR ? r.maxX() - spacingRight - buttonWidth : r.x() + spacingLeft; 501 502 // Compute the rectangle of the button in the destination image. 503 IntRect rect(buttonX, 504 r.y() + spacingTop, 505 std::min(buttonWidth, r.maxX() - r.x()), 506 r.height() - (spacingTop + spacingBottom)); 507 508 // Get the correct theme data for a textfield and paint the menu. 509 ThemePainter painter(i.context, rect); 510 PlatformBridge::paintMenuList(painter.context(), 511 CP_DROPDOWNBUTTON, 512 determineState(o), 513 determineClassicState(o), 514 painter.drawRect()); 515 return false; 516 } 517 518 // static 519 void RenderThemeChromiumWin::setDefaultFontSize(int fontSize) 520 { 521 RenderThemeChromiumSkia::setDefaultFontSize(fontSize); 522 523 // Reset cached fonts. 524 smallSystemFont = menuFont = labelFont = FontDescription(); 525 } 526 527 double RenderThemeChromiumWin::caretBlinkIntervalInternal() const 528 { 529 // This involves a system call, so we cache the result. 530 static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval()); 531 return blinkInterval; 532 } 533 534 unsigned RenderThemeChromiumWin::determineState(RenderObject* o, ControlSubPart subPart) 535 { 536 unsigned result = TS_NORMAL; 537 ControlPart appearance = o->style()->appearance(); 538 if (!isEnabled(o)) 539 result = TS_DISABLED; 540 else if (isReadOnlyControl(o)) 541 result = (appearance == TextFieldPart || appearance == TextAreaPart || appearance == SearchFieldPart) ? ETS_READONLY : TS_DISABLED; 542 // Active overrides hover and focused. 543 else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o)) 544 result = TS_PRESSED; 545 else if (supportsFocus(appearance) && isFocused(o)) 546 result = ETS_FOCUSED; 547 else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o)) 548 result = TS_HOT; 549 550 // CBS_UNCHECKED*: 1-4 551 // CBS_CHECKED*: 5-8 552 // CBS_MIXED*: 9-12 553 if (isIndeterminate(o)) 554 result += 8; 555 else if (isChecked(o)) 556 result += 4; 557 return result; 558 } 559 560 unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o) 561 { 562 unsigned result = TUS_NORMAL; 563 if (!isEnabled(o->parent())) 564 result = TUS_DISABLED; 565 else if (supportsFocus(o->style()->appearance()) && isFocused(o->parent())) 566 result = TUS_FOCUSED; 567 else if (toRenderSlider(o->parent())->inDragMode()) 568 result = TUS_PRESSED; 569 else if (isHovered(o)) 570 result = TUS_HOT; 571 return result; 572 } 573 574 unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o, ControlSubPart subPart) 575 { 576 unsigned result = 0; 577 578 ControlPart part = o->style()->appearance(); 579 580 // Sliders are always in the normal state. 581 if (part == SliderHorizontalPart || part == SliderVerticalPart) 582 return result; 583 584 // So are readonly text fields. 585 if (isReadOnlyControl(o) && (part == TextFieldPart || part == TextAreaPart || part == SearchFieldPart)) 586 return result; 587 588 if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) { 589 if (!isEnabled(o->parent())) 590 result = DFCS_INACTIVE; 591 else if (toRenderSlider(o->parent())->inDragMode()) // Active supersedes hover 592 result = DFCS_PUSHED; 593 else if (isHovered(o)) 594 result = DFCS_HOT; 595 } else { 596 if (!isEnabled(o) || isReadOnlyControl(o)) 597 result = DFCS_INACTIVE; 598 // Active supersedes hover 599 else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o)) 600 result = DFCS_PUSHED; 601 else if (supportsFocus(part) && isFocused(o)) // So does focused 602 result = 0; 603 else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o)) 604 result = DFCS_HOT; 605 // Classic theme can't represent indeterminate states. Use unchecked appearance. 606 if (isChecked(o) && !isIndeterminate(o)) 607 result |= DFCS_CHECKED; 608 } 609 return result; 610 } 611 612 ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o, ControlSubPart subPart) 613 { 614 ThemeData result; 615 switch (o->style()->appearance()) { 616 case CheckboxPart: 617 result.m_part = BP_CHECKBOX; 618 result.m_state = determineState(o); 619 result.m_classicState = DFCS_BUTTONCHECK; 620 break; 621 case RadioPart: 622 result.m_part = BP_RADIOBUTTON; 623 result.m_state = determineState(o); 624 result.m_classicState = DFCS_BUTTONRADIO; 625 break; 626 case PushButtonPart: 627 case ButtonPart: 628 result.m_part = BP_PUSHBUTTON; 629 result.m_state = determineState(o); 630 result.m_classicState = DFCS_BUTTONPUSH; 631 break; 632 case SliderHorizontalPart: 633 result.m_part = TKP_TRACK; 634 result.m_state = TRS_NORMAL; 635 break; 636 case SliderVerticalPart: 637 result.m_part = TKP_TRACKVERT; 638 result.m_state = TRVS_NORMAL; 639 break; 640 case SliderThumbHorizontalPart: 641 result.m_part = TKP_THUMBBOTTOM; 642 result.m_state = determineSliderThumbState(o); 643 break; 644 case SliderThumbVerticalPart: 645 result.m_part = TKP_THUMBVERT; 646 result.m_state = determineSliderThumbState(o); 647 break; 648 case ListboxPart: 649 case MenulistPart: 650 case MenulistButtonPart: 651 case SearchFieldPart: 652 case TextFieldPart: 653 case TextAreaPart: 654 result.m_part = EP_EDITTEXT; 655 result.m_state = determineState(o); 656 break; 657 case InnerSpinButtonPart: 658 result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN; 659 result.m_state = determineState(o, subPart); 660 result.m_classicState = subPart == SpinButtonUp ? DFCS_SCROLLUP : DFCS_SCROLLDOWN; 661 break; 662 } 663 664 result.m_classicState |= determineClassicState(o, subPart); 665 666 return result; 667 } 668 669 bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o, 670 const PaintInfo& i, 671 const IntRect& r, 672 bool drawEdges) 673 { 674 // Fallback to white if the specified color object is invalid. 675 // (Note PlatformBridge::paintTextField duplicates this check). 676 Color backgroundColor(Color::white); 677 if (o->style()->visitedDependentColor(CSSPropertyBackgroundColor).isValid()) 678 backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor); 679 680 // If we have background-image, don't fill the content area to expose the 681 // parent's background. Also, we shouldn't fill the content area if the 682 // alpha of the color is 0. The API of Windows GDI ignores the alpha. 683 // 684 // Note that we should paint the content area white if we have neither the 685 // background color nor background image explicitly specified to keep the 686 // appearance of select element consistent with other browsers. 687 bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha(); 688 689 if (o->style()->hasBorderRadius()) { 690 // If the style has rounded borders, setup the context to clip the 691 // background (themed or filled) appropriately. 692 // FIXME: make sure we do the right thing if css background-clip is set. 693 i.context->save(); 694 i.context->addRoundedRectClip(o->style()->getRoundedBorderFor(r)); 695 } 696 { 697 const ThemeData& themeData = getThemeData(o); 698 ThemePainter painter(i.context, r); 699 PlatformBridge::paintTextField(painter.context(), 700 themeData.m_part, 701 themeData.m_state, 702 themeData.m_classicState, 703 painter.drawRect(), 704 backgroundColor, 705 fillContentArea, 706 drawEdges); 707 // End of block commits the painter before restoring context. 708 } 709 if (o->style()->hasBorderRadius()) 710 i.context->restore(); 711 return false; 712 } 713 714 void RenderThemeChromiumWin::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const 715 { 716 int width = ScrollbarTheme::nativeTheme()->scrollbarThickness(); 717 style->setWidth(Length(width, Fixed)); 718 style->setMinWidth(Length(width, Fixed)); 719 } 720 721 bool RenderThemeChromiumWin::paintInnerSpinButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) 722 { 723 IntRect half = rect; 724 725 // Need explicit blocks to avoid to create multiple ThemePainter instances. 726 { 727 half.setHeight(rect.height() / 2); 728 const ThemeData& upThemeData = getThemeData(object, SpinButtonUp); 729 ThemePainter upPainter(info.context, half); 730 PlatformBridge::paintSpinButton(upPainter.context(), 731 upThemeData.m_part, 732 upThemeData.m_state, 733 upThemeData.m_classicState, 734 upPainter.drawRect()); 735 } 736 737 { 738 half.setY(rect.y() + rect.height() / 2); 739 const ThemeData& downThemeData = getThemeData(object, SpinButtonDown); 740 ThemePainter downPainter(info.context, half); 741 PlatformBridge::paintSpinButton(downPainter.context(), 742 downThemeData.m_part, 743 downThemeData.m_state, 744 downThemeData.m_classicState, 745 downPainter.drawRect()); 746 } 747 return false; 748 } 749 750 #if ENABLE(PROGRESS_TAG) 751 752 // MSDN says that update intervals for the bar is 30ms. 753 // http://msdn.microsoft.com/en-us/library/bb760842(v=VS.85).aspx 754 static const double progressAnimationFrameRate = 0.033; 755 756 double RenderThemeChromiumWin::animationRepeatIntervalForProgressBar(RenderProgress*) const 757 { 758 return progressAnimationFrameRate; 759 } 760 761 double RenderThemeChromiumWin::animationDurationForProgressBar(RenderProgress* renderProgress) const 762 { 763 // On Chromium Windows port, animationProgress() and associated values aren't used. 764 // So here we can return arbitrary positive value. 765 return progressAnimationFrameRate; 766 } 767 768 void RenderThemeChromiumWin::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const 769 { 770 } 771 772 bool RenderThemeChromiumWin::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& r) 773 { 774 if (!o->isProgress()) 775 return true; 776 777 RenderProgress* renderProgress = toRenderProgress(o); 778 // For indeterminate bar, valueRect is ignored and it is computed by the theme engine 779 // because the animation is a platform detail and WebKit doesn't need to know how. 780 IntRect valueRect = renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, r) : IntRect(0, 0, 0, 0); 781 double animatedSeconds = renderProgress->animationStartTime() ? WTF::currentTime() - renderProgress->animationStartTime() : 0; 782 ThemePainter painter(i.context, r); 783 PlatformBridge::paintProgressBar(painter.context(), r, valueRect, renderProgress->isDeterminate(), animatedSeconds); 784 return false; 785 } 786 787 #endif 788 789 } // namespace WebCore 790