/* * This file is part of the WebKit project. * * Copyright (C) 2006 Apple Computer, Inc. * Copyright (C) 2008, 2009 Google, Inc. * Copyright (C) 2009 Kenneth Rohde Christiansen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * */ #include "config.h" #include "RenderThemeChromiumWin.h" #include #include #include #include "CSSValueKeywords.h" #include "CurrentTime.h" #include "FontSelector.h" #include "FontUtilsChromiumWin.h" #include "GraphicsContext.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "MediaControlElements.h" #include "PaintInfo.h" #include "PlatformBridge.h" #include "RenderBox.h" #include "RenderProgress.h" #include "RenderSlider.h" #include "ScrollbarTheme.h" #include "SystemInfo.h" #include "TransparencyWin.h" // FIXME: This dependency should eventually be removed. #include #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \ offsetof(structName, member) + \ (sizeof static_cast(0)->member) #define NONCLIENTMETRICS_SIZE_PRE_VISTA \ SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) namespace WebCore { // The standard width for the menu list drop-down button when run under // layout test mode. Use the value that's currently captured in most baselines. static const int kStandardMenuListButtonWidth = 17; namespace { // We must not create multiple ThemePainter instances. class ThemePainter { public: ThemePainter(GraphicsContext* context, const IntRect& r) { #ifndef NDEBUG ASSERT(!s_hasInstance); s_hasInstance = true; #endif TransparencyWin::TransformMode transformMode = getTransformMode(context->getCTM()); m_helper.init(context, getLayerMode(context, transformMode), transformMode, r); if (!m_helper.context()) { // TransparencyWin doesn't have well-defined copy-ctor nor op=() // so we re-initialize it instead of assigning a fresh istance. // On the reinitialization, we fallback to use NoLayer mode. // Note that the original initialization failure can be caused by // a failure of an internal buffer allocation and NoLayer mode // does not have such buffer allocations. m_helper.~TransparencyWin(); new (&m_helper) TransparencyWin(); m_helper.init(context, TransparencyWin::NoLayer, transformMode, r); } } ~ThemePainter() { m_helper.composite(); #ifndef NDEBUG s_hasInstance = false; #endif } GraphicsContext* context() { return m_helper.context(); } const IntRect& drawRect() { return m_helper.drawRect(); } private: static bool canvasHasMultipleLayers(const SkCanvas* canvas) { SkCanvas::LayerIter iter(const_cast(canvas), false); iter.next(); // There is always at least one layer. return !iter.done(); // There is > 1 layer if the the iterator can stil advance. } static TransparencyWin::LayerMode getLayerMode(GraphicsContext* context, TransparencyWin::TransformMode transformMode) { if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background. return TransparencyWin::WhiteLayer; if (canvasHasMultipleLayers(context->platformContext()->canvas())) // Needs antialiasing help. return TransparencyWin::OpaqueCompositeLayer; // Nothing interesting. return transformMode == TransparencyWin::KeepTransform ? TransparencyWin::NoLayer : TransparencyWin::OpaqueCompositeLayer; } static TransparencyWin::TransformMode getTransformMode(const AffineTransform& matrix) { if (matrix.b() || matrix.c()) // Skew. return TransparencyWin::Untransform; if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale. return TransparencyWin::ScaleTransform; // Nothing interesting. return TransparencyWin::KeepTransform; } TransparencyWin m_helper; #ifndef NDEBUG static bool s_hasInstance; #endif }; #ifndef NDEBUG bool ThemePainter::s_hasInstance = false; #endif } // namespace static void getNonClientMetrics(NONCLIENTMETRICS* metrics) { static UINT size = (windowsVersion() >= WindowsVista) ? (sizeof NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; metrics->cbSize = size; bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0); ASSERT(success); } static FontDescription smallSystemFont; static FontDescription menuFont; static FontDescription labelFont; // Internal static helper functions. We don't put them in an anonymous // namespace so they have easier access to the WebCore namespace. static bool supportsFocus(ControlPart appearance) { switch (appearance) { case PushButtonPart: case ButtonPart: case DefaultButtonPart: case SearchFieldPart: case TextFieldPart: case TextAreaPart: return true; } return false; } // Return the height of system font |font| in pixels. We use this size by // default for some non-form-control elements. static float systemFontSize(const LOGFONT& font) { float size = -font.lfHeight; if (size < 0) { HFONT hFont = CreateFontIndirect(&font); if (hFont) { HDC hdc = GetDC(0); // What about printing? Is this the right DC? if (hdc) { HGDIOBJ hObject = SelectObject(hdc, hFont); TEXTMETRIC tm; GetTextMetrics(hdc, &tm); SelectObject(hdc, hObject); ReleaseDC(0, hdc); size = tm.tmAscent; } DeleteObject(hFont); } } // The "codepage 936" bit here is from Gecko; apparently this helps make // fonts more legible in Simplified Chinese where the default font size is // too small. // // FIXME: http://b/1119883 Since this is only used for "small caption", // "menu", and "status bar" objects, I'm not sure how much this even // matters. Plus the Gecko patch went in back in 2002, and maybe this // isn't even relevant anymore. We should investigate whether this should // be removed, or perhaps broadened to be "any CJK locale". // return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size; } // Converts |points| to pixels. One point is 1/72 of an inch. static float pointsToPixels(float points) { static float pixelsPerInch = 0.0f; if (!pixelsPerInch) { HDC hdc = GetDC(0); // What about printing? Is this the right DC? if (hdc) { // Can this ever actually be NULL? pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY); ReleaseDC(0, hdc); } else { pixelsPerInch = 96.0f; } } static const float pointsPerInch = 72.0f; return points / pointsPerInch * pixelsPerInch; } static double querySystemBlinkInterval(double defaultInterval) { UINT blinkTime = GetCaretBlinkTime(); if (!blinkTime) return defaultInterval; if (blinkTime == INFINITE) return 0; return blinkTime / 1000.0; } PassRefPtr RenderThemeChromiumWin::create() { return adoptRef(new RenderThemeChromiumWin); } PassRefPtr RenderTheme::themeForPage(Page* page) { static RenderTheme* rt = RenderThemeChromiumWin::create().releaseRef(); return rt; } bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const { // Let webkit draw one of its halo rings around any focused element, // except push buttons. For buttons we use the windows PBS_DEFAULTED // styling to give it a blue border. return style->appearance() == ButtonPart || style->appearance() == PushButtonPart; } Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const { if (PlatformBridge::layoutTestMode()) return Color(0x00, 0x00, 0xff); // Royal blue. COLORREF color = GetSysColor(COLOR_HIGHLIGHT); return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); } Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const { if (PlatformBridge::layoutTestMode()) return Color(0x99, 0x99, 0x99); // Medium gray. COLORREF color = GetSysColor(COLOR_GRAYTEXT); return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); } Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const { if (PlatformBridge::layoutTestMode()) return Color(0xff, 0xff, 0xcc); // Pale yellow. COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT); return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff); } Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const { return Color::white; } Color RenderThemeChromiumWin::platformActiveTextSearchHighlightColor() const { return Color(0xff, 0x96, 0x32); // Orange. } Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const { return Color(0xff, 0xff, 0x96); // Yellow. } void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescription) const { // This logic owes much to RenderThemeSafari.cpp. FontDescription* cachedDesc = 0; AtomicString faceName; float fontSize = 0; switch (propId) { case CSSValueSmallCaption: cachedDesc = &smallSystemFont; if (!smallSystemFont.isAbsoluteSize()) { NONCLIENTMETRICS metrics; getNonClientMetrics(&metrics); faceName = AtomicString(metrics.lfSmCaptionFont.lfFaceName, wcslen(metrics.lfSmCaptionFont.lfFaceName)); fontSize = systemFontSize(metrics.lfSmCaptionFont); } break; case CSSValueMenu: cachedDesc = &menuFont; if (!menuFont.isAbsoluteSize()) { NONCLIENTMETRICS metrics; getNonClientMetrics(&metrics); faceName = AtomicString(metrics.lfMenuFont.lfFaceName, wcslen(metrics.lfMenuFont.lfFaceName)); fontSize = systemFontSize(metrics.lfMenuFont); } break; case CSSValueStatusBar: cachedDesc = &labelFont; if (!labelFont.isAbsoluteSize()) { NONCLIENTMETRICS metrics; getNonClientMetrics(&metrics); faceName = metrics.lfStatusFont.lfFaceName; fontSize = systemFontSize(metrics.lfStatusFont); } break; case CSSValueWebkitMiniControl: case CSSValueWebkitSmallControl: case CSSValueWebkitControl: faceName = defaultGUIFont(); // Why 2 points smaller? Because that's what Gecko does. fontSize = defaultFontSize - pointsToPixels(2); break; default: faceName = defaultGUIFont(); fontSize = defaultFontSize; break; } if (!cachedDesc) cachedDesc = &fontDescription; if (fontSize) { cachedDesc->firstFamily().setFamily(faceName); cachedDesc->setIsAbsoluteSize(true); cachedDesc->setGenericFamily(FontDescription::NoFamily); cachedDesc->setSpecifiedSize(fontSize); cachedDesc->setWeight(FontWeightNormal); cachedDesc->setItalic(false); } fontDescription = *cachedDesc; } // Map a CSSValue* system color to an index understood by GetSysColor(). static int cssValueIdToSysColorIndex(int cssValueId) { switch (cssValueId) { case CSSValueActiveborder: return COLOR_ACTIVEBORDER; case CSSValueActivecaption: return COLOR_ACTIVECAPTION; case CSSValueAppworkspace: return COLOR_APPWORKSPACE; case CSSValueBackground: return COLOR_BACKGROUND; case CSSValueButtonface: return COLOR_BTNFACE; case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT; case CSSValueButtonshadow: return COLOR_BTNSHADOW; case CSSValueButtontext: return COLOR_BTNTEXT; case CSSValueCaptiontext: return COLOR_CAPTIONTEXT; case CSSValueGraytext: return COLOR_GRAYTEXT; case CSSValueHighlight: return COLOR_HIGHLIGHT; case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT; case CSSValueInactiveborder: return COLOR_INACTIVEBORDER; case CSSValueInactivecaption: return COLOR_INACTIVECAPTION; case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT; case CSSValueInfobackground: return COLOR_INFOBK; case CSSValueInfotext: return COLOR_INFOTEXT; case CSSValueMenu: return COLOR_MENU; case CSSValueMenutext: return COLOR_MENUTEXT; case CSSValueScrollbar: return COLOR_SCROLLBAR; case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW; case CSSValueThreedface: return COLOR_3DFACE; case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT; case CSSValueThreedlightshadow: return COLOR_3DLIGHT; case CSSValueThreedshadow: return COLOR_3DSHADOW; case CSSValueWindow: return COLOR_WINDOW; case CSSValueWindowframe: return COLOR_WINDOWFRAME; case CSSValueWindowtext: return COLOR_WINDOWTEXT; default: return -1; // Unsupported CSSValue } } Color RenderThemeChromiumWin::systemColor(int cssValueId) const { int sysColorIndex = cssValueIdToSysColorIndex(cssValueId); if (PlatformBridge::layoutTestMode() || (sysColorIndex == -1)) return RenderTheme::systemColor(cssValueId); COLORREF color = GetSysColor(sysColorIndex); return Color(GetRValue(color), GetGValue(color), GetBValue(color)); } void RenderThemeChromiumWin::adjustSliderThumbSize(RenderObject* o) const { // These sizes match what WinXP draws for various menus. const int sliderThumbAlongAxis = 11; const int sliderThumbAcrossAxis = 21; if (o->style()->appearance() == SliderThumbHorizontalPart) { o->style()->setWidth(Length(sliderThumbAlongAxis, Fixed)); o->style()->setHeight(Length(sliderThumbAcrossAxis, Fixed)); } else if (o->style()->appearance() == SliderThumbVerticalPart) { o->style()->setWidth(Length(sliderThumbAcrossAxis, Fixed)); o->style()->setHeight(Length(sliderThumbAlongAxis, Fixed)); } else RenderThemeChromiumSkia::adjustSliderThumbSize(o); } bool RenderThemeChromiumWin::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r) { return paintButton(o, i, r); } bool RenderThemeChromiumWin::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r) { return paintButton(o, i, r); } bool RenderThemeChromiumWin::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r) { const ThemeData& themeData = getThemeData(o); ThemePainter painter(i.context, r); PlatformBridge::paintButton(painter.context(), themeData.m_part, themeData.m_state, themeData.m_classicState, painter.drawRect()); return false; } bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r) { return paintTextFieldInternal(o, i, r, true); } bool RenderThemeChromiumWin::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r) { const ThemeData& themeData = getThemeData(o); ThemePainter painter(i.context, r); PlatformBridge::paintTrackbar(painter.context(), themeData.m_part, themeData.m_state, themeData.m_classicState, painter.drawRect()); return false; } bool RenderThemeChromiumWin::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r) { return paintSliderTrack(o, i, r); } static int menuListButtonWidth() { static int width = PlatformBridge::layoutTestMode() ? kStandardMenuListButtonWidth : GetSystemMetrics(SM_CXVSCROLL); return width; } // Used to paint unstyled menulists (i.e. with the default border) bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r) { if (!o->isBox()) return false; const RenderBox* box = toRenderBox(o); int borderRight = box->borderRight(); int borderLeft = box->borderLeft(); int borderTop = box->borderTop(); int borderBottom = box->borderBottom(); // If all the borders are 0, then tell skia not to paint the border on the // textfield. FIXME: http://b/1210017 Figure out how to get Windows to not // draw individual borders and then pass that to skia so we can avoid // drawing any borders that are set to 0. For non-zero borders, we draw the // border, but webkit just draws over it. bool drawEdges = !(!borderRight && !borderLeft && !borderTop && !borderBottom); paintTextFieldInternal(o, i, r, drawEdges); // Take padding and border into account. If the MenuList is smaller than // the size of a button, make sure to shrink it appropriately and not put // its x position to the left of the menulist. const int buttonWidth = menuListButtonWidth(); int spacingLeft = borderLeft + box->paddingLeft(); int spacingRight = borderRight + box->paddingRight(); int spacingTop = borderTop + box->paddingTop(); int spacingBottom = borderBottom + box->paddingBottom(); int buttonX; if (r.maxX() - r.x() < buttonWidth) buttonX = r.x(); else buttonX = o->style()->direction() == LTR ? r.maxX() - spacingRight - buttonWidth : r.x() + spacingLeft; // Compute the rectangle of the button in the destination image. IntRect rect(buttonX, r.y() + spacingTop, std::min(buttonWidth, r.maxX() - r.x()), r.height() - (spacingTop + spacingBottom)); // Get the correct theme data for a textfield and paint the menu. ThemePainter painter(i.context, rect); PlatformBridge::paintMenuList(painter.context(), CP_DROPDOWNBUTTON, determineState(o), determineClassicState(o), painter.drawRect()); return false; } // static void RenderThemeChromiumWin::setDefaultFontSize(int fontSize) { RenderThemeChromiumSkia::setDefaultFontSize(fontSize); // Reset cached fonts. smallSystemFont = menuFont = labelFont = FontDescription(); } double RenderThemeChromiumWin::caretBlinkIntervalInternal() const { // This involves a system call, so we cache the result. static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval()); return blinkInterval; } unsigned RenderThemeChromiumWin::determineState(RenderObject* o, ControlSubPart subPart) { unsigned result = TS_NORMAL; ControlPart appearance = o->style()->appearance(); if (!isEnabled(o)) result = TS_DISABLED; else if (isReadOnlyControl(o)) result = (appearance == TextFieldPart || appearance == TextAreaPart || appearance == SearchFieldPart) ? ETS_READONLY : TS_DISABLED; // Active overrides hover and focused. else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o)) result = TS_PRESSED; else if (supportsFocus(appearance) && isFocused(o)) result = ETS_FOCUSED; else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o)) result = TS_HOT; // CBS_UNCHECKED*: 1-4 // CBS_CHECKED*: 5-8 // CBS_MIXED*: 9-12 if (isIndeterminate(o)) result += 8; else if (isChecked(o)) result += 4; return result; } unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o) { unsigned result = TUS_NORMAL; if (!isEnabled(o->parent())) result = TUS_DISABLED; else if (supportsFocus(o->style()->appearance()) && isFocused(o->parent())) result = TUS_FOCUSED; else if (toRenderSlider(o->parent())->inDragMode()) result = TUS_PRESSED; else if (isHovered(o)) result = TUS_HOT; return result; } unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o, ControlSubPart subPart) { unsigned result = 0; ControlPart part = o->style()->appearance(); // Sliders are always in the normal state. if (part == SliderHorizontalPart || part == SliderVerticalPart) return result; // So are readonly text fields. if (isReadOnlyControl(o) && (part == TextFieldPart || part == TextAreaPart || part == SearchFieldPart)) return result; if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) { if (!isEnabled(o->parent())) result = DFCS_INACTIVE; else if (toRenderSlider(o->parent())->inDragMode()) // Active supersedes hover result = DFCS_PUSHED; else if (isHovered(o)) result = DFCS_HOT; } else { if (!isEnabled(o) || isReadOnlyControl(o)) result = DFCS_INACTIVE; // Active supersedes hover else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o)) result = DFCS_PUSHED; else if (supportsFocus(part) && isFocused(o)) // So does focused result = 0; else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o)) result = DFCS_HOT; // Classic theme can't represent indeterminate states. Use unchecked appearance. if (isChecked(o) && !isIndeterminate(o)) result |= DFCS_CHECKED; } return result; } ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o, ControlSubPart subPart) { ThemeData result; switch (o->style()->appearance()) { case CheckboxPart: result.m_part = BP_CHECKBOX; result.m_state = determineState(o); result.m_classicState = DFCS_BUTTONCHECK; break; case RadioPart: result.m_part = BP_RADIOBUTTON; result.m_state = determineState(o); result.m_classicState = DFCS_BUTTONRADIO; break; case PushButtonPart: case ButtonPart: result.m_part = BP_PUSHBUTTON; result.m_state = determineState(o); result.m_classicState = DFCS_BUTTONPUSH; break; case SliderHorizontalPart: result.m_part = TKP_TRACK; result.m_state = TRS_NORMAL; break; case SliderVerticalPart: result.m_part = TKP_TRACKVERT; result.m_state = TRVS_NORMAL; break; case SliderThumbHorizontalPart: result.m_part = TKP_THUMBBOTTOM; result.m_state = determineSliderThumbState(o); break; case SliderThumbVerticalPart: result.m_part = TKP_THUMBVERT; result.m_state = determineSliderThumbState(o); break; case ListboxPart: case MenulistPart: case MenulistButtonPart: case SearchFieldPart: case TextFieldPart: case TextAreaPart: result.m_part = EP_EDITTEXT; result.m_state = determineState(o); break; case InnerSpinButtonPart: result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN; result.m_state = determineState(o, subPart); result.m_classicState = subPart == SpinButtonUp ? DFCS_SCROLLUP : DFCS_SCROLLDOWN; break; } result.m_classicState |= determineClassicState(o, subPart); return result; } bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o, const PaintInfo& i, const IntRect& r, bool drawEdges) { // Fallback to white if the specified color object is invalid. // (Note PlatformBridge::paintTextField duplicates this check). Color backgroundColor(Color::white); if (o->style()->visitedDependentColor(CSSPropertyBackgroundColor).isValid()) backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor); // If we have background-image, don't fill the content area to expose the // parent's background. Also, we shouldn't fill the content area if the // alpha of the color is 0. The API of Windows GDI ignores the alpha. // // Note that we should paint the content area white if we have neither the // background color nor background image explicitly specified to keep the // appearance of select element consistent with other browsers. bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha(); if (o->style()->hasBorderRadius()) { // If the style has rounded borders, setup the context to clip the // background (themed or filled) appropriately. // FIXME: make sure we do the right thing if css background-clip is set. i.context->save(); i.context->addRoundedRectClip(o->style()->getRoundedBorderFor(r)); } { const ThemeData& themeData = getThemeData(o); ThemePainter painter(i.context, r); PlatformBridge::paintTextField(painter.context(), themeData.m_part, themeData.m_state, themeData.m_classicState, painter.drawRect(), backgroundColor, fillContentArea, drawEdges); // End of block commits the painter before restoring context. } if (o->style()->hasBorderRadius()) i.context->restore(); return false; } void RenderThemeChromiumWin::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { int width = ScrollbarTheme::nativeTheme()->scrollbarThickness(); style->setWidth(Length(width, Fixed)); style->setMinWidth(Length(width, Fixed)); } bool RenderThemeChromiumWin::paintInnerSpinButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) { IntRect half = rect; // Need explicit blocks to avoid to create multiple ThemePainter instances. { half.setHeight(rect.height() / 2); const ThemeData& upThemeData = getThemeData(object, SpinButtonUp); ThemePainter upPainter(info.context, half); PlatformBridge::paintSpinButton(upPainter.context(), upThemeData.m_part, upThemeData.m_state, upThemeData.m_classicState, upPainter.drawRect()); } { half.setY(rect.y() + rect.height() / 2); const ThemeData& downThemeData = getThemeData(object, SpinButtonDown); ThemePainter downPainter(info.context, half); PlatformBridge::paintSpinButton(downPainter.context(), downThemeData.m_part, downThemeData.m_state, downThemeData.m_classicState, downPainter.drawRect()); } return false; } #if ENABLE(PROGRESS_TAG) // MSDN says that update intervals for the bar is 30ms. // http://msdn.microsoft.com/en-us/library/bb760842(v=VS.85).aspx static const double progressAnimationFrameRate = 0.033; double RenderThemeChromiumWin::animationRepeatIntervalForProgressBar(RenderProgress*) const { return progressAnimationFrameRate; } double RenderThemeChromiumWin::animationDurationForProgressBar(RenderProgress* renderProgress) const { // On Chromium Windows port, animationProgress() and associated values aren't used. // So here we can return arbitrary positive value. return progressAnimationFrameRate; } void RenderThemeChromiumWin::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const { } bool RenderThemeChromiumWin::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& r) { if (!o->isProgress()) return true; RenderProgress* renderProgress = toRenderProgress(o); // For indeterminate bar, valueRect is ignored and it is computed by the theme engine // because the animation is a platform detail and WebKit doesn't need to know how. IntRect valueRect = renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, r) : IntRect(0, 0, 0, 0); double animatedSeconds = renderProgress->animationStartTime() ? WTF::currentTime() - renderProgress->animationStartTime() : 0; ThemePainter painter(i.context, r); PlatformBridge::paintProgressBar(painter.context(), r, valueRect, renderProgress->isDeterminate(), animatedSeconds); return false; } #endif } // namespace WebCore