// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/child/webthemeengine_impl_win.h"

#include <vsstyle.h>  // To convert to ui::NativeTheme::State

#include "base/logging.h"
#include "skia/ext/platform_canvas.h"
#include "skia/ext/skia_utils_win.h"
#include "third_party/WebKit/public/platform/WebRect.h"
#include "ui/gfx/win/dpi.h"
#include "ui/native_theme/native_theme.h"

using blink::WebCanvas;
using blink::WebColor;
using blink::WebRect;
using blink::WebSize;

namespace webkit_glue {

static RECT WebRectToRECT(const WebRect& rect) {
  RECT result;
  result.left = rect.x;
  result.top = rect.y;
  result.right = rect.x + rect.width;
  result.bottom = rect.y + rect.height;
  return result;
}

static ui::NativeTheme::State WebButtonStateToGfx(
    int part, int state, ui::NativeTheme::ButtonExtraParams* extra) {
  ui::NativeTheme::State gfx_state = ui::NativeTheme::kNormal;
  // Native buttons have a different focus style.
  extra->is_focused = false;
  extra->has_border = false;
  extra->background_color = ui::NativeTheme::instance()->GetSystemColor(
      ui::NativeTheme::kColorId_ButtonBackgroundColor);

  if (part == BP_PUSHBUTTON) {
    switch (state) {
      case PBS_NORMAL:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case PBS_HOT:
        gfx_state = ui::NativeTheme::kHovered;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case PBS_PRESSED:
        gfx_state = ui::NativeTheme::kPressed;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case PBS_DISABLED:
        gfx_state = ui::NativeTheme::kDisabled;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case PBS_DEFAULTED:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = true;
        break;
      case PBS_DEFAULTED_ANIMATING:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = true;
        break;
      default:
        NOTREACHED() << "Invalid state: " << state;
    }
  } else if (part == BP_RADIOBUTTON) {
    switch (state) {
      case RBS_UNCHECKEDNORMAL:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case RBS_UNCHECKEDHOT:
        gfx_state = ui::NativeTheme::kHovered;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case RBS_UNCHECKEDPRESSED:
        gfx_state = ui::NativeTheme::kPressed;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case RBS_UNCHECKEDDISABLED:
        gfx_state = ui::NativeTheme::kDisabled;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case RBS_CHECKEDNORMAL:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = true;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case RBS_CHECKEDHOT:
        gfx_state = ui::NativeTheme::kHovered;
        extra->checked = true;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case RBS_CHECKEDPRESSED:
        gfx_state = ui::NativeTheme::kPressed;
        extra->checked = true;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case RBS_CHECKEDDISABLED:
        gfx_state = ui::NativeTheme::kDisabled;
        extra->checked = true;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      default:
        NOTREACHED() << "Invalid state: " << state;
        break;
    }
  } else if (part == BP_CHECKBOX) {
    switch (state) {
      case CBS_UNCHECKEDNORMAL:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_UNCHECKEDHOT:
        gfx_state = ui::NativeTheme::kHovered;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_UNCHECKEDPRESSED:
        gfx_state = ui::NativeTheme::kPressed;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_UNCHECKEDDISABLED:
        gfx_state = ui::NativeTheme::kDisabled;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_CHECKEDNORMAL:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = true;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_CHECKEDHOT:
        gfx_state = ui::NativeTheme::kHovered;
        extra->checked = true;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_CHECKEDPRESSED:
        gfx_state = ui::NativeTheme::kPressed;
        extra->checked = true;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_CHECKEDDISABLED:
        gfx_state = ui::NativeTheme::kDisabled;
        extra->checked = true;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_MIXEDNORMAL:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = true;
        extra->is_default = false;
        break;
      case CBS_MIXEDHOT:
        gfx_state = ui::NativeTheme::kHovered;
        extra->checked = false;
        extra->indeterminate = true;
        extra->is_default = false;
        break;
      case CBS_MIXEDPRESSED:
        gfx_state = ui::NativeTheme::kPressed;
        extra->checked = false;
        extra->indeterminate = true;
        extra->is_default = false;
        break;
      case CBS_MIXEDDISABLED:
        gfx_state = ui::NativeTheme::kDisabled;
        extra->checked = false;
        extra->indeterminate = true;
        extra->is_default = false;
        break;
      case CBS_IMPLICITNORMAL:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_IMPLICITHOT:
        gfx_state = ui::NativeTheme::kHovered;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_IMPLICITPRESSED:
        gfx_state = ui::NativeTheme::kPressed;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_IMPLICITDISABLED:
        gfx_state = ui::NativeTheme::kDisabled;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_EXCLUDEDNORMAL:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_EXCLUDEDHOT:
        gfx_state = ui::NativeTheme::kHovered;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_EXCLUDEDPRESSED:
        gfx_state = ui::NativeTheme::kPressed;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CBS_EXCLUDEDDISABLED:
        gfx_state = ui::NativeTheme::kDisabled;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      default:
        NOTREACHED() << "Invalid state: " << state;
        break;
    }
  } else if (part == BP_GROUPBOX) {
    switch (state) {
      case GBS_NORMAL:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case GBS_DISABLED:
        gfx_state = ui::NativeTheme::kDisabled;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      default:
        NOTREACHED() << "Invalid state: " << state;
        break;
    }
  } else if (part == BP_COMMANDLINK) {
    switch (state) {
      case CMDLS_NORMAL:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CMDLS_HOT:
        gfx_state = ui::NativeTheme::kHovered;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CMDLS_PRESSED:
        gfx_state = ui::NativeTheme::kPressed;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CMDLS_DISABLED:
        gfx_state = ui::NativeTheme::kDisabled;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CMDLS_DEFAULTED:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = true;
        break;
      case CMDLS_DEFAULTED_ANIMATING:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = true;
        break;
      default:
        NOTREACHED() << "Invalid state: " << state;
        break;
    }
  } else if (part == BP_COMMANDLINKGLYPH) {
    switch (state) {
      case CMDLGS_NORMAL:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CMDLGS_HOT:
        gfx_state = ui::NativeTheme::kHovered;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CMDLGS_PRESSED:
        gfx_state = ui::NativeTheme::kPressed;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CMDLGS_DISABLED:
        gfx_state = ui::NativeTheme::kDisabled;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = false;
        break;
      case CMDLGS_DEFAULTED:
        gfx_state = ui::NativeTheme::kNormal;
        extra->checked = false;
        extra->indeterminate = false;
        extra->is_default = true;
        break;
      default:
        NOTREACHED() << "Invalid state: " << state;
        break;
    }
  }
  return gfx_state;
}

void WebThemeEngineImpl::paintButton(
    WebCanvas* canvas, int part, int state, int classic_state,
    const WebRect& rect) {
  ui::NativeTheme::Part native_part = ui::NativeTheme::kPushButton;
  switch (part) {
    case BP_PUSHBUTTON:
      native_part = ui::NativeTheme::kPushButton;
      break;
    case BP_CHECKBOX:
      native_part = ui::NativeTheme::kCheckbox;
      break;
    case BP_RADIOBUTTON:
      native_part = ui::NativeTheme::kRadio;
      break;
    default:
      NOTREACHED() << "Invalid part: " << part;
      break;
  }
  ui::NativeTheme::ExtraParams extra;
  ui::NativeTheme::State native_state = WebButtonStateToGfx(part, state,
                                                             &extra.button);
  extra.button.classic_state = classic_state;
  gfx::Rect gfx_rect(rect.x, rect.y, rect.width, rect.height);
  ui::NativeTheme::instance()->Paint(canvas, native_part,
                                      native_state, gfx_rect, extra);
}

static ui::NativeTheme::State WebListMenuStateToGfx(int part, int state) {
  ui::NativeTheme::State gfx_state = ui::NativeTheme::kNormal;

  switch (part) {
    case CP_DROPDOWNBUTTON:
      switch (state) {
        case CBXS_NORMAL:
          gfx_state = ui::NativeTheme::kNormal;
          break;
        case CBXS_HOT:
          gfx_state = ui::NativeTheme::kHovered;
          break;
        case CBXS_PRESSED:
          gfx_state = ui::NativeTheme::kPressed;
          break;
        case CBXS_DISABLED:
          gfx_state = ui::NativeTheme::kDisabled;
          break;
        default:
          NOTREACHED() << "Invalid state: " << state;
          break;
      }
      break;
    default:
      NOTREACHED() << "Invalid part: " << part;
      break;
  }
  return gfx_state;
}

void WebThemeEngineImpl::paintMenuList(
    WebCanvas* canvas, int part, int state, int classic_state,
    const WebRect& rect) {
  ui::NativeTheme::Part native_part = ui::NativeTheme::kMenuList;
  switch (part) {
    case CP_DROPDOWNBUTTON:
      native_part = ui::NativeTheme::kMenuList;
      break;
    default:
      NOTREACHED() << "Invalid part: " << part;
      break;
  }
  ui::NativeTheme::State native_state = WebListMenuStateToGfx(part, state);
  gfx::Rect gfx_rect(rect.x, rect.y, rect.width, rect.height);
  ui::NativeTheme::ExtraParams extra;
  extra.menu_list.classic_state = classic_state;
  ui::NativeTheme::instance()->Paint(canvas, native_part,
                                      native_state, gfx_rect, extra);
}

static ui::NativeTheme::State WebScrollbarArrowStateToGfx(
    int state, ui::NativeTheme::Part* part,
    ui::NativeTheme::ScrollbarArrowExtraParams* extra) {
  ui::NativeTheme::State gfx_state = ui::NativeTheme::kNormal;
  switch (state) {
    case ABS_UPNORMAL:
      gfx_state = ui::NativeTheme::kNormal;
      *part = ui::NativeTheme::kScrollbarUpArrow;
      extra->is_hovering = false;
      break;
    case ABS_UPHOT:
      gfx_state = ui::NativeTheme::kHovered;
      *part = ui::NativeTheme::kScrollbarUpArrow;
      extra->is_hovering = false;
      break;
    case ABS_UPPRESSED:
      gfx_state = ui::NativeTheme::kPressed;
      *part = ui::NativeTheme::kScrollbarUpArrow;
      extra->is_hovering = false;
      break;
    case ABS_UPDISABLED:
      gfx_state = ui::NativeTheme::kDisabled;
      *part = ui::NativeTheme::kScrollbarUpArrow;
      extra->is_hovering = false;
      break;
    case ABS_DOWNNORMAL:
      gfx_state = ui::NativeTheme::kNormal;
      *part = ui::NativeTheme::kScrollbarDownArrow;
      extra->is_hovering = false;
      break;
    case ABS_DOWNHOT:
      gfx_state = ui::NativeTheme::kHovered;
      *part = ui::NativeTheme::kScrollbarDownArrow;
      extra->is_hovering = false;
      break;
    case ABS_DOWNPRESSED:
      gfx_state = ui::NativeTheme::kPressed;
      *part = ui::NativeTheme::kScrollbarDownArrow;
      extra->is_hovering = false;
      break;
    case ABS_DOWNDISABLED:
      gfx_state = ui::NativeTheme::kDisabled;
      *part = ui::NativeTheme::kScrollbarDownArrow;
      extra->is_hovering = false;
      break;
    case ABS_LEFTNORMAL:
      gfx_state = ui::NativeTheme::kNormal;
      *part = ui::NativeTheme::kScrollbarLeftArrow;
      extra->is_hovering = false;
      break;
    case ABS_LEFTHOT:
      gfx_state = ui::NativeTheme::kHovered;
      *part = ui::NativeTheme::kScrollbarLeftArrow;
      extra->is_hovering = false;
      break;
    case ABS_LEFTPRESSED:
      gfx_state = ui::NativeTheme::kPressed;
      *part = ui::NativeTheme::kScrollbarLeftArrow;
      extra->is_hovering = false;
      break;
    case ABS_LEFTDISABLED:
      gfx_state = ui::NativeTheme::kDisabled;
      *part = ui::NativeTheme::kScrollbarLeftArrow;
      extra->is_hovering = false;
      break;
    case ABS_RIGHTNORMAL:
      gfx_state = ui::NativeTheme::kNormal;
      *part = ui::NativeTheme::kScrollbarRightArrow;
      extra->is_hovering = false;
      break;
    case ABS_RIGHTHOT:
      gfx_state = ui::NativeTheme::kHovered;
      *part = ui::NativeTheme::kScrollbarRightArrow;
      extra->is_hovering = false;
      break;
    case ABS_RIGHTPRESSED:
      gfx_state = ui::NativeTheme::kPressed;
      *part = ui::NativeTheme::kScrollbarRightArrow;
      extra->is_hovering = false;
      break;
    case ABS_RIGHTDISABLED:
      gfx_state = ui::NativeTheme::kDisabled;
      *part = ui::NativeTheme::kScrollbarRightArrow;
      extra->is_hovering = false;
      break;
    case ABS_UPHOVER:
      gfx_state = ui::NativeTheme::kHovered;
      *part = ui::NativeTheme::kScrollbarUpArrow;
      extra->is_hovering = true;
      break;
    case ABS_DOWNHOVER:
      gfx_state = ui::NativeTheme::kHovered;
      *part = ui::NativeTheme::kScrollbarDownArrow;
      extra->is_hovering = true;
      break;
    case ABS_LEFTHOVER:
      gfx_state = ui::NativeTheme::kHovered;
      *part = ui::NativeTheme::kScrollbarLeftArrow;
      extra->is_hovering = true;
      break;
    case ABS_RIGHTHOVER:
      gfx_state = ui::NativeTheme::kHovered;
      *part = ui::NativeTheme::kScrollbarRightArrow;
      extra->is_hovering = true;
      break;
    default:
      NOTREACHED() << "Invalid state: " << state;
      break;
  }
  return gfx_state;
}

void WebThemeEngineImpl::paintScrollbarArrow(
    WebCanvas* canvas, int state, int classic_state, const WebRect& rect) {
  ui::NativeTheme::Part native_part;
  ui::NativeTheme::ExtraParams extra;
  ui::NativeTheme::State native_state = WebScrollbarArrowStateToGfx(
      state, &native_part, &extra.scrollbar_arrow);
  gfx::Rect gfx_rect(rect.x, rect.y, rect.width, rect.height);
  ui::NativeTheme::instance()->Paint(canvas, native_part,
                                      native_state, gfx_rect, extra);
}

static ui::NativeTheme::State WebScrollbarThumbStateToGfx(
    int state, ui::NativeTheme::ScrollbarThumbExtraParams* extra) {
  ui::NativeTheme::State gfx_state = ui::NativeTheme::kNormal;
  switch (state) {
    case SCRBS_NORMAL:
      gfx_state = ui::NativeTheme::kNormal;
      extra->is_hovering = false;
      break;
    case SCRBS_HOVER:
      gfx_state = ui::NativeTheme::kHovered;
      extra->is_hovering = true;
      break;
    case SCRBS_HOT:
      gfx_state = ui::NativeTheme::kHovered;
      extra->is_hovering = false;
      break;
    case SCRBS_PRESSED:
      gfx_state = ui::NativeTheme::kPressed;
      extra->is_hovering = false;
      break;
    case SCRBS_DISABLED:
      gfx_state = ui::NativeTheme::kDisabled;
      extra->is_hovering = false;
      break;
    default:
      NOTREACHED() << "Invalid state: " << state;
      break;
  }
  return gfx_state;
}

void WebThemeEngineImpl::paintScrollbarThumb(
    WebCanvas* canvas, int part, int state, int classic_state,
    const WebRect& rect) {
  ui::NativeTheme::Part native_part;
  if (part == SBP_THUMBBTNHORZ) {
    native_part = ui::NativeTheme::kScrollbarHorizontalThumb;
  } else if (part == SBP_THUMBBTNVERT) {
    native_part = ui::NativeTheme::kScrollbarVerticalThumb;
  } else if (part == SBP_GRIPPERHORZ) {
    native_part = ui::NativeTheme::kScrollbarHorizontalGripper;
  } else if (part == SBP_GRIPPERVERT) {
    native_part = ui::NativeTheme::kScrollbarVerticalGripper;
  } else {
      NOTREACHED() << "Invalid part: " << part;
  }

  ui::NativeTheme::ExtraParams extra;
  ui::NativeTheme::State native_state = WebScrollbarThumbStateToGfx(
      state, &extra.scrollbar_thumb);

  gfx::Rect gfx_rect(rect.x, rect.y, rect.width, rect.height);
  ui::NativeTheme::instance()->Paint(canvas, native_part,
                                      native_state, gfx_rect, extra);
}

static ui::NativeTheme::State WebScrollbarTrackStateToGfx(
    int part, int state, ui::NativeTheme::Part* gfx_part,
    ui::NativeTheme::ScrollbarTrackExtraParams* extra) {
  ui::NativeTheme::State gfx_state = ui::NativeTheme::kNormal;
  switch (part) {
    case SBP_LOWERTRACKHORZ:
      switch (state) {
        case SCRBS_NORMAL:
          gfx_state = ui::NativeTheme::kNormal;
          *gfx_part = ui::NativeTheme::kScrollbarHorizontalTrack;
          extra->is_upper = false;
          break;
        case SCRBS_HOVER:
        case SCRBS_HOT:
          gfx_state = ui::NativeTheme::kHovered;
          *gfx_part = ui::NativeTheme::kScrollbarHorizontalTrack;
          extra->is_upper = false;
          break;
        case SCRBS_PRESSED:
          gfx_state = ui::NativeTheme::kPressed;
          *gfx_part = ui::NativeTheme::kScrollbarHorizontalTrack;
          extra->is_upper = false;
          break;
        case SCRBS_DISABLED:
          gfx_state = ui::NativeTheme::kDisabled;
          *gfx_part = ui::NativeTheme::kScrollbarHorizontalTrack;
          extra->is_upper = false;
          break;
        default:
          NOTREACHED() << "Invalid state: " << state;
          break;
      }
      break;
    case SBP_UPPERTRACKHORZ:
      switch (state) {
        case SCRBS_NORMAL:
          gfx_state = ui::NativeTheme::kNormal;
          *gfx_part = ui::NativeTheme::kScrollbarHorizontalTrack;
          extra->is_upper = true;
          break;
        case SCRBS_HOVER:
        case SCRBS_HOT:
          gfx_state = ui::NativeTheme::kHovered;
          *gfx_part = ui::NativeTheme::kScrollbarHorizontalTrack;
          extra->is_upper = true;
          break;
        case SCRBS_PRESSED:
          gfx_state = ui::NativeTheme::kPressed;
          *gfx_part = ui::NativeTheme::kScrollbarHorizontalTrack;
          extra->is_upper = true;
          break;
        case SCRBS_DISABLED:
          gfx_state = ui::NativeTheme::kDisabled;
          *gfx_part = ui::NativeTheme::kScrollbarHorizontalTrack;
          extra->is_upper = true;
          break;
        default:
          NOTREACHED() << "Invalid state: " << state;
          break;
      }
      break;
    case SBP_LOWERTRACKVERT:
      switch (state) {
        case SCRBS_NORMAL:
          gfx_state = ui::NativeTheme::kNormal;
          *gfx_part = ui::NativeTheme::kScrollbarVerticalTrack;
          extra->is_upper = false;
          break;
        case SCRBS_HOVER:
        case SCRBS_HOT:
          gfx_state = ui::NativeTheme::kHovered;
          *gfx_part = ui::NativeTheme::kScrollbarVerticalTrack;
          extra->is_upper = false;
          break;
        case SCRBS_PRESSED:
          gfx_state = ui::NativeTheme::kPressed;
          *gfx_part = ui::NativeTheme::kScrollbarVerticalTrack;
          extra->is_upper = false;
          break;
        case SCRBS_DISABLED:
          gfx_state = ui::NativeTheme::kDisabled;
          *gfx_part = ui::NativeTheme::kScrollbarVerticalTrack;
          extra->is_upper = false;
          break;
        default:
          NOTREACHED() << "Invalid state: " << state;
          break;
      }
      break;
    case SBP_UPPERTRACKVERT:
      switch (state) {
        case SCRBS_NORMAL:
          gfx_state = ui::NativeTheme::kNormal;
          *gfx_part = ui::NativeTheme::kScrollbarVerticalTrack;
          extra->is_upper = true;
          break;
        case SCRBS_HOVER:
        case SCRBS_HOT:
          gfx_state = ui::NativeTheme::kHovered;
          *gfx_part = ui::NativeTheme::kScrollbarVerticalTrack;
          extra->is_upper = true;
          break;
        case SCRBS_PRESSED:
          gfx_state = ui::NativeTheme::kPressed;
          *gfx_part = ui::NativeTheme::kScrollbarVerticalTrack;
          extra->is_upper = true;
          break;
        case SCRBS_DISABLED:
          gfx_state = ui::NativeTheme::kDisabled;
          *gfx_part = ui::NativeTheme::kScrollbarVerticalTrack;
          extra->is_upper = true;
          break;
        default:
          NOTREACHED() << "Invalid state: " << state;
          break;
      }
      break;
    default:
      NOTREACHED() << "Invalid part: " << part;
      break;
  }
  return gfx_state;
}

void WebThemeEngineImpl::paintScrollbarTrack(
    WebCanvas* canvas, int part, int state, int classic_state,
    const WebRect& rect, const WebRect& align_rect) {
  ui::NativeTheme::Part native_part;
  ui::NativeTheme::ExtraParams extra;
  ui::NativeTheme::State native_state = WebScrollbarTrackStateToGfx(
      part, state, &native_part, &extra.scrollbar_track);
  extra.scrollbar_track.classic_state = classic_state;
  extra.scrollbar_track.track_x = align_rect.x;
  extra.scrollbar_track.track_y = align_rect.y;
  extra.scrollbar_track.track_width = align_rect.width;
  extra.scrollbar_track.track_height = align_rect.height;

  gfx::Rect gfx_rect(rect.x, rect.y, rect.width, rect.height);
  ui::NativeTheme::instance()->Paint(canvas, native_part,
                                      native_state, gfx_rect, extra);
}

static ui::NativeTheme::State WebSpinButtonStateToGfx(
    int part, int state, ui::NativeTheme::InnerSpinButtonExtraParams* extra) {
  ui::NativeTheme::State gfx_state = ui::NativeTheme::kNormal;
  switch (part) {
    case SPNP_UP:
      switch (state) {
        case UPS_NORMAL:
          gfx_state = ui::NativeTheme::kNormal;
          extra->spin_up = true;
          extra->read_only = false;
          break;
        case UPS_HOT:
          gfx_state = ui::NativeTheme::kHovered;
          extra->spin_up = true;
          extra->read_only = false;
          break;
        case UPS_PRESSED:
          gfx_state = ui::NativeTheme::kPressed;
          extra->spin_up = true;
          extra->read_only = false;
          break;
        case UPS_DISABLED:
          gfx_state = ui::NativeTheme::kDisabled;
          extra->spin_up = true;
          extra->read_only = false;
          break;
        default:
          NOTREACHED() << "Invalid state: " << state;
          break;
      }
      break;
    case SPNP_DOWN:
      switch (state) {
        case DNS_NORMAL:
          gfx_state = ui::NativeTheme::kNormal;
          extra->spin_up = false;
          extra->read_only = false;
          break;
        case DNS_HOT:
          gfx_state = ui::NativeTheme::kHovered;
          extra->spin_up = false;
          extra->read_only = false;
          break;
        case DNS_PRESSED:
          gfx_state = ui::NativeTheme::kPressed;
          extra->spin_up = false;
          extra->read_only = false;
          break;
        case DNS_DISABLED:
          gfx_state = ui::NativeTheme::kDisabled;
          extra->spin_up = false;
          extra->read_only = false;
          break;
        default:
          NOTREACHED() << "Invalid state: " << state;
          break;
      }
      break;
    default:
      NOTREACHED() << "Invalid part: " << part;
      break;
  }
  return gfx_state;
}

void WebThemeEngineImpl::paintSpinButton(
    WebCanvas* canvas, int part, int state, int classic_state,
    const WebRect& rect) {
  ui::NativeTheme::ExtraParams extra;
  ui::NativeTheme::State native_state = WebSpinButtonStateToGfx(
      part, state, &extra.inner_spin);
  extra.inner_spin.classic_state = classic_state;
  gfx::Rect gfx_rect(rect.x, rect.y, rect.width, rect.height);
  ui::NativeTheme::instance()->Paint(canvas,
                                      ui::NativeTheme::kInnerSpinButton,
                                      native_state,
                                      gfx_rect,
                                      extra);
}

static ui::NativeTheme::State WebTextFieldStateToGfx(
    int part, int state, ui::NativeTheme::TextFieldExtraParams* extra) {
  ui::NativeTheme::State gfx_state = ui::NativeTheme::kNormal;
  switch (part) {
    case EP_EDITTEXT:
      switch (state) {
        case ETS_NORMAL:
          gfx_state = ui::NativeTheme::kNormal;
          extra->is_read_only = false;
          extra->is_focused = false;
          break;
        case ETS_HOT:
          gfx_state = ui::NativeTheme::kHovered;
          extra->is_read_only = false;
          extra->is_focused = false;
          break;
        case ETS_SELECTED:
          gfx_state = ui::NativeTheme::kPressed;
          extra->is_read_only = false;
          extra->is_focused = false;
          break;
        case ETS_DISABLED:
          gfx_state = ui::NativeTheme::kDisabled;
          extra->is_read_only = false;
          extra->is_focused = false;
          break;
        case ETS_FOCUSED:
          gfx_state = ui::NativeTheme::kNormal;
          extra->is_read_only = false;
          extra->is_focused = true;
          break;
        case ETS_READONLY:
          gfx_state = ui::NativeTheme::kNormal;
          extra->is_read_only = true;
          extra->is_focused = false;
          break;
        default:
          NOTREACHED() << "Invalid state: " << state;
          break;
      }
      break;
    default:
      NOTREACHED() << "Invalid part: " << part;
      break;
  }
  return gfx_state;
}

void WebThemeEngineImpl::paintTextField(
    WebCanvas* canvas, int part, int state, int classic_state,
    const WebRect& rect, WebColor color, bool fill_content_area,
    bool draw_edges) {
  ui::NativeTheme::ExtraParams extra;
  ui::NativeTheme::State native_state = WebTextFieldStateToGfx(
      part, state, &extra.text_field);
  extra.text_field.fill_content_area = fill_content_area;
  extra.text_field.draw_edges = draw_edges;
  extra.text_field.background_color = color;
  extra.text_field.classic_state = classic_state;
  gfx::Rect gfx_rect(rect.x, rect.y, rect.width, rect.height);

  ui::NativeTheme::instance()->Paint(canvas,
      ui::NativeTheme::kTextField, native_state, gfx_rect, extra);
}

static ui::NativeTheme::State WebTrackbarStateToGfx(
    int part,
    int state,
    ui::NativeTheme::TrackbarExtraParams* extra) {
  ui::NativeTheme::State gfx_state = ui::NativeTheme::kNormal;
  switch (state) {
    case TUS_NORMAL:
      gfx_state = ui::NativeTheme::kNormal;
      break;
    case TUS_HOT:
      gfx_state = ui::NativeTheme::kHovered;
      break;
    case TUS_PRESSED:
      gfx_state = ui::NativeTheme::kPressed;
      break;
    case TUS_DISABLED:
      gfx_state = ui::NativeTheme::kDisabled;
      break;
    default:
      NOTREACHED() << "Invalid state: " << state;
      break;
  }

  switch (part) {
    case TKP_TRACK:
    case TKP_THUMBBOTTOM:
      extra->vertical = false;
      break;
    case TKP_TRACKVERT:
    case TKP_THUMBVERT:
      extra->vertical = true;
      break;
    default:
      NOTREACHED() << "Invalid part: " << part;
      break;
  }

  return gfx_state;
}

void WebThemeEngineImpl::paintTrackbar(
    WebCanvas* canvas, int part, int state, int classic_state,
    const WebRect& rect) {
  ui::NativeTheme::Part native_part = ui::NativeTheme::kTrackbarTrack;
  switch (part) {
    case TKP_TRACK:
    case TKP_TRACKVERT:
      native_part = ui::NativeTheme::kTrackbarTrack;
      break;
    case TKP_THUMBBOTTOM:
    case TKP_THUMBVERT:
      native_part = ui::NativeTheme::kTrackbarThumb;
      break;
    default:
      NOTREACHED() << "Invalid part: " << part;
      break;
  }

  ui::NativeTheme::ExtraParams extra;
  ui::NativeTheme::State native_state = WebTrackbarStateToGfx(part, state,
                                                               &extra.trackbar);
  gfx::Rect gfx_rect(rect.x, rect.y, rect.width, rect.height);
  extra.trackbar.classic_state = classic_state;
  ui::NativeTheme::instance()->Paint(canvas, native_part,
                                      native_state, gfx_rect, extra);
}

void WebThemeEngineImpl::paintProgressBar(
    WebCanvas* canvas, const WebRect& barRect, const WebRect& valueRect,
    bool determinate, double animatedSeconds)
{
  gfx::Rect gfx_rect(barRect.x, barRect.y, barRect.width, barRect.height);
  ui::NativeTheme::ExtraParams extra;
  extra.progress_bar.animated_seconds = animatedSeconds;
  extra.progress_bar.determinate = determinate;
  extra.progress_bar.value_rect_x = valueRect.x;
  extra.progress_bar.value_rect_y = valueRect.y;
  extra.progress_bar.value_rect_width = valueRect.width;
  extra.progress_bar.value_rect_height = valueRect.height;
  ui::NativeTheme::instance()->Paint(canvas, ui::NativeTheme::kProgressBar,
                                      ui::NativeTheme::kNormal, gfx_rect,
                                      extra);
}

WebSize WebThemeEngineImpl::getSize(int part) {
  switch (part) {
    case SBP_ARROWBTN: {
      gfx::Size size = ui::NativeTheme::instance()->GetPartSize(
          ui::NativeTheme::kScrollbarUpArrow,
          ui::NativeTheme::kNormal,
          ui::NativeTheme::ExtraParams());
      // GetPartSize returns a size of (0, 0) when not using a themed style
      // (i.e. Windows Classic).  Returning a non-zero size in this context
      // creates repaint conflicts, particularly in the window titlebar area
      // which significantly degrades performance.  Fallback to using a system
      // metric if required.
      if (size.width() == 0) {
        int width = static_cast<int>(GetSystemMetrics(SM_CXVSCROLL) /
            gfx::win::GetDeviceScaleFactor());
        size = gfx::Size(width, width);
      }
      return WebSize(size.width(), size.height());
    }
    default:
      NOTREACHED() << "Unhandled part: " << part;
  }
  return WebSize();
}

}  // namespace webkit_glue