text: /*
   * 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 <windows.h>
  #include <uxtheme.h>
  #include <vssym32.h>
  
  #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 "PlatformSupport.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 <skia/ext/skia_utils_win.h>
  
  #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \
      offsetof(structName, member) + \
      (sizeof static_cast<structName*>(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<SkCanvas*>(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 SquareButtonPart:
      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<RenderTheme> RenderThemeChromiumWin::create()
  {
      return adoptRef(new RenderThemeChromiumWin);
  }
  
  PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
  {
      static RenderTheme* rt = RenderThemeChromiumWin::create().leakRef();
      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
              || style->appearance() == SquareButtonPart;
  }
  
  Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const
  {
      if (PlatformSupport::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 (PlatformSupport::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 (PlatformSupport::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 (PlatformSupport::layoutTestMode() || (sysColorIndex == -1))
          return RenderTheme::systemColor(cssValueId);
  
      COLORREF color = GetSysColor(sysColorIndex);
      return Color(GetRValue(color), GetGValue(color), GetBValue(color));
  }
  
  void RenderThemeChromiumWin::adjustSliderThumbSize(RenderStyle* style) const
  {
      // These sizes match what WinXP draws for various menus.
      const int sliderThumbAlongAxis = 11;
      const int sliderThumbAcrossAxis = 21;
      if (style->appearance() == SliderThumbHorizontalPart) {
          style->setWidth(Length(sliderThumbAlongAxis, Fixed));
          style->setHeight(Length(sliderThumbAcrossAxis, Fixed));
      } else if (style->appearance() == SliderThumbVerticalPart) {
          style->setWidth(Length(sliderThumbAcrossAxis, Fixed));
          style->setHeight(Length(sliderThumbAlongAxis, Fixed));
      } else
          RenderThemeChromiumSkia::adjustSliderThumbSize(style);
  }
  
  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);
      PlatformSupport::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);
      PlatformSupport::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 = PlatformSupport::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);
      PlatformSupport::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))
          result = TUS_DISABLED;
      else if (supportsFocus(o->style()->appearance()) && isFocused(o))
          result = TUS_FOCUSED;
      else if (isPressed(o))
          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))
              result = DFCS_INACTIVE;
          else if (isPressed(o)) // 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 SquareButtonPart:
      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 PlatformSupport::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);
          PlatformSupport::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::theme()->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);
          PlatformSupport::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);
          PlatformSupport::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);
      PlatformSupport::paintProgressBar(painter.context(), r, valueRect, renderProgress->isDeterminate(), animatedSeconds);
      return false;
  }
  
  #endif
  
  } // namespace WebCore
  