RenderThemeChromiumWin.cpp [plain text]
#include "config.h"
#include "RenderThemeChromiumWin.h"
#include <windows.h>
#include <uxtheme.h>
#include <vssym32.h>
#include "ChromiumBridge.h"
#include "CSSStyleSheet.h"
#include "CSSValueKeywords.h"
#include "Document.h"
#include "FontSelector.h"
#include "FontUtilsChromiumWin.h"
#include "GraphicsContext.h"
#include "ScrollbarTheme.h"
#include "SkiaUtils.h"
#include "ThemeHelperChromiumWin.h"
#include "UserAgentStyleSheets.h"
#include "WindowsVersion.h"
#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 {
static void getNonClientMetrics(NONCLIENTMETRICS* metrics) {
static UINT size = WebCore::isVistaOrNewer() ?
sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
metrics->cbSize = size;
bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0);
ASSERT(success);
}
enum PaddingType {
TopPadding,
RightPadding,
BottomPadding,
LeftPadding
};
static const int styledMenuListInternalPadding[4] = { 1, 4, 1, 4 };
static float defaultFontSize = 16.0;
static FontDescription smallSystemFont;
static FontDescription menuFont;
static FontDescription labelFont;
bool RenderThemeChromiumWin::m_findInPageMode = false;
static bool supportsFocus(ControlPart appearance)
{
switch (appearance) {
case PushButtonPart:
case ButtonPart:
case DefaultButtonPart:
case TextFieldPart:
case TextAreaPart:
return true;
}
return false;
}
static void setFixedPadding(RenderStyle* style, const int padding[4])
{
style->setPaddingLeft(Length(padding[LeftPadding], Fixed));
style->setPaddingRight(Length(padding[RightPadding], Fixed));
style->setPaddingTop(Length(padding[TopPadding], Fixed));
style->setPaddingBottom(Length(padding[BottomPadding], Fixed));
}
static float systemFontSize(const LOGFONT& font)
{
float size = -font.lfHeight;
if (size < 0) {
HFONT hFont = CreateFontIndirect(&font);
if (hFont) {
HDC hdc = GetDC(0); if (hdc) {
HGDIOBJ hObject = SelectObject(hdc, hFont);
TEXTMETRIC tm;
GetTextMetrics(hdc, &tm);
SelectObject(hdc, hObject);
ReleaseDC(0, hdc);
size = tm.tmAscent;
}
DeleteObject(hFont);
}
}
return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size;
}
static wchar_t* defaultGUIFont(Document* document)
{
UScriptCode dominantScript = document->dominantScript();
const wchar_t* family = NULL;
if (dominantScript != USCRIPT_LATIN &&
dominantScript != USCRIPT_CYRILLIC &&
dominantScript != USCRIPT_GREEK &&
dominantScript != USCRIPT_INVALID_CODE) {
family = getFontFamilyForScript(dominantScript, FontDescription::NoFamily);
if (family)
return const_cast<wchar_t*>(family);
}
return L"Arial";
}
static float pointsToPixels(float points)
{
static float pixelsPerInch = 0.0f;
if (!pixelsPerInch) {
HDC hdc = GetDC(0); if (hdc) { pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(0, hdc);
} else {
pixelsPerInch = 96.0f;
}
}
static const float pointsPerInch = 72.0f;
return points / pointsPerInch * pixelsPerInch;
}
static void setSizeIfAuto(RenderStyle* style, const IntSize& size)
{
if (style->width().isIntrinsicOrAuto())
style->setWidth(Length(size.width(), Fixed));
if (style->height().isAuto())
style->setHeight(Length(size.height(), Fixed));
}
static double querySystemBlinkInterval(double defaultInterval)
{
UINT blinkTime = GetCaretBlinkTime();
if (blinkTime == 0)
return defaultInterval;
if (blinkTime == INFINITE)
return 0;
return blinkTime / 1000.0;
}
RenderTheme* theme()
{
static RenderThemeChromiumWin winTheme;
return &winTheme;
}
String RenderThemeChromiumWin::extraDefaultStyleSheet()
{
return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet));
}
String RenderThemeChromiumWin::extraQuirksStyleSheet()
{
return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
}
bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const
{
return style->appearance() == ButtonPart
|| style->appearance() == PushButtonPart;
}
Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const
{
if (ChromiumBridge::layoutTestMode())
return Color("#0000FF"); if (m_findInPageMode)
return Color(255, 150, 50, 200); COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
}
Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const
{
if (ChromiumBridge::layoutTestMode())
return Color("#999999"); if (m_findInPageMode)
return Color(255, 150, 50, 200); COLORREF color = GetSysColor(COLOR_GRAYTEXT);
return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
}
Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const
{
if (ChromiumBridge::layoutTestMode())
return Color("#FFFFCC"); COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
}
Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const
{
return Color::white;
}
Color RenderThemeChromiumWin::platformTextSearchHighlightColor() const
{
return Color(255, 255, 150);
}
double RenderThemeChromiumWin::caretBlinkInterval() const
{
if (ChromiumBridge::layoutTestMode())
return 0;
static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval());
return blinkInterval;
}
void RenderThemeChromiumWin::systemFont(int propId, Document* document, FontDescription& fontDescription) const
{
FontDescription* cachedDesc = NULL;
wchar_t* faceName = 0;
float fontSize = 0;
switch (propId) {
case CSSValueSmallCaption:
cachedDesc = &smallSystemFont;
if (!smallSystemFont.isAbsoluteSize()) {
NONCLIENTMETRICS metrics;
getNonClientMetrics(&metrics);
faceName = metrics.lfSmCaptionFont.lfFaceName;
fontSize = systemFontSize(metrics.lfSmCaptionFont);
}
break;
case CSSValueMenu:
cachedDesc = &menuFont;
if (!menuFont.isAbsoluteSize()) {
NONCLIENTMETRICS metrics;
getNonClientMetrics(&metrics);
faceName = 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(document);
fontSize = defaultFontSize - pointsToPixels(2);
break;
default:
faceName = defaultGUIFont(document);
fontSize = defaultFontSize;
break;
}
if (!cachedDesc)
cachedDesc = &fontDescription;
if (fontSize) {
ASSERT(faceName);
cachedDesc->firstFamily().setFamily(AtomicString(faceName,
wcslen(faceName)));
cachedDesc->setIsAbsoluteSize(true);
cachedDesc->setGenericFamily(FontDescription::NoFamily);
cachedDesc->setSpecifiedSize(fontSize);
cachedDesc->setWeight(FontWeightNormal);
cachedDesc->setItalic(false);
}
fontDescription = *cachedDesc;
}
int RenderThemeChromiumWin::minimumMenuListSize(RenderStyle* style) const
{
return 0;
}
void RenderThemeChromiumWin::setCheckboxSize(RenderStyle* style) const
{
if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
return;
const IntSize size(13, 13);
setSizeIfAuto(style, size);
}
void RenderThemeChromiumWin::setRadioSize(RenderStyle* style) const
{
setCheckboxSize(style);
}
bool RenderThemeChromiumWin::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
{
const ThemeData& themeData = getThemeData(o);
WebCore::ThemeHelperWin helper(i.context, r);
ChromiumBridge::paintButton(helper.context(),
themeData.m_part,
themeData.m_state,
themeData.m_classicState,
helper.rect());
return false;
}
bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
{
return paintTextFieldInternal(o, i, r, true);
}
bool RenderThemeChromiumWin::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
{
return paintTextField(o, i, r);
}
void RenderThemeChromiumWin::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
style->setLineHeight(RenderStyle::initialLineHeight());
}
bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
{
int borderRight = o->borderRight();
int borderLeft = o->borderLeft();
int borderTop = o->borderTop();
int borderBottom = o->borderBottom();
bool drawEdges = !(borderRight == 0 && borderLeft == 0 && borderTop == 0 && borderBottom == 0);
paintTextFieldInternal(o, i, r, drawEdges);
const int buttonWidth = GetSystemMetrics(SM_CXVSCROLL);
int spacingLeft = borderLeft + o->paddingLeft();
int spacingRight = borderRight + o->paddingRight();
int spacingTop = borderTop + o->paddingTop();
int spacingBottom = borderBottom + o->paddingBottom();
int buttonX;
if (r.right() - r.x() < buttonWidth)
buttonX = r.x();
else
buttonX = o->style()->direction() == LTR ? r.right() - spacingRight - buttonWidth : r.x() + spacingLeft;
IntRect rect(buttonX,
r.y() + spacingTop,
std::min(buttonWidth, r.right() - r.x()),
r.height() - (spacingTop + spacingBottom));
WebCore::ThemeHelperWin helper(i.context, rect);
ChromiumBridge::paintMenuList(helper.context(),
CP_DROPDOWNBUTTON,
determineState(o),
determineClassicState(o),
helper.rect());
return false;
}
void RenderThemeChromiumWin::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
{
adjustMenuListStyle(selector, style, e);
}
bool RenderThemeChromiumWin::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
{
return paintMenuList(o, i, r);
}
int RenderThemeChromiumWin::popupInternalPaddingLeft(RenderStyle* style) const
{
return menuListInternalPadding(style, LeftPadding);
}
int RenderThemeChromiumWin::popupInternalPaddingRight(RenderStyle* style) const
{
return menuListInternalPadding(style, RightPadding);
}
int RenderThemeChromiumWin::popupInternalPaddingTop(RenderStyle* style) const
{
return menuListInternalPadding(style, TopPadding);
}
int RenderThemeChromiumWin::popupInternalPaddingBottom(RenderStyle* style) const
{
return menuListInternalPadding(style, BottomPadding);
}
void RenderThemeChromiumWin::adjustButtonInnerStyle(RenderStyle* style) const
{
style->setPaddingTop(Length(1, Fixed));
style->setPaddingRight(Length(3, Fixed));
style->setPaddingBottom(Length(1, Fixed));
style->setPaddingLeft(Length(3, Fixed));
}
void RenderThemeChromiumWin::setDefaultFontSize(int fontSize) {
defaultFontSize = static_cast<float>(fontSize);
smallSystemFont = menuFont = labelFont = FontDescription();
}
unsigned RenderThemeChromiumWin::determineState(RenderObject* o)
{
unsigned result = TS_NORMAL;
ControlPart appearance = o->style()->appearance();
if (!isEnabled(o))
result = TS_DISABLED;
else if (isReadOnlyControl(o) && (TextFieldPart == appearance || TextAreaPart == appearance))
result = ETS_READONLY; else if (isPressed(o)) result = TS_PRESSED;
else if (supportsFocus(appearance) && isFocused(o))
result = ETS_FOCUSED;
else if (isHovered(o))
result = TS_HOT;
if (isChecked(o))
result += 4; return result;
}
unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o)
{
unsigned result = 0;
if (!isEnabled(o))
result = DFCS_INACTIVE;
else if (isPressed(o)) result = DFCS_PUSHED;
else if (isHovered(o))
result = DFCS_HOT;
if (isChecked(o))
result |= DFCS_CHECKED;
return result;
}
ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o)
{
ThemeData result;
switch (o->style()->appearance()) {
case PushButtonPart:
case ButtonPart:
result.m_part = BP_PUSHBUTTON;
result.m_classicState = DFCS_BUTTONPUSH;
break;
case CheckboxPart:
result.m_part = BP_CHECKBOX;
result.m_classicState = DFCS_BUTTONCHECK;
break;
case RadioPart:
result.m_part = BP_RADIOBUTTON;
result.m_classicState = DFCS_BUTTONRADIO;
break;
case ListboxPart:
case MenulistPart:
case TextFieldPart:
case TextAreaPart:
result.m_part = ETS_NORMAL;
break;
}
result.m_state = determineState(o);
result.m_classicState |= determineClassicState(o);
return result;
}
bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o,
const RenderObject::PaintInfo& i,
const IntRect& r,
bool drawEdges)
{
if (o->style()->hasBorderRadius())
return false;
const ThemeData& themeData = getThemeData(o);
WebCore::ThemeHelperWin helper(i.context, r);
ChromiumBridge::paintTextField(helper.context(),
themeData.m_part,
themeData.m_state,
themeData.m_classicState,
helper.rect(),
o->style()->backgroundColor(),
true,
drawEdges);
return false;
}
int RenderThemeChromiumWin::menuListInternalPadding(RenderStyle* style, int paddingType) const
{
int padding = styledMenuListInternalPadding[paddingType];
const int barType = style->direction() == LTR ? RightPadding : LeftPadding;
if (paddingType == barType && style->appearance() != NoControlPart)
padding += ScrollbarTheme::nativeTheme()->scrollbarThickness();
return padding;
}
void RenderThemeChromiumWin::setFindInPageMode(bool enable) {
if (m_findInPageMode == enable)
return;
m_findInPageMode = enable;
theme()->platformColorsDidChange();
}
}