Home | History | Annotate | Download | only in gtk
      1 /*
      2  * Copyright (C) 2007 Apple Inc.
      3  * Copyright (C) 2007 Alp Toker <alp (at) atoker.com>
      4  * Copyright (C) 2008 Collabora Ltd.
      5  * Copyright (C) 2009 Kenneth Rohde Christiansen
      6  * Copyright (C) 2010 Igalia S.L.
      7  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Library General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Library General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Library General Public License
     19  * along with this library; see the file COPYING.LIB.  If not, write to
     20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     21  * Boston, MA 02110-1301, USA.
     22  *
     23  */
     24 
     25 #include "config.h"
     26 #include "RenderThemeGtk.h"
     27 
     28 #ifndef GTK_API_VERSION_2
     29 
     30 #include "CSSValueKeywords.h"
     31 #include "GraphicsContext.h"
     32 #include "GtkVersioning.h"
     33 #include "HTMLNames.h"
     34 #include "MediaControlElements.h"
     35 #include "Page.h"
     36 #include "PaintInfo.h"
     37 #include "PlatformContextCairo.h"
     38 #include "RenderObject.h"
     39 #include "TextDirection.h"
     40 #include "UserAgentStyleSheets.h"
     41 #include <cmath>
     42 #include <gdk/gdk.h>
     43 #include <gtk/gtk.h>
     44 
     45 namespace WebCore {
     46 
     47 // This is the default value defined by GTK+, where it was defined as MIN_ARROW_SIZE in gtkarrow.c.
     48 static const int minArrowSize = 15;
     49 // This is the default value defined by GTK+, where it was defined as MIN_ARROW_WIDTH in gtkspinbutton.c.
     50 static const int minSpinButtonArrowSize = 6;
     51 
     52 typedef HashMap<GType, GRefPtr<GtkStyleContext> > StyleContextMap;
     53 static StyleContextMap& styleContextMap();
     54 
     55 static void gtkStyleChangedCallback(GObject*, GParamSpec*)
     56 {
     57     StyleContextMap::const_iterator end = styleContextMap().end();
     58     for (StyleContextMap::const_iterator iter = styleContextMap().begin(); iter != end; ++iter)
     59         gtk_style_context_invalidate(iter->second.get());
     60 
     61     Page::scheduleForcedStyleRecalcForAllPages();
     62 }
     63 
     64 static StyleContextMap& styleContextMap()
     65 {
     66     DEFINE_STATIC_LOCAL(StyleContextMap, map, ());
     67 
     68     static bool initialized = false;
     69     if (!initialized) {
     70         GtkSettings* settings = gtk_settings_get_default();
     71         g_signal_connect(settings, "notify::gtk-theme-name", G_CALLBACK(gtkStyleChangedCallback), 0);
     72         g_signal_connect(settings, "notify::gtk-color-scheme", G_CALLBACK(gtkStyleChangedCallback), 0);
     73         initialized = true;
     74     }
     75     return map;
     76 }
     77 
     78 static GtkStyleContext* getStyleContext(GType widgetType)
     79 {
     80     std::pair<StyleContextMap::iterator, bool> result = styleContextMap().add(widgetType, 0);
     81     if (!result.second)
     82         return result.first->second.get();
     83 
     84     GtkWidgetPath* path = gtk_widget_path_new();
     85     gtk_widget_path_append_type(path, widgetType);
     86 
     87     GRefPtr<GtkStyleContext> context = adoptGRef(gtk_style_context_new());
     88     gtk_style_context_set_path(context.get(), path);
     89     gtk_widget_path_free(path);
     90 
     91     result.first->second = context;
     92     return context.get();
     93 }
     94 
     95 GtkStyleContext* RenderThemeGtk::gtkScrollbarStyle()
     96 {
     97     return getStyleContext(GTK_TYPE_SCROLLBAR);
     98 }
     99 
    100 // This is not a static method, because we want to avoid having GTK+ headers in RenderThemeGtk.h.
    101 extern GtkTextDirection gtkTextDirection(TextDirection);
    102 
    103 void RenderThemeGtk::platformInit()
    104 {
    105 }
    106 
    107 RenderThemeGtk::~RenderThemeGtk()
    108 {
    109 }
    110 
    111 #if ENABLE(VIDEO)
    112 void RenderThemeGtk::initMediaColors()
    113 {
    114     GdkRGBA color;
    115     GtkStyleContext* containerContext = getStyleContext(GTK_TYPE_CONTAINER);
    116 
    117     gtk_style_context_get_background_color(containerContext, GTK_STATE_FLAG_NORMAL, &color);
    118     m_panelColor = color;
    119     gtk_style_context_get_background_color(containerContext, GTK_STATE_FLAG_ACTIVE, &color);
    120     m_sliderColor = color;
    121     gtk_style_context_get_background_color(containerContext, GTK_STATE_FLAG_SELECTED, &color);
    122     m_sliderThumbColor = color;
    123 }
    124 #endif
    125 
    126 static void adjustRectForFocus(GtkStyleContext* context, IntRect& rect)
    127 {
    128     gint focusWidth, focusPad;
    129     gtk_style_context_get_style(context,
    130                                 "focus-line-width", &focusWidth,
    131                                 "focus-padding", &focusPad, NULL);
    132     rect.inflate(focusWidth + focusPad);
    133 }
    134 
    135 void RenderThemeGtk::adjustRepaintRect(const RenderObject* renderObject, IntRect& rect)
    136 {
    137     GtkStyleContext* context = 0;
    138     bool checkInteriorFocus = false;
    139     ControlPart part = renderObject->style()->appearance();
    140     switch (part) {
    141     case CheckboxPart:
    142     case RadioPart:
    143         context = getStyleContext(part == CheckboxPart ? GTK_TYPE_CHECK_BUTTON : GTK_TYPE_RADIO_BUTTON);
    144 
    145         gint indicatorSpacing;
    146         gtk_style_context_get_style(context, "indicator-spacing", &indicatorSpacing, NULL);
    147         rect.inflate(indicatorSpacing);
    148 
    149         return;
    150     case SliderVerticalPart:
    151     case SliderHorizontalPart:
    152         context = getStyleContext(part == SliderThumbHorizontalPart ?  GTK_TYPE_HSCALE : GTK_TYPE_VSCALE);
    153         break;
    154     case ButtonPart:
    155     case MenulistButtonPart:
    156     case MenulistPart:
    157         context = getStyleContext(GTK_TYPE_BUTTON);
    158         checkInteriorFocus = true;
    159         break;
    160     case TextFieldPart:
    161     case TextAreaPart:
    162         context = getStyleContext(GTK_TYPE_ENTRY);
    163         checkInteriorFocus = true;
    164         break;
    165     default:
    166         return;
    167     }
    168 
    169     ASSERT(context);
    170     if (checkInteriorFocus) {
    171         gboolean interiorFocus;
    172         gtk_style_context_get_style(context, "interior-focus", &interiorFocus, NULL);
    173         if (interiorFocus)
    174             return;
    175     }
    176     adjustRectForFocus(context, rect);
    177 }
    178 
    179 static void setToggleSize(GtkStyleContext* context, RenderStyle* style)
    180 {
    181     // The width and height are both specified, so we shouldn't change them.
    182     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
    183         return;
    184 
    185     // Other ports hard-code this to 13 which is also the default value defined by GTK+.
    186     // GTK+ users tend to demand the native look.
    187     // It could be made a configuration option values other than 13 actually break site compatibility.
    188     gint indicatorSize;
    189     gtk_style_context_get_style(context, "indicator-size", &indicatorSize, NULL);
    190 
    191     if (style->width().isIntrinsicOrAuto())
    192         style->setWidth(Length(indicatorSize, Fixed));
    193 
    194     if (style->height().isAuto())
    195         style->setHeight(Length(indicatorSize, Fixed));
    196 }
    197 
    198 static void paintToggle(const RenderThemeGtk* theme, GType widgetType, RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
    199 {
    200     GtkStyleContext* context = getStyleContext(widgetType);
    201     gtk_style_context_save(context);
    202 
    203     gtk_style_context_set_direction(context, static_cast<GtkTextDirection>(gtkTextDirection(renderObject->style()->direction())));
    204     gtk_style_context_add_class(context, widgetType == GTK_TYPE_CHECK_BUTTON ? GTK_STYLE_CLASS_CHECK : GTK_STYLE_CLASS_RADIO);
    205 
    206     guint flags = 0;
    207     if (!theme->isEnabled(renderObject) || theme->isReadOnlyControl(renderObject))
    208         flags |= GTK_STATE_FLAG_INSENSITIVE;
    209     else if (theme->isHovered(renderObject))
    210         flags |= GTK_STATE_FLAG_PRELIGHT;
    211     if (theme->isIndeterminate(renderObject))
    212         flags |= GTK_STATE_FLAG_INCONSISTENT;
    213     else if (theme->isChecked(renderObject))
    214         flags |= GTK_STATE_FLAG_ACTIVE;
    215     if (theme->isPressed(renderObject))
    216         flags |= GTK_STATE_FLAG_SELECTED;
    217     gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags));
    218 
    219     if (widgetType == GTK_TYPE_CHECK_BUTTON)
    220         gtk_render_check(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
    221     else
    222         gtk_render_option(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
    223 
    224     if (theme->isFocused(renderObject)) {
    225         IntRect indicatorRect(rect);
    226         gint indicatorSpacing;
    227         gtk_style_context_get_style(context, "indicator-spacing", &indicatorSpacing, NULL);
    228         indicatorRect.inflate(indicatorSpacing);
    229         gtk_render_focus(context, paintInfo.context->platformContext()->cr(), indicatorRect.x(), indicatorRect.y(),
    230                          indicatorRect.width(), indicatorRect.height());
    231     }
    232 
    233     gtk_style_context_restore(context);
    234 }
    235 
    236 void RenderThemeGtk::setCheckboxSize(RenderStyle* style) const
    237 {
    238     setToggleSize(getStyleContext(GTK_TYPE_CHECK_BUTTON), style);
    239 }
    240 
    241 bool RenderThemeGtk::paintCheckbox(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
    242 {
    243     paintToggle(this, GTK_TYPE_CHECK_BUTTON, renderObject, paintInfo, rect);
    244     return false;
    245 }
    246 
    247 void RenderThemeGtk::setRadioSize(RenderStyle* style) const
    248 {
    249     setToggleSize(getStyleContext(GTK_TYPE_RADIO_BUTTON), style);
    250 }
    251 
    252 bool RenderThemeGtk::paintRadio(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
    253 {
    254     paintToggle(this, GTK_TYPE_RADIO_BUTTON, renderObject, paintInfo, rect);
    255     return false;
    256 }
    257 
    258 static void renderButton(RenderTheme* theme, GtkStyleContext* context, RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
    259 {
    260     IntRect buttonRect(rect);
    261 
    262     guint flags = 0;
    263     if (!theme->isEnabled(renderObject) || theme->isReadOnlyControl(renderObject))
    264         flags |= GTK_STATE_FLAG_INSENSITIVE;
    265     else if (theme->isHovered(renderObject))
    266         flags |= GTK_STATE_FLAG_PRELIGHT;
    267     if (theme->isPressed(renderObject))
    268         flags |= GTK_STATE_FLAG_ACTIVE;
    269     gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags));
    270 
    271     if (theme->isDefault(renderObject)) {
    272         GtkBorder* borderPtr = 0;
    273         GtkBorder border = { 1, 1, 1, 1 };
    274 
    275         gtk_style_context_get_style(context, "default-border", &borderPtr, NULL);
    276         if (borderPtr) {
    277             border = *borderPtr;
    278             gtk_border_free(borderPtr);
    279         }
    280 
    281         buttonRect.move(border.left, border.top);
    282         buttonRect.setWidth(buttonRect.width() - (border.left + border.right));
    283         buttonRect.setHeight(buttonRect.height() - (border.top + border.bottom));
    284 
    285         gtk_style_context_add_class(context, GTK_STYLE_CLASS_DEFAULT);
    286     }
    287 
    288     gtk_render_background(context, paintInfo.context->platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
    289     gtk_render_frame(context, paintInfo.context->platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
    290 
    291     if (theme->isFocused(renderObject)) {
    292         gint focusWidth, focusPad;
    293         gboolean displaceFocus, interiorFocus;
    294         gtk_style_context_get_style(context,
    295                                     "focus-line-width", &focusWidth,
    296                                     "focus-padding", &focusPad,
    297                                     "interior-focus", &interiorFocus,
    298                                     "displace-focus", &displaceFocus,
    299                                     NULL);
    300 
    301         if (interiorFocus) {
    302             GtkBorder borderWidth;
    303             gtk_style_context_get_border(context, static_cast<GtkStateFlags>(flags), &borderWidth);
    304 
    305             buttonRect = IntRect(buttonRect.x() + borderWidth.left + focusPad, buttonRect.y() + borderWidth.top + focusPad,
    306                                  buttonRect.width() - (2 * focusPad + borderWidth.left + borderWidth.right),
    307                                  buttonRect.height() - (2 * focusPad + borderWidth.top + borderWidth.bottom));
    308         } else
    309             buttonRect.inflate(focusWidth + focusPad);
    310 
    311         if (displaceFocus && theme->isPressed(renderObject)) {
    312             gint childDisplacementX;
    313             gint childDisplacementY;
    314             gtk_style_context_get_style(context,
    315                                         "child-displacement-x", &childDisplacementX,
    316                                         "child-displacement-y", &childDisplacementY,
    317                                         NULL);
    318             buttonRect.move(childDisplacementX, childDisplacementY);
    319         }
    320 
    321         gtk_render_focus(context, paintInfo.context->platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
    322     }
    323 }
    324 bool RenderThemeGtk::paintButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
    325 {
    326     GtkStyleContext* context = getStyleContext(GTK_TYPE_BUTTON);
    327     gtk_style_context_save(context);
    328 
    329     gtk_style_context_set_direction(context, static_cast<GtkTextDirection>(gtkTextDirection(renderObject->style()->direction())));
    330     gtk_style_context_add_class(context, GTK_STYLE_CLASS_BUTTON);
    331 
    332     renderButton(this, context, renderObject, paintInfo, rect);
    333 
    334     gtk_style_context_restore(context);
    335 
    336     return false;
    337 }
    338 
    339 static void getComboBoxMetrics(RenderStyle* style, GtkBorder& border, int& focus, int& separator)
    340 {
    341     // If this menu list button isn't drawn using the native theme, we
    342     // don't add any extra padding beyond what WebCore already uses.
    343     if (style->appearance() == NoControlPart)
    344         return;
    345 
    346     GtkStyleContext* context = getStyleContext(GTK_TYPE_BUTTON);
    347     gtk_style_context_save(context);
    348 
    349     gtk_style_context_add_class(context, GTK_STYLE_CLASS_BUTTON);
    350     gtk_style_context_set_direction(context, static_cast<GtkTextDirection>(gtkTextDirection(style->direction())));
    351 
    352     gtk_style_context_get_border(context, static_cast<GtkStateFlags>(0), &border);
    353 
    354     gboolean interiorFocus;
    355     gint focusWidth, focusPad;
    356     gtk_style_context_get_style(context,
    357                                 "interior-focus", &interiorFocus,
    358                                 "focus-line-width", &focusWidth,
    359                                 "focus-padding", &focusPad, NULL);
    360     focus = interiorFocus ? focusWidth + focusPad : 0;
    361 
    362     gtk_style_context_restore(context);
    363 
    364     context = getStyleContext(GTK_TYPE_SEPARATOR);
    365     gtk_style_context_save(context);
    366 
    367     GtkTextDirection direction = static_cast<GtkTextDirection>(gtkTextDirection(style->direction()));
    368     gtk_style_context_set_direction(context, direction);
    369     gtk_style_context_add_class(context, "separator");
    370 
    371     gboolean wideSeparators;
    372     gint separatorWidth;
    373     gtk_style_context_get_style(context,
    374                                 "wide-separators", &wideSeparators,
    375                                 "separator-width", &separatorWidth,
    376                                 NULL);
    377 
    378     // GTK+ always uses border.left, regardless of text direction. See gtkseperator.c.
    379     if (!wideSeparators)
    380         separatorWidth = border.left;
    381 
    382     separator = separatorWidth;
    383 
    384     gtk_style_context_restore(context);
    385 }
    386 
    387 int RenderThemeGtk::popupInternalPaddingLeft(RenderStyle* style) const
    388 {
    389     GtkBorder borderWidth = { 0, 0, 0, 0 };
    390     int focusWidth = 0, separatorWidth = 0;
    391     getComboBoxMetrics(style, borderWidth, focusWidth, separatorWidth);
    392     int left = borderWidth.left + focusWidth;
    393     if (style->direction() == RTL)
    394         left += separatorWidth + minArrowSize;
    395     return left;
    396 }
    397 
    398 int RenderThemeGtk::popupInternalPaddingRight(RenderStyle* style) const
    399 {
    400     GtkBorder borderWidth = { 0, 0, 0, 0 };
    401     int focusWidth = 0, separatorWidth = 0;
    402     getComboBoxMetrics(style, borderWidth, focusWidth, separatorWidth);
    403     int right = borderWidth.right + focusWidth;
    404     if (style->direction() == LTR)
    405         right += separatorWidth + minArrowSize;
    406     return right;
    407 }
    408 
    409 int RenderThemeGtk::popupInternalPaddingTop(RenderStyle* style) const
    410 {
    411     GtkBorder borderWidth = { 0, 0, 0, 0 };
    412     int focusWidth = 0, separatorWidth = 0;
    413     getComboBoxMetrics(style, borderWidth, focusWidth, separatorWidth);
    414     return borderWidth.top + focusWidth;
    415 }
    416 
    417 int RenderThemeGtk::popupInternalPaddingBottom(RenderStyle* style) const
    418 {
    419     GtkBorder borderWidth = { 0, 0, 0, 0 };
    420     int focusWidth = 0, separatorWidth = 0;
    421     getComboBoxMetrics(style, borderWidth, focusWidth, separatorWidth);
    422     return borderWidth.bottom + focusWidth;
    423 }
    424 
    425 bool RenderThemeGtk::paintMenuList(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
    426 {
    427     cairo_t* cairoContext = paintInfo.context->platformContext()->cr();
    428     GtkTextDirection direction = static_cast<GtkTextDirection>(gtkTextDirection(renderObject->style()->direction()));
    429 
    430     // Paint the button.
    431     GtkStyleContext* buttonStyleContext = getStyleContext(GTK_TYPE_BUTTON);
    432     gtk_style_context_save(buttonStyleContext);
    433     gtk_style_context_set_direction(buttonStyleContext, direction);
    434     gtk_style_context_add_class(buttonStyleContext, GTK_STYLE_CLASS_BUTTON);
    435     renderButton(this, buttonStyleContext, renderObject, paintInfo, rect);
    436 
    437     // Get the inner rectangle.
    438     gint focusWidth, focusPad;
    439     GtkBorder* innerBorderPtr = 0;
    440     GtkBorder innerBorder = { 1, 1, 1, 1 };
    441     gtk_style_context_get_style(buttonStyleContext,
    442                                 "inner-border", &innerBorderPtr,
    443                                 "focus-line-width", &focusWidth,
    444                                 "focus-padding", &focusPad,
    445                                 NULL);
    446     if (innerBorderPtr) {
    447         innerBorder = *innerBorderPtr;
    448         gtk_border_free(innerBorderPtr);
    449     }
    450 
    451     GtkBorder borderWidth;
    452     GtkStateFlags state = gtk_style_context_get_state(buttonStyleContext);
    453     gtk_style_context_get_border(buttonStyleContext, state, &borderWidth);
    454 
    455     focusWidth += focusPad;
    456     IntRect innerRect(rect.x() + innerBorder.left + borderWidth.left + focusWidth,
    457                       rect.y() + innerBorder.top + borderWidth.top + focusWidth,
    458                       rect.width() - borderWidth.left - borderWidth.right - innerBorder.left - innerBorder.right - (2 * focusWidth),
    459                       rect.height() - borderWidth.top - borderWidth.bottom - innerBorder.top - innerBorder.bottom - (2 * focusWidth));
    460 
    461     if (isPressed(renderObject)) {
    462         gint childDisplacementX;
    463         gint childDisplacementY;
    464         gtk_style_context_get_style(buttonStyleContext,
    465                                     "child-displacement-x", &childDisplacementX,
    466                                     "child-displacement-y", &childDisplacementY,
    467                                     NULL);
    468         innerRect.move(childDisplacementX, childDisplacementY);
    469     }
    470     innerRect.setWidth(max(1, innerRect.width()));
    471     innerRect.setHeight(max(1, innerRect.height()));
    472 
    473     gtk_style_context_restore(buttonStyleContext);
    474 
    475     // Paint the arrow.
    476     GtkStyleContext* arrowStyleContext = getStyleContext(GTK_TYPE_ARROW);
    477     gtk_style_context_save(arrowStyleContext);
    478 
    479     gtk_style_context_set_direction(arrowStyleContext, direction);
    480     gtk_style_context_add_class(arrowStyleContext, "arrow");
    481     gtk_style_context_add_class(arrowStyleContext, GTK_STYLE_CLASS_BUTTON);
    482 
    483     gfloat arrowScaling;
    484     gtk_style_context_get_style(arrowStyleContext, "arrow-scaling", &arrowScaling, NULL);
    485 
    486     IntSize arrowSize(minArrowSize, innerRect.height());
    487     FloatPoint arrowPosition(innerRect.location());
    488     if (direction == GTK_TEXT_DIR_LTR)
    489         arrowPosition.move(innerRect.width() - arrowSize.width(), 0);
    490 
    491     // GTK+ actually fetches the xalign and valign values from the widget, but since we
    492     // don't have a widget here, we are just using the default xalign and valign values of 0.5.
    493     gint extent = std::min(arrowSize.width(), arrowSize.height()) * arrowScaling;
    494     arrowPosition.move((arrowSize.width() - extent) / 2, (arrowSize.height() - extent) / 2);
    495 
    496     gtk_style_context_set_state(arrowStyleContext, state);
    497     gtk_render_arrow(arrowStyleContext, cairoContext, G_PI, arrowPosition.x(), arrowPosition.y(), extent);
    498 
    499     gtk_style_context_restore(arrowStyleContext);
    500 
    501     // Paint the separator if needed.
    502     GtkStyleContext* separatorStyleContext = getStyleContext(GTK_TYPE_SEPARATOR);
    503     gtk_style_context_save(separatorStyleContext);
    504 
    505     gtk_style_context_set_direction(separatorStyleContext, direction);
    506     gtk_style_context_add_class(separatorStyleContext, "separator");
    507     gtk_style_context_add_class(separatorStyleContext, GTK_STYLE_CLASS_BUTTON);
    508 
    509     gboolean wideSeparators;
    510     gint separatorWidth;
    511     gtk_style_context_get_style(separatorStyleContext,
    512                                 "wide-separators", &wideSeparators,
    513                                 "separator-width", &separatorWidth,
    514                                 NULL);
    515     if (wideSeparators && !separatorWidth) {
    516         gtk_style_context_restore(separatorStyleContext);
    517         return false;
    518     }
    519 
    520     gtk_style_context_set_state(separatorStyleContext, state);
    521     IntPoint separatorPosition(arrowPosition.x(), innerRect.y());
    522     if (wideSeparators) {
    523         if (direction == GTK_TEXT_DIR_LTR)
    524             separatorPosition.move(-separatorWidth, 0);
    525         else
    526             separatorPosition.move(arrowSize.width(), 0);
    527 
    528         gtk_render_frame(separatorStyleContext, cairoContext,
    529                          separatorPosition.x(), separatorPosition.y(),
    530                          separatorWidth, innerRect.height());
    531     } else {
    532         GtkBorder padding;
    533         gtk_style_context_get_padding(separatorStyleContext, state, &padding);
    534         GtkBorder border;
    535         gtk_style_context_get_border(separatorStyleContext, state, &border);
    536 
    537         if (direction == GTK_TEXT_DIR_LTR)
    538             separatorPosition.move(-(padding.left + border.left), 0);
    539         else
    540             separatorPosition.move(arrowSize.width(), 0);
    541 
    542         cairo_save(cairoContext);
    543 
    544         // An extra clip prevents the separator bleeding outside of the specified rectangle because of subpixel positioning.
    545         cairo_rectangle(cairoContext, separatorPosition.x(), separatorPosition.y(), border.left, innerRect.height());
    546         cairo_clip(cairoContext);
    547         gtk_render_line(separatorStyleContext, cairoContext,
    548                         separatorPosition.x(), separatorPosition.y(),
    549                         separatorPosition.x(), innerRect.maxY());
    550         cairo_restore(cairoContext);
    551     }
    552 
    553     gtk_style_context_restore(separatorStyleContext);
    554     return false;
    555 }
    556 
    557 bool RenderThemeGtk::paintTextField(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
    558 {
    559     GtkStyleContext* context = getStyleContext(GTK_TYPE_ENTRY);
    560     gtk_style_context_save(context);
    561 
    562     gtk_style_context_set_direction(context, static_cast<GtkTextDirection>(gtkTextDirection(renderObject->style()->direction())));
    563     gtk_style_context_add_class(context, GTK_STYLE_CLASS_ENTRY);
    564 
    565     guint flags = 0;
    566     if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
    567         flags |= GTK_STATE_FLAG_INSENSITIVE;
    568     else if (isFocused(renderObject))
    569         flags |= GTK_STATE_FLAG_FOCUSED;
    570     gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags));
    571 
    572     gtk_render_background(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
    573     gtk_render_frame(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
    574 
    575     if (isFocused(renderObject) && isEnabled(renderObject)) {
    576         gboolean interiorFocus;
    577         gint focusWidth, focusPad;
    578         gtk_style_context_get_style(context,
    579                                     "interior-focus", &interiorFocus,
    580                                     "focus-line-width", &focusWidth,
    581                                     "focus-padding", &focusPad,
    582                                     NULL);
    583         if (!interiorFocus) {
    584             IntRect focusRect(rect);
    585             focusRect.inflate(focusWidth + focusPad);
    586             gtk_render_focus(context, paintInfo.context->platformContext()->cr(),
    587                              focusRect.x(), focusRect.y(), focusRect.width(), focusRect.height());
    588         }
    589     }
    590 
    591     gtk_style_context_restore(context);
    592 
    593     return false;
    594 }
    595 
    596 bool RenderThemeGtk::paintSliderTrack(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
    597 {
    598     ControlPart part = renderObject->style()->appearance();
    599     ASSERT(part == SliderHorizontalPart || part == SliderVerticalPart || part == MediaVolumeSliderPart);
    600 
    601     GtkStyleContext* context = getStyleContext(part == SliderThumbHorizontalPart ? GTK_TYPE_HSCALE : GTK_TYPE_VSCALE);
    602     gtk_style_context_save(context);
    603 
    604     gtk_style_context_set_direction(context, gtkTextDirection(renderObject->style()->direction()));
    605     gtk_style_context_add_class(context, GTK_STYLE_CLASS_SCALE);
    606     gtk_style_context_add_class(context, GTK_STYLE_CLASS_TROUGH);
    607 
    608     if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
    609         gtk_style_context_set_state(context, GTK_STATE_FLAG_INSENSITIVE);
    610 
    611     gtk_render_background(context, paintInfo.context->platformContext()->cr(),
    612                           rect.x(), rect.y(), rect.width(), rect.height());
    613     gtk_render_frame(context, paintInfo.context->platformContext()->cr(),
    614                      rect.x(), rect.y(), rect.width(), rect.height());
    615 
    616     if (isFocused(renderObject)) {
    617         gint focusWidth, focusPad;
    618         gtk_style_context_get_style(context,
    619                                     "focus-line-width", &focusWidth,
    620                                     "focus-padding", &focusPad, NULL);
    621         IntRect focusRect(rect);
    622         focusRect.inflate(focusWidth + focusPad);
    623         gtk_render_focus(context, paintInfo.context->platformContext()->cr(),
    624                          focusRect.x(), focusRect.y(), focusRect.width(), focusRect.height());
    625     }
    626 
    627     gtk_style_context_restore(context);
    628     return false;
    629 }
    630 
    631 bool RenderThemeGtk::paintSliderThumb(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
    632 {
    633     ControlPart part = renderObject->style()->appearance();
    634     ASSERT(part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart || part == MediaVolumeSliderThumbPart);
    635 
    636     GtkStyleContext* context = getStyleContext(part == SliderThumbHorizontalPart ? GTK_TYPE_HSCALE : GTK_TYPE_VSCALE);
    637     gtk_style_context_save(context);
    638 
    639     gtk_style_context_set_direction(context, gtkTextDirection(renderObject->style()->direction()));
    640     gtk_style_context_add_class(context, GTK_STYLE_CLASS_SCALE);
    641     gtk_style_context_add_class(context, GTK_STYLE_CLASS_SLIDER);
    642 
    643     gint troughBorder;
    644     gtk_style_context_get_style(context, "trough-border", &troughBorder, NULL);
    645 
    646     IntRect sliderRect(rect);
    647     sliderRect.inflate(-troughBorder);
    648 
    649     guint flags = 0;
    650     if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
    651         flags |= GTK_STATE_FLAG_INSENSITIVE;
    652     else if (isHovered(renderObject))
    653         flags |= GTK_STATE_FLAG_PRELIGHT;
    654     if (isPressed(renderObject))
    655         flags |= GTK_STATE_FLAG_ACTIVE;
    656     gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags));
    657 
    658     gtk_render_slider(context, paintInfo.context->platformContext()->cr(), sliderRect.x(), sliderRect.y(), sliderRect.width(), sliderRect.height(),
    659                       part == SliderThumbHorizontalPart ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
    660 
    661     gtk_style_context_restore(context);
    662 
    663     return false;
    664 }
    665 
    666 void RenderThemeGtk::adjustSliderThumbSize(RenderObject* renderObject) const
    667 {
    668     ControlPart part = renderObject->style()->appearance();
    669 #if ENABLE(VIDEO)
    670     if (part == MediaSliderThumbPart) {
    671         adjustMediaSliderThumbSize(renderObject);
    672         return;
    673     }
    674 #endif
    675 
    676     gint sliderWidth, sliderLength;
    677     gtk_style_context_get_style(getStyleContext(part == SliderThumbHorizontalPart ? GTK_TYPE_HSCALE : GTK_TYPE_VSCALE),
    678                                 "slider-width", &sliderWidth,
    679                                 "slider-length", &sliderLength,
    680                                 NULL);
    681     if (part == SliderThumbHorizontalPart) {
    682         renderObject->style()->setWidth(Length(sliderLength, Fixed));
    683         renderObject->style()->setHeight(Length(sliderWidth, Fixed));
    684         return;
    685     }
    686     ASSERT(part == SliderThumbVerticalPart || part == MediaVolumeSliderThumbPart);
    687     renderObject->style()->setWidth(Length(sliderWidth, Fixed));
    688     renderObject->style()->setHeight(Length(sliderLength, Fixed));
    689 }
    690 
    691 #if ENABLE(PROGRESS_TAG)
    692 bool RenderThemeGtk::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
    693 {
    694     if (!renderObject->isProgress())
    695         return true;
    696 
    697     GtkStyleContext* context = getStyleContext(GTK_TYPE_PROGRESS_BAR);
    698     gtk_style_context_save(context);
    699 
    700     gtk_style_context_add_class(context, GTK_STYLE_CLASS_TROUGH);
    701 
    702     gtk_render_background(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
    703     gtk_render_frame(context, paintInfo.context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height());
    704 
    705     gtk_style_context_restore(context);
    706 
    707     gtk_style_context_save(context);
    708     gtk_style_context_add_class(context, GTK_STYLE_CLASS_PROGRESSBAR);
    709 
    710 
    711     GtkBorder padding;
    712     gtk_style_context_get_padding(context, static_cast<GtkStateFlags>(0), &padding);
    713     IntRect progressRect(rect.x() + padding.left, rect.y() + padding.top,
    714                          rect.width() - (padding.left + padding.right),
    715                          rect.height() - (padding.top + padding.bottom));
    716     progressRect = RenderThemeGtk::calculateProgressRect(renderObject, progressRect);
    717 
    718     if (!progressRect.isEmpty())
    719         gtk_render_activity(context, paintInfo.context->platformContext()->cr(), progressRect.x(), progressRect.y(), progressRect.width(), progressRect.height());
    720 
    721     gtk_style_context_restore(context);
    722     return false;
    723 }
    724 #endif
    725 
    726 static gint spinButtonArrowSize(GtkStyleContext* context)
    727 {
    728     const PangoFontDescription* fontDescription = gtk_style_context_get_font(context, static_cast<GtkStateFlags>(0));
    729     gint fontSize = pango_font_description_get_size(fontDescription);
    730     gint arrowSize = max(PANGO_PIXELS(fontSize), minSpinButtonArrowSize);
    731 
    732     return arrowSize - arrowSize % 2; // Force even.
    733 }
    734 
    735 void RenderThemeGtk::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
    736 {
    737     GtkStyleContext* context = getStyleContext(GTK_TYPE_SPIN_BUTTON);
    738 
    739     GtkBorder padding;
    740     gtk_style_context_get_padding(context, static_cast<GtkStateFlags>(0), &padding);
    741 
    742     int width = spinButtonArrowSize(context) + padding.left + padding.right;
    743     style->setWidth(Length(width, Fixed));
    744     style->setMinWidth(Length(width, Fixed));
    745 }
    746 
    747 static void paintSpinArrowButton(RenderTheme* theme, GtkStyleContext* context, RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect, GtkArrowType arrowType)
    748 {
    749     ASSERT(arrowType == GTK_ARROW_UP || arrowType == GTK_ARROW_DOWN);
    750 
    751     gtk_style_context_save(context);
    752     gtk_style_context_add_class(context, GTK_STYLE_CLASS_BUTTON);
    753 
    754     GtkTextDirection direction = gtk_style_context_get_direction(context);
    755     guint state = static_cast<guint>(gtk_style_context_get_state(context));
    756     if (!(state & GTK_STATE_FLAG_INSENSITIVE)) {
    757         if (theme->isPressed(renderObject)) {
    758             if ((arrowType == GTK_ARROW_UP && theme->isSpinUpButtonPartPressed(renderObject))
    759                 || (arrowType == GTK_ARROW_DOWN && !theme->isSpinUpButtonPartPressed(renderObject)))
    760                 state |= GTK_STATE_FLAG_ACTIVE;
    761         } else if (theme->isHovered(renderObject)) {
    762             if ((arrowType == GTK_ARROW_UP && theme->isSpinUpButtonPartHovered(renderObject))
    763                 || (arrowType == GTK_ARROW_DOWN && !theme->isSpinUpButtonPartHovered(renderObject)))
    764                 state |= GTK_STATE_FLAG_PRELIGHT;
    765         }
    766     }
    767     gtk_style_context_set_state(context, static_cast<GtkStateFlags>(state));
    768 
    769     // Paint button.
    770     IntRect buttonRect(rect);
    771     guint junction = gtk_style_context_get_junction_sides(context);
    772     if (arrowType == GTK_ARROW_UP)
    773         junction |= GTK_JUNCTION_BOTTOM;
    774     else {
    775         junction |= GTK_JUNCTION_TOP;
    776         buttonRect.move(0, rect.height() / 2);
    777     }
    778     buttonRect.setHeight(rect.height() / 2);
    779     gtk_style_context_set_junction_sides(context, static_cast<GtkJunctionSides>(junction));
    780 
    781     gtk_render_background(context, paintInfo.context->platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
    782     gtk_render_frame(context, paintInfo.context->platformContext()->cr(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
    783 
    784     // Paint arrow centered inside button.
    785     // This code is based on gtkspinbutton.c code.
    786     IntRect arrowRect;
    787     gdouble angle;
    788     if (arrowType == GTK_ARROW_UP) {
    789         angle = 0;
    790         arrowRect.setY(rect.y());
    791         arrowRect.setHeight(rect.height() / 2 - 2);
    792     } else {
    793         angle = G_PI;
    794         arrowRect.setY(rect.y() + buttonRect.y());
    795         arrowRect.setHeight(rect.height() - arrowRect.y() - 2);
    796     }
    797     arrowRect.setWidth(rect.width() - 3);
    798     if (direction == GTK_TEXT_DIR_LTR)
    799         arrowRect.setX(rect.x() + 1);
    800     else
    801         arrowRect.setX(rect.x() + 2);
    802 
    803     gint width = arrowRect.width() / 2;
    804     width -= width % 2 - 1; // Force odd.
    805     gint height = (width + 1) / 2;
    806 
    807     arrowRect.move((arrowRect.width() - width) / 2, (arrowRect.height() - height) / 2);
    808     gtk_render_arrow(context, paintInfo.context->platformContext()->cr(), angle, arrowRect.x(), arrowRect.y(), width);
    809 
    810     gtk_style_context_restore(context);
    811 }
    812 
    813 bool RenderThemeGtk::paintInnerSpinButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
    814 {
    815     GtkStyleContext* context = getStyleContext(GTK_TYPE_SPIN_BUTTON);
    816     gtk_style_context_save(context);
    817 
    818     GtkTextDirection direction = static_cast<GtkTextDirection>(gtkTextDirection(renderObject->style()->direction()));
    819     gtk_style_context_set_direction(context, direction);
    820 
    821     guint flags = 0;
    822     if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
    823         flags |= GTK_STATE_FLAG_INSENSITIVE;
    824     else if (isFocused(renderObject))
    825         flags |= GTK_STATE_FLAG_FOCUSED;
    826     gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags));
    827     gtk_style_context_remove_class(context, GTK_STYLE_CLASS_ENTRY);
    828 
    829     paintSpinArrowButton(this, context, renderObject, paintInfo, rect, GTK_ARROW_UP);
    830     paintSpinArrowButton(this, context, renderObject, paintInfo, rect, GTK_ARROW_DOWN);
    831 
    832     gtk_style_context_restore(context);
    833 
    834     return false;
    835 }
    836 
    837 GRefPtr<GdkPixbuf> RenderThemeGtk::getStockIcon(GType widgetType, const char* iconName, gint direction, gint state, gint iconSize)
    838 {
    839     GtkStyleContext* context = getStyleContext(widgetType);
    840     GtkIconSet* iconSet = gtk_style_context_lookup_icon_set(context, iconName);
    841 
    842     gtk_style_context_save(context);
    843 
    844     guint flags = 0;
    845     if (state == GTK_STATE_PRELIGHT)
    846         flags |= GTK_STATE_FLAG_PRELIGHT;
    847     else if (state == GTK_STATE_INSENSITIVE)
    848         flags |= GTK_STATE_FLAG_INSENSITIVE;
    849 
    850     gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags));
    851     gtk_style_context_set_direction(context, static_cast<GtkTextDirection>(direction));
    852     GdkPixbuf* icon = gtk_icon_set_render_icon_pixbuf(iconSet, context, static_cast<GtkIconSize>(iconSize));
    853 
    854     gtk_style_context_restore(context);
    855 
    856     return adoptGRef(icon);
    857 }
    858 
    859 Color RenderThemeGtk::platformActiveSelectionBackgroundColor() const
    860 {
    861     GdkRGBA gdkRGBAColor;
    862     gtk_style_context_get_background_color(getStyleContext(GTK_TYPE_ENTRY), GTK_STATE_FLAG_SELECTED, &gdkRGBAColor);
    863     return gdkRGBAColor;
    864 }
    865 
    866 Color RenderThemeGtk::platformInactiveSelectionBackgroundColor() const
    867 {
    868     GdkRGBA gdkRGBAColor;
    869     gtk_style_context_get_background_color(getStyleContext(GTK_TYPE_ENTRY), GTK_STATE_FLAG_ACTIVE, &gdkRGBAColor);
    870     return gdkRGBAColor;
    871 }
    872 
    873 Color RenderThemeGtk::platformActiveSelectionForegroundColor() const
    874 {
    875     GdkRGBA gdkRGBAColor;
    876     gtk_style_context_get_color(getStyleContext(GTK_TYPE_ENTRY), GTK_STATE_FLAG_SELECTED, &gdkRGBAColor);
    877     return gdkRGBAColor;
    878 }
    879 
    880 Color RenderThemeGtk::platformInactiveSelectionForegroundColor() const
    881 {
    882     GdkRGBA gdkRGBAColor;
    883     gtk_style_context_get_color(getStyleContext(GTK_TYPE_ENTRY), GTK_STATE_FLAG_ACTIVE, &gdkRGBAColor);
    884     return gdkRGBAColor;
    885 }
    886 
    887 Color RenderThemeGtk::activeListBoxSelectionBackgroundColor() const
    888 {
    889     GdkRGBA gdkRGBAColor;
    890     gtk_style_context_get_background_color(getStyleContext(GTK_TYPE_TREE_VIEW), GTK_STATE_FLAG_SELECTED, &gdkRGBAColor);
    891     return gdkRGBAColor;
    892 }
    893 
    894 Color RenderThemeGtk::inactiveListBoxSelectionBackgroundColor() const
    895 {
    896     GdkRGBA gdkRGBAColor;
    897     gtk_style_context_get_background_color(getStyleContext(GTK_TYPE_TREE_VIEW), GTK_STATE_FLAG_ACTIVE, &gdkRGBAColor);
    898     return gdkRGBAColor;
    899 }
    900 
    901 Color RenderThemeGtk::activeListBoxSelectionForegroundColor() const
    902 {
    903     GdkRGBA gdkRGBAColor;
    904     gtk_style_context_get_color(getStyleContext(GTK_TYPE_TREE_VIEW), GTK_STATE_FLAG_SELECTED, &gdkRGBAColor);
    905     return gdkRGBAColor;
    906 }
    907 
    908 Color RenderThemeGtk::inactiveListBoxSelectionForegroundColor() const
    909 {
    910     GdkRGBA gdkRGBAColor;
    911     gtk_style_context_get_color(getStyleContext(GTK_TYPE_TREE_VIEW), GTK_STATE_FLAG_ACTIVE, &gdkRGBAColor);
    912     return gdkRGBAColor;
    913 }
    914 
    915 Color RenderThemeGtk::systemColor(int cssValueId) const
    916 {
    917     GdkRGBA gdkRGBAColor;
    918 
    919     switch (cssValueId) {
    920     case CSSValueButtontext:
    921         gtk_style_context_get_color(getStyleContext(GTK_TYPE_BUTTON), static_cast<GtkStateFlags>(0), &gdkRGBAColor);
    922         return gdkRGBAColor;
    923     case CSSValueCaptiontext:
    924         gtk_style_context_get_color(getStyleContext(GTK_TYPE_ENTRY), static_cast<GtkStateFlags>(0), &gdkRGBAColor);
    925         return gdkRGBAColor;
    926     default:
    927         return RenderTheme::systemColor(cssValueId);
    928     }
    929 }
    930 
    931 } // namespace WebCore
    932 
    933 #endif // !GTK_API_VERSION_2
    934