webengine/osswebengine/WebCore/rendering/RenderThemeWin.cpp
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * This file is part of the WebKit project.
       
     3  *
       
     4  * Copyright (C) 2006 Apple Computer, Inc.
       
     5  *
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Library General Public
       
     8  * License as published by the Free Software Foundation; either
       
     9  * version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This library is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Library General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Library General Public License
       
    17  * along with this library; see the file COPYING.LIB.  If not, write to
       
    18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    19  * Boston, MA 02110-1301, USA.
       
    20  *
       
    21  */
       
    22 
       
    23 #include "config.h"
       
    24 #include "RenderThemeWin.h"
       
    25 
       
    26 #include <cairo-win32.h>
       
    27 #include "Document.h"
       
    28 #include "GraphicsContext.h"
       
    29 
       
    30 /* 
       
    31  * The following constants are used to determine how a widget is drawn using
       
    32  * Windows' Theme API. For more information on theme parts and states see
       
    33  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/topics/partsandstates.asp
       
    34  */
       
    35 #define THEME_COLOR 204
       
    36 #define THEME_FONT  210
       
    37 
       
    38 // Generic state constants
       
    39 #define TS_NORMAL    1
       
    40 #define TS_HOVER     2
       
    41 #define TS_ACTIVE    3
       
    42 #define TS_DISABLED  4
       
    43 #define TS_FOCUSED   5
       
    44 
       
    45 // Button constants
       
    46 #define BP_BUTTON    1
       
    47 #define BP_RADIO     2
       
    48 #define BP_CHECKBOX  3
       
    49 
       
    50 // Textfield constants
       
    51 #define TFP_TEXTFIELD 1
       
    52 #define TFS_READONLY  6
       
    53 
       
    54 // Combobox constants
       
    55 #define CP_DROPDOWNBUTTON 1
       
    56 
       
    57 typedef HANDLE (WINAPI*openThemeDataPtr)(HWND hwnd, LPCWSTR pszClassList);
       
    58 typedef HRESULT (WINAPI*closeThemeDataPtr)(HANDLE hTheme);
       
    59 typedef HRESULT (WINAPI*drawThemeBackgroundPtr)(HANDLE hTheme, HDC hdc, int iPartId, 
       
    60                                           int iStateId, const RECT *pRect,
       
    61                                           const RECT* pClipRect);
       
    62 typedef HRESULT (WINAPI*drawThemeEdgePtr)(HANDLE hTheme, HDC hdc, int iPartId, 
       
    63                                           int iStateId, const RECT *pRect,
       
    64                                           unsigned uEdge, unsigned uFlags,
       
    65                                           const RECT* pClipRect);
       
    66 typedef HRESULT (WINAPI*getThemeContentRectPtr)(HANDLE hTheme, HDC hdc, int iPartId,
       
    67                                           int iStateId, const RECT* pRect,
       
    68                                           RECT* pContentRect);
       
    69 typedef HRESULT (WINAPI*getThemePartSizePtr)(HANDLE hTheme, HDC hdc, int iPartId,
       
    70                                        int iStateId, RECT* prc, int ts,
       
    71                                        SIZE* psz);
       
    72 typedef HRESULT (WINAPI*getThemeSysFontPtr)(HANDLE hTheme, int iFontId, OUT LOGFONT* pFont);
       
    73 typedef HRESULT (WINAPI*getThemeColorPtr)(HANDLE hTheme, HDC hdc, int iPartId,
       
    74                                    int iStateId, int iPropId, OUT COLORREF* pFont);
       
    75 
       
    76 static openThemeDataPtr openTheme = 0;
       
    77 static closeThemeDataPtr closeTheme = 0;
       
    78 static drawThemeBackgroundPtr drawThemeBG = 0;
       
    79 static drawThemeEdgePtr drawThemeEdge = 0;
       
    80 static getThemeContentRectPtr getThemeContentRect = 0;
       
    81 static getThemePartSizePtr getThemePartSize = 0;
       
    82 static getThemeSysFontPtr getThemeSysFont = 0;
       
    83 static getThemeColorPtr getThemeColor = 0;
       
    84 
       
    85 namespace WebCore {
       
    86 
       
    87 RenderTheme* theme()
       
    88 {
       
    89     static RenderThemeWin winTheme;
       
    90     return &winTheme;
       
    91 }
       
    92 
       
    93 RenderThemeWin::RenderThemeWin()
       
    94 :m_themeDLL(0), m_buttonTheme(0), m_textFieldTheme(0), m_menuListTheme(0)
       
    95 {
       
    96     m_themeDLL = ::LoadLibrary(L"uxtheme.dll");
       
    97     if (m_themeDLL) {
       
    98         openTheme = (openThemeDataPtr)GetProcAddress(m_themeDLL, "OpenThemeData");
       
    99         closeTheme = (closeThemeDataPtr)GetProcAddress(m_themeDLL, "CloseThemeData");
       
   100         drawThemeBG = (drawThemeBackgroundPtr)GetProcAddress(m_themeDLL, "DrawThemeBackground");
       
   101         drawThemeEdge = (drawThemeEdgePtr)GetProcAddress(m_themeDLL, "DrawThemeEdge");
       
   102         getThemeContentRect = (getThemeContentRectPtr)GetProcAddress(m_themeDLL, "GetThemeBackgroundContentRect");
       
   103         getThemePartSize = (getThemePartSizePtr)GetProcAddress(m_themeDLL, "GetThemePartSize");
       
   104         getThemeSysFont = (getThemeSysFontPtr)GetProcAddress(m_themeDLL, "GetThemeSysFont");
       
   105         getThemeColor = (getThemeColorPtr)GetProcAddress(m_themeDLL, "GetThemeColor");
       
   106     }
       
   107 }
       
   108 
       
   109 RenderThemeWin::~RenderThemeWin()
       
   110 {
       
   111     if (!m_themeDLL)
       
   112         return;
       
   113 
       
   114     close();
       
   115 
       
   116     ::FreeLibrary(m_themeDLL);
       
   117 }
       
   118 
       
   119 void RenderThemeWin::close()
       
   120 {
       
   121     // This method will need to be called when the OS theme changes to flush our cached themes.
       
   122     if (m_buttonTheme)
       
   123         closeTheme(m_buttonTheme);
       
   124     if (m_textFieldTheme)
       
   125         closeTheme(m_textFieldTheme);
       
   126     if (m_menuListTheme)
       
   127         closeTheme(m_menuListTheme);
       
   128     m_buttonTheme = m_textFieldTheme = m_menuListTheme = 0;
       
   129 }
       
   130 
       
   131 Color RenderThemeWin::platformActiveSelectionBackgroundColor() const
       
   132 {
       
   133     COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
       
   134     return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
       
   135 }
       
   136 
       
   137 Color RenderThemeWin::platformInactiveSelectionBackgroundColor() const
       
   138 {
       
   139     COLORREF color = GetSysColor(COLOR_GRAYTEXT);
       
   140     return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
       
   141 }
       
   142 
       
   143 Color RenderThemeWin::platformActiveSelectionForegroundColor() const
       
   144 {
       
   145     COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
       
   146     return Color(GetRValue(color), GetGValue(color), GetBValue(color), 255);
       
   147 }
       
   148 
       
   149 Color RenderThemeWin::platformInactiveSelectionForegroundColor() const
       
   150 {
       
   151     return Color::white;
       
   152 }
       
   153 
       
   154 bool RenderThemeWin::supportsFocus(EAppearance appearance)
       
   155 {
       
   156     switch (appearance) {
       
   157         case PushButtonAppearance:
       
   158         case ButtonAppearance:
       
   159         case TextFieldAppearance:
       
   160         case TextAreaAppearance:
       
   161             return true;
       
   162         default:
       
   163             return false;
       
   164     }
       
   165 
       
   166     return false;
       
   167 }
       
   168 
       
   169 unsigned RenderThemeWin::determineState(RenderObject* o)
       
   170 {
       
   171     unsigned result = TS_NORMAL;
       
   172     if (!isEnabled(o))
       
   173         result = TS_DISABLED;
       
   174     else if (isReadOnlyControl(o))
       
   175         result = TFS_READONLY; // Readonly is supported on textfields.
       
   176     else if (supportsFocus(o->style()->appearance()) && isFocused(o))
       
   177         result = TS_FOCUSED;
       
   178     else if (isPressed(o)) // Active overrides hover.
       
   179         result = TS_ACTIVE;
       
   180     else if (isHovered(o))
       
   181         result = TS_HOVER;
       
   182     if (isChecked(o))
       
   183         result += 4; // 4 unchecked states, 4 checked states.
       
   184     return result;
       
   185 }
       
   186 
       
   187 unsigned RenderThemeWin::determineClassicState(RenderObject* o)
       
   188 {
       
   189     unsigned result = 0;
       
   190     if (!isEnabled(o) || isReadOnlyControl(o))
       
   191         result = DFCS_INACTIVE;
       
   192     else if (isPressed(o)) // Active supersedes hover
       
   193         result = DFCS_PUSHED;
       
   194     else if (isHovered(o))
       
   195         result = DFCS_HOT;
       
   196     if (isChecked(o))
       
   197         result |= DFCS_CHECKED;
       
   198     return result;
       
   199 }
       
   200 
       
   201 ThemeData RenderThemeWin::getThemeData(RenderObject* o)
       
   202 {
       
   203     ThemeData result;
       
   204     switch (o->style()->appearance()) {
       
   205         case PushButtonAppearance:
       
   206         case ButtonAppearance:
       
   207             result.m_part = BP_BUTTON;
       
   208             result.m_classicState = DFCS_BUTTONPUSH;
       
   209             break;
       
   210         case CheckboxAppearance:
       
   211             result.m_part = BP_CHECKBOX;
       
   212             result.m_classicState = DFCS_BUTTONCHECK;
       
   213             break;
       
   214         case RadioAppearance:
       
   215             result.m_part = BP_RADIO;
       
   216             result.m_classicState = DFCS_BUTTONRADIO;
       
   217             break;
       
   218         case ListboxAppearance:
       
   219         case MenulistAppearance:
       
   220         case TextFieldAppearance:
       
   221         case TextAreaAppearance:
       
   222             result.m_part = TFP_TEXTFIELD;
       
   223             break;
       
   224     }
       
   225 
       
   226     result.m_state = determineState(o);
       
   227     result.m_classicState |= determineClassicState(o);
       
   228 
       
   229     return result;
       
   230 }
       
   231 
       
   232 // May need to add stuff to these later, so keep the graphics context retrieval/release in some helpers.
       
   233 static HDC prepareForDrawing(GraphicsContext* g)
       
   234 {
       
   235     return g->getWindowsContext();
       
   236 }
       
   237  
       
   238 static void doneDrawing(GraphicsContext* g, HDC hdc)
       
   239 {
       
   240     g->releaseWindowsContext(hdc);
       
   241 }
       
   242 
       
   243 bool RenderThemeWin::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
       
   244 {
       
   245     // Get the correct theme data for a button
       
   246     ThemeData themeData = getThemeData(o);
       
   247 
       
   248     // Now paint the button.
       
   249     HDC hdc = prepareForDrawing(i.context);  
       
   250     RECT widgetRect = r;
       
   251     if (m_themeDLL && !m_buttonTheme)
       
   252         m_buttonTheme = openTheme(0, L"Button");
       
   253     if (m_buttonTheme && drawThemeBG) {
       
   254         drawThemeBG(m_buttonTheme, hdc, themeData.m_part, themeData.m_state, &widgetRect, NULL);
       
   255     } else {
       
   256         if ((themeData.m_part == BP_BUTTON) && isFocused(o)) {
       
   257             // Draw black focus rect around button outer edge
       
   258             HBRUSH brush = GetSysColorBrush(COLOR_3DDKSHADOW);
       
   259             if (brush) {
       
   260                 FrameRect(hdc, &widgetRect, brush);
       
   261                 InflateRect(&widgetRect, -1, -1);
       
   262             }
       
   263         }
       
   264         DrawFrameControl(hdc, &widgetRect, DFC_BUTTON, themeData.m_classicState);
       
   265         if ((themeData.m_part != BP_BUTTON) && isFocused(o)) {
       
   266             DrawFocusRect(hdc, &widgetRect);
       
   267         }
       
   268     }
       
   269     doneDrawing(i.context, hdc);
       
   270 
       
   271     return false;
       
   272 }
       
   273 
       
   274 void RenderThemeWin::setCheckboxSize(RenderStyle* style) const
       
   275 {
       
   276     // If the width and height are both specified, then we have nothing to do.
       
   277     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
       
   278         return;
       
   279 
       
   280     // FIXME:  A hard-coded size of 13 is used.  This is wrong but necessary for now.  It matches Firefox.
       
   281     // At different DPI settings on Windows, querying the theme gives you a larger size that accounts for
       
   282     // the higher DPI.  Until our entire engine honors a DPI setting other than 96, we can't rely on the theme's
       
   283     // metrics.
       
   284     if (style->width().isIntrinsicOrAuto())
       
   285         style->setWidth(Length(13, Fixed));
       
   286     if (style->height().isAuto())
       
   287         style->setHeight(Length(13, Fixed));
       
   288 }
       
   289 
       
   290 bool RenderThemeWin::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
       
   291 {
       
   292     // Get the correct theme data for a textfield
       
   293     ThemeData themeData = getThemeData(o);
       
   294 
       
   295     // Now paint the text field.
       
   296     HDC hdc = prepareForDrawing(i.context);
       
   297     RECT widgetRect = r;
       
   298     if (m_themeDLL && !m_textFieldTheme)
       
   299         m_textFieldTheme = openTheme(0, L"Edit");
       
   300     if (m_textFieldTheme && drawThemeBG) {
       
   301         drawThemeBG(m_textFieldTheme, hdc, themeData.m_part, themeData.m_state, &widgetRect, NULL);
       
   302     } else {
       
   303         DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
       
   304         FillRect(hdc, &widgetRect, reinterpret_cast<HBRUSH>(((themeData.m_classicState & DFCS_INACTIVE) ? COLOR_BTNFACE : COLOR_WINDOW) + 1));
       
   305     }
       
   306     doneDrawing(i.context, hdc);
       
   307 
       
   308     return false;
       
   309 }
       
   310 
       
   311 void RenderThemeWin::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
       
   312 {
       
   313     // Height is locked to auto.
       
   314     style->setHeight(Length(Auto));
       
   315 
       
   316     // White-space is locked to pre
       
   317     style->setWhiteSpace(PRE);
       
   318 
       
   319     // Add in the padding that we'd like to use.
       
   320     const int buttonWidth = GetSystemMetrics(SM_CXVSCROLL);
       
   321     style->setPaddingLeft(Length(2, Fixed));
       
   322     style->setPaddingRight(Length(buttonWidth + 2, Fixed));
       
   323     style->setPaddingTop(Length(1, Fixed));
       
   324     style->setPaddingBottom(Length(1, Fixed));
       
   325 }
       
   326 
       
   327 bool RenderThemeWin::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
       
   328 {
       
   329     // FIXME: All these inflate() calls are bogus, causing painting problems,
       
   330     // as well as sizing wackiness in Classic mode
       
   331     IntRect editRect(r);
       
   332     paintTextField(o, i, editRect);
       
   333 
       
   334     const int buttonWidth = GetSystemMetrics(SM_CXVSCROLL);
       
   335     IntRect buttonRect(r.right() - buttonWidth - 1, r.y(), buttonWidth, r.height());
       
   336     buttonRect.inflateY(-1);
       
   337     paintMenuListButton(o, i, buttonRect);
       
   338 
       
   339     return false;
       
   340 }
       
   341 
       
   342 bool RenderThemeWin::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
       
   343 {
       
   344     HDC hdc = prepareForDrawing(i.context);
       
   345     RECT widgetRect = r;
       
   346     if (m_themeDLL && !m_menuListTheme)
       
   347         m_menuListTheme = openTheme(0, L"Combobox");
       
   348     if (m_menuListTheme && drawThemeBG)
       
   349         drawThemeBG(m_menuListTheme, hdc, CP_DROPDOWNBUTTON, determineState(o), &widgetRect, NULL);
       
   350     else
       
   351         DrawFrameControl(hdc, &widgetRect, DFC_SCROLL, DFCS_SCROLLCOMBOBOX | determineClassicState(o));
       
   352     doneDrawing(i.context, hdc);
       
   353 
       
   354     return false;
       
   355 }
       
   356 
       
   357 }