--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/rendering/RenderThemeWin.cpp Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,357 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "RenderThemeWin.h"
+
+#include <cairo-win32.h>
+#include "Document.h"
+#include "GraphicsContext.h"
+
+/*
+ * The following constants are used to determine how a widget is drawn using
+ * Windows' Theme API. For more information on theme parts and states see
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/topics/partsandstates.asp
+ */
+#define THEME_COLOR 204
+#define THEME_FONT 210
+
+// Generic state constants
+#define TS_NORMAL 1
+#define TS_HOVER 2
+#define TS_ACTIVE 3
+#define TS_DISABLED 4
+#define TS_FOCUSED 5
+
+// Button constants
+#define BP_BUTTON 1
+#define BP_RADIO 2
+#define BP_CHECKBOX 3
+
+// Textfield constants
+#define TFP_TEXTFIELD 1
+#define TFS_READONLY 6
+
+// Combobox constants
+#define CP_DROPDOWNBUTTON 1
+
+typedef HANDLE (WINAPI*openThemeDataPtr)(HWND hwnd, LPCWSTR pszClassList);
+typedef HRESULT (WINAPI*closeThemeDataPtr)(HANDLE hTheme);
+typedef HRESULT (WINAPI*drawThemeBackgroundPtr)(HANDLE hTheme, HDC hdc, int iPartId,
+ int iStateId, const RECT *pRect,
+ const RECT* pClipRect);
+typedef HRESULT (WINAPI*drawThemeEdgePtr)(HANDLE hTheme, HDC hdc, int iPartId,
+ int iStateId, const RECT *pRect,
+ unsigned uEdge, unsigned uFlags,
+ const RECT* pClipRect);
+typedef HRESULT (WINAPI*getThemeContentRectPtr)(HANDLE hTheme, HDC hdc, int iPartId,
+ int iStateId, const RECT* pRect,
+ RECT* pContentRect);
+typedef HRESULT (WINAPI*getThemePartSizePtr)(HANDLE hTheme, HDC hdc, int iPartId,
+ int iStateId, RECT* prc, int ts,
+ SIZE* psz);
+typedef HRESULT (WINAPI*getThemeSysFontPtr)(HANDLE hTheme, int iFontId, OUT LOGFONT* pFont);
+typedef HRESULT (WINAPI*getThemeColorPtr)(HANDLE hTheme, HDC hdc, int iPartId,
+ int iStateId, int iPropId, OUT COLORREF* pFont);
+
+static openThemeDataPtr openTheme = 0;
+static closeThemeDataPtr closeTheme = 0;
+static drawThemeBackgroundPtr drawThemeBG = 0;
+static drawThemeEdgePtr drawThemeEdge = 0;
+static getThemeContentRectPtr getThemeContentRect = 0;
+static getThemePartSizePtr getThemePartSize = 0;
+static getThemeSysFontPtr getThemeSysFont = 0;
+static getThemeColorPtr getThemeColor = 0;
+
+namespace WebCore {
+
+RenderTheme* theme()
+{
+ static RenderThemeWin winTheme;
+ return &winTheme;
+}
+
+RenderThemeWin::RenderThemeWin()
+:m_themeDLL(0), m_buttonTheme(0), m_textFieldTheme(0), m_menuListTheme(0)
+{
+ m_themeDLL = ::LoadLibrary(L"uxtheme.dll");
+ if (m_themeDLL) {
+ openTheme = (openThemeDataPtr)GetProcAddress(m_themeDLL, "OpenThemeData");
+ closeTheme = (closeThemeDataPtr)GetProcAddress(m_themeDLL, "CloseThemeData");
+ drawThemeBG = (drawThemeBackgroundPtr)GetProcAddress(m_themeDLL, "DrawThemeBackground");
+ drawThemeEdge = (drawThemeEdgePtr)GetProcAddress(m_themeDLL, "DrawThemeEdge");
+ getThemeContentRect = (getThemeContentRectPtr)GetProcAddress(m_themeDLL, "GetThemeBackgroundContentRect");
+ getThemePartSize = (getThemePartSizePtr)GetProcAddress(m_themeDLL, "GetThemePartSize");
+ getThemeSysFont = (getThemeSysFontPtr)GetProcAddress(m_themeDLL, "GetThemeSysFont");
+ getThemeColor = (getThemeColorPtr)GetProcAddress(m_themeDLL, "GetThemeColor");
+ }
+}
+
+RenderThemeWin::~RenderThemeWin()
+{
+ if (!m_themeDLL)
+ return;
+
+ close();
+
+ ::FreeLibrary(m_themeDLL);
+}
+
+void RenderThemeWin::close()
+{
+ // This method will need to be called when the OS theme changes to flush our cached themes.
+ if (m_buttonTheme)
+ closeTheme(m_buttonTheme);
+ if (m_textFieldTheme)
+ closeTheme(m_textFieldTheme);
+ if (m_menuListTheme)
+ closeTheme(m_menuListTheme);
+ m_buttonTheme = m_textFieldTheme = m_menuListTheme = 0;
+}
+
+Color RenderThemeWin::platformActiveSelectionBackgroundColor() const
+{
+ COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
+ return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
+}
+
+Color RenderThemeWin::platformInactiveSelectionBackgroundColor() const
+{
+ COLORREF color = GetSysColor(COLOR_GRAYTEXT);
+ return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
+}
+
+Color RenderThemeWin::platformActiveSelectionForegroundColor() const
+{
+ COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
+ return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
+}
+
+Color RenderThemeWin::platformInactiveSelectionForegroundColor() const
+{
+ return Color::white;
+}
+
+bool RenderThemeWin::supportsFocus(EAppearance appearance)
+{
+ switch (appearance) {
+ case PushButtonAppearance:
+ case ButtonAppearance:
+ case TextFieldAppearance:
+ case TextAreaAppearance:
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+unsigned RenderThemeWin::determineState(RenderObject* o)
+{
+ unsigned result = TS_NORMAL;
+ if (!isEnabled(o))
+ result = TS_DISABLED;
+ else if (isReadOnlyControl(o))
+ result = TFS_READONLY; // Readonly is supported on textfields.
+ else if (supportsFocus(o->style()->appearance()) && isFocused(o))
+ result = TS_FOCUSED;
+ else if (isPressed(o)) // Active overrides hover.
+ result = TS_ACTIVE;
+ else if (isHovered(o))
+ result = TS_HOVER;
+ if (isChecked(o))
+ result += 4; // 4 unchecked states, 4 checked states.
+ return result;
+}
+
+unsigned RenderThemeWin::determineClassicState(RenderObject* o)
+{
+ unsigned result = 0;
+ if (!isEnabled(o) || isReadOnlyControl(o))
+ result = DFCS_INACTIVE;
+ else if (isPressed(o)) // Active supersedes hover
+ result = DFCS_PUSHED;
+ else if (isHovered(o))
+ result = DFCS_HOT;
+ if (isChecked(o))
+ result |= DFCS_CHECKED;
+ return result;
+}
+
+ThemeData RenderThemeWin::getThemeData(RenderObject* o)
+{
+ ThemeData result;
+ switch (o->style()->appearance()) {
+ case PushButtonAppearance:
+ case ButtonAppearance:
+ result.m_part = BP_BUTTON;
+ result.m_classicState = DFCS_BUTTONPUSH;
+ break;
+ case CheckboxAppearance:
+ result.m_part = BP_CHECKBOX;
+ result.m_classicState = DFCS_BUTTONCHECK;
+ break;
+ case RadioAppearance:
+ result.m_part = BP_RADIO;
+ result.m_classicState = DFCS_BUTTONRADIO;
+ break;
+ case ListboxAppearance:
+ case MenulistAppearance:
+ case TextFieldAppearance:
+ case TextAreaAppearance:
+ result.m_part = TFP_TEXTFIELD;
+ break;
+ }
+
+ result.m_state = determineState(o);
+ result.m_classicState |= determineClassicState(o);
+
+ return result;
+}
+
+// May need to add stuff to these later, so keep the graphics context retrieval/release in some helpers.
+static HDC prepareForDrawing(GraphicsContext* g)
+{
+ return g->getWindowsContext();
+}
+
+static void doneDrawing(GraphicsContext* g, HDC hdc)
+{
+ g->releaseWindowsContext(hdc);
+}
+
+bool RenderThemeWin::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ // Get the correct theme data for a button
+ ThemeData themeData = getThemeData(o);
+
+ // Now paint the button.
+ HDC hdc = prepareForDrawing(i.context);
+ RECT widgetRect = r;
+ if (m_themeDLL && !m_buttonTheme)
+ m_buttonTheme = openTheme(0, L"Button");
+ if (m_buttonTheme && drawThemeBG) {
+ drawThemeBG(m_buttonTheme, hdc, themeData.m_part, themeData.m_state, &widgetRect, NULL);
+ } else {
+ if ((themeData.m_part == BP_BUTTON) && isFocused(o)) {
+ // Draw black focus rect around button outer edge
+ HBRUSH brush = GetSysColorBrush(COLOR_3DDKSHADOW);
+ if (brush) {
+ FrameRect(hdc, &widgetRect, brush);
+ InflateRect(&widgetRect, -1, -1);
+ }
+ }
+ DrawFrameControl(hdc, &widgetRect, DFC_BUTTON, themeData.m_classicState);
+ if ((themeData.m_part != BP_BUTTON) && isFocused(o)) {
+ DrawFocusRect(hdc, &widgetRect);
+ }
+ }
+ doneDrawing(i.context, hdc);
+
+ return false;
+}
+
+void RenderThemeWin::setCheckboxSize(RenderStyle* style) const
+{
+ // If the width and height are both specified, then we have nothing to do.
+ if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
+ return;
+
+ // FIXME: A hard-coded size of 13 is used. This is wrong but necessary for now. It matches Firefox.
+ // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for
+ // the higher DPI. Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's
+ // metrics.
+ if (style->width().isIntrinsicOrAuto())
+ style->setWidth(Length(13, Fixed));
+ if (style->height().isAuto())
+ style->setHeight(Length(13, Fixed));
+}
+
+bool RenderThemeWin::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ // Get the correct theme data for a textfield
+ ThemeData themeData = getThemeData(o);
+
+ // Now paint the text field.
+ HDC hdc = prepareForDrawing(i.context);
+ RECT widgetRect = r;
+ if (m_themeDLL && !m_textFieldTheme)
+ m_textFieldTheme = openTheme(0, L"Edit");
+ if (m_textFieldTheme && drawThemeBG) {
+ drawThemeBG(m_textFieldTheme, hdc, themeData.m_part, themeData.m_state, &widgetRect, NULL);
+ } else {
+ DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+ FillRect(hdc, &widgetRect, reinterpret_cast<HBRUSH>(((themeData.m_classicState & DFCS_INACTIVE) ? COLOR_BTNFACE : COLOR_WINDOW) + 1));
+ }
+ doneDrawing(i.context, hdc);
+
+ return false;
+}
+
+void RenderThemeWin::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ // Height is locked to auto.
+ style->setHeight(Length(Auto));
+
+ // White-space is locked to pre
+ style->setWhiteSpace(PRE);
+
+ // Add in the padding that we'd like to use.
+ const int buttonWidth = GetSystemMetrics(SM_CXVSCROLL);
+ style->setPaddingLeft(Length(2, Fixed));
+ style->setPaddingRight(Length(buttonWidth + 2, Fixed));
+ style->setPaddingTop(Length(1, Fixed));
+ style->setPaddingBottom(Length(1, Fixed));
+}
+
+bool RenderThemeWin::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ // FIXME: All these inflate() calls are bogus, causing painting problems,
+ // as well as sizing wackiness in Classic mode
+ IntRect editRect(r);
+ paintTextField(o, i, editRect);
+
+ const int buttonWidth = GetSystemMetrics(SM_CXVSCROLL);
+ IntRect buttonRect(r.right() - buttonWidth - 1, r.y(), buttonWidth, r.height());
+ buttonRect.inflateY(-1);
+ paintMenuListButton(o, i, buttonRect);
+
+ return false;
+}
+
+bool RenderThemeWin::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+{
+ HDC hdc = prepareForDrawing(i.context);
+ RECT widgetRect = r;
+ if (m_themeDLL && !m_menuListTheme)
+ m_menuListTheme = openTheme(0, L"Combobox");
+ if (m_menuListTheme && drawThemeBG)
+ drawThemeBG(m_menuListTheme, hdc, CP_DROPDOWNBUTTON, determineState(o), &widgetRect, NULL);
+ else
+ DrawFrameControl(hdc, &widgetRect, DFC_SCROLL, DFCS_SCROLLCOMBOBOX | determineClassicState(o));
+ doneDrawing(i.context, hdc);
+
+ return false;
+}
+
+}