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  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Library General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Library General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Library General Public License
     18  * along with this library; see the file COPYING.LIB.  If not, write to
     19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20  * Boston, MA 02110-1301, USA.
     21  *
     22  */
     23 
     24 #include "config.h"
     25 #include "RenderThemeGtk.h"
     26 
     27 #include "AffineTransform.h"
     28 #include "CString.h"
     29 #include "GOwnPtr.h"
     30 #include "GraphicsContext.h"
     31 #include "HTMLMediaElement.h"
     32 #include "HTMLNames.h"
     33 #include "NotImplemented.h"
     34 #include "RenderBox.h"
     35 #include "RenderObject.h"
     36 #include "UserAgentStyleSheets.h"
     37 #include "gtkdrawing.h"
     38 
     39 #include <gdk/gdk.h>
     40 #include <gtk/gtk.h>
     41 
     42 namespace WebCore {
     43 
     44 using namespace HTMLNames;
     45 
     46 #if ENABLE(VIDEO)
     47 static HTMLMediaElement* getMediaElementFromRenderObject(RenderObject* o)
     48 {
     49     Node* node = o->node();
     50     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
     51     if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
     52         return 0;
     53 
     54     return static_cast<HTMLMediaElement*>(mediaNode);
     55 }
     56 
     57 static gchar* getIconNameForTextDirection(const char* baseName)
     58 {
     59     GString* nameWithDirection = g_string_new(baseName);
     60     GtkTextDirection textDirection = gtk_widget_get_default_direction();
     61 
     62     if (textDirection == GTK_TEXT_DIR_RTL)
     63         g_string_append(nameWithDirection, "-rtl");
     64     else if (textDirection == GTK_TEXT_DIR_LTR)
     65         g_string_append(nameWithDirection, "-ltr");
     66 
     67     return g_string_free(nameWithDirection, FALSE);
     68 }
     69 
     70 void RenderThemeGtk::initMediaStyling(GtkStyle* style, bool force)
     71 {
     72     static bool stylingInitialized = false;
     73 
     74     if (!stylingInitialized || force) {
     75         m_panelColor = style->bg[GTK_STATE_NORMAL];
     76         m_sliderColor = style->bg[GTK_STATE_ACTIVE];
     77         m_sliderThumbColor = style->bg[GTK_STATE_SELECTED];
     78 
     79         // Names of these icons can vary because of text direction.
     80         gchar* playButtonIconName = getIconNameForTextDirection("gtk-media-play");
     81         gchar* seekBackButtonIconName = getIconNameForTextDirection("gtk-media-rewind");
     82         gchar* seekForwardButtonIconName = getIconNameForTextDirection("gtk-media-forward");
     83 
     84         m_fullscreenButton.clear();
     85         m_muteButton.clear();
     86         m_unmuteButton.clear();
     87         m_playButton.clear();
     88         m_pauseButton.clear();
     89         m_seekBackButton.clear();
     90         m_seekForwardButton.clear();
     91 
     92         m_fullscreenButton = Image::loadPlatformThemeIcon("gtk-fullscreen", m_mediaIconSize);
     93         m_muteButton = Image::loadPlatformThemeIcon("audio-volume-muted", m_mediaIconSize);
     94         m_unmuteButton = Image::loadPlatformThemeIcon("audio-volume-high", m_mediaIconSize);
     95         m_playButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(playButtonIconName), m_mediaIconSize);
     96         m_pauseButton = Image::loadPlatformThemeIcon("gtk-media-pause", m_mediaIconSize).releaseRef();
     97         m_seekBackButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(seekBackButtonIconName), m_mediaIconSize);
     98         m_seekForwardButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(seekForwardButtonIconName), m_mediaIconSize);
     99 
    100         g_free(playButtonIconName);
    101         g_free(seekBackButtonIconName);
    102         g_free(seekForwardButtonIconName);
    103         stylingInitialized = true;
    104     }
    105 }
    106 #endif
    107 
    108 PassRefPtr<RenderTheme> RenderThemeGtk::create()
    109 {
    110     return adoptRef(new RenderThemeGtk());
    111 }
    112 
    113 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
    114 {
    115     static RenderTheme* rt = RenderThemeGtk::create().releaseRef();
    116     return rt;
    117 }
    118 
    119 static int mozGtkRefCount = 0;
    120 
    121 RenderThemeGtk::RenderThemeGtk()
    122     : m_gtkWindow(0)
    123     , m_gtkContainer(0)
    124     , m_gtkEntry(0)
    125     , m_gtkTreeView(0)
    126     , m_panelColor(Color::white)
    127     , m_sliderColor(Color::white)
    128     , m_sliderThumbColor(Color::white)
    129     , m_mediaIconSize(16)
    130     , m_mediaSliderHeight(14)
    131     , m_mediaSliderThumbWidth(12)
    132     , m_mediaSliderThumbHeight(12)
    133     , m_fullscreenButton(0)
    134     , m_muteButton(0)
    135     , m_unmuteButton(0)
    136     , m_playButton(0)
    137     , m_pauseButton(0)
    138     , m_seekBackButton(0)
    139     , m_seekForwardButton(0)
    140     , m_partsTable(adoptGRef(g_hash_table_new_full(0, 0, 0, g_free)))
    141 {
    142     if (!mozGtkRefCount) {
    143         moz_gtk_init();
    144 
    145         // Use the theme parts for the default drawable.
    146         moz_gtk_use_theme_parts(partsForDrawable(0));
    147     }
    148 
    149     ++mozGtkRefCount;
    150 
    151 #if ENABLE(VIDEO)
    152     initMediaStyling(gtk_rc_get_style(GTK_WIDGET(gtkContainer())), false);
    153 #endif
    154 }
    155 
    156 RenderThemeGtk::~RenderThemeGtk()
    157 {
    158     --mozGtkRefCount;
    159 
    160     if (!mozGtkRefCount)
    161         moz_gtk_shutdown();
    162 
    163     m_fullscreenButton.clear();
    164     m_muteButton.clear();
    165     m_unmuteButton.clear();
    166     m_playButton.clear();
    167     m_pauseButton.clear();
    168     m_seekBackButton.clear();
    169     m_seekForwardButton.clear();
    170 
    171     GList* values = g_hash_table_get_values(m_partsTable.get());
    172     for (guint i = 0; i < g_list_length(values); i++)
    173         moz_gtk_destroy_theme_parts_widgets(
    174             static_cast<GtkThemeParts*>(g_list_nth_data(values, i)));
    175 }
    176 
    177 GtkThemeParts* RenderThemeGtk::partsForDrawable(GdkDrawable* drawable) const
    178 {
    179     // A null drawable represents the default screen colormap.
    180     GdkColormap* colormap = 0;
    181     if (!drawable)
    182         colormap = gdk_screen_get_default_colormap(gdk_screen_get_default());
    183     else
    184         colormap = gdk_drawable_get_colormap(drawable);
    185 
    186     GtkThemeParts* parts = static_cast<GtkThemeParts*>(g_hash_table_lookup(m_partsTable.get(), colormap));
    187     if (!parts) {
    188         parts = g_new0(GtkThemeParts, 1);
    189         parts->colormap = colormap;
    190         g_hash_table_insert(m_partsTable.get(), colormap, parts);
    191     }
    192 
    193     return parts;
    194 }
    195 
    196 static bool supportsFocus(ControlPart appearance)
    197 {
    198     switch (appearance) {
    199     case PushButtonPart:
    200     case ButtonPart:
    201     case TextFieldPart:
    202     case TextAreaPart:
    203     case SearchFieldPart:
    204     case MenulistPart:
    205     case RadioPart:
    206     case CheckboxPart:
    207         return true;
    208     default:
    209         return false;
    210     }
    211 }
    212 
    213 bool RenderThemeGtk::supportsFocusRing(const RenderStyle* style) const
    214 {
    215     return supportsFocus(style->appearance());
    216 }
    217 
    218 bool RenderThemeGtk::controlSupportsTints(const RenderObject* o) const
    219 {
    220     return isEnabled(o);
    221 }
    222 
    223 int RenderThemeGtk::baselinePosition(const RenderObject* o) const
    224 {
    225     if (!o->isBox())
    226         return 0;
    227 
    228     // FIXME: This strategy is possibly incorrect for the GTK+ port.
    229     if (o->style()->appearance() == CheckboxPart
    230         || o->style()->appearance() == RadioPart) {
    231         const RenderBox* box = toRenderBox(o);
    232         return box->marginTop() + box->height() - 2;
    233     }
    234 
    235     return RenderTheme::baselinePosition(o);
    236 }
    237 
    238 static GtkTextDirection gtkTextDirection(TextDirection direction)
    239 {
    240     switch (direction) {
    241     case RTL:
    242         return GTK_TEXT_DIR_RTL;
    243     case LTR:
    244         return GTK_TEXT_DIR_LTR;
    245     default:
    246         return GTK_TEXT_DIR_NONE;
    247     }
    248 }
    249 
    250 static void adjustMozillaStyle(const RenderThemeGtk* theme, RenderStyle* style, GtkThemeWidgetType type)
    251 {
    252     gint left, top, right, bottom;
    253     GtkTextDirection direction = gtkTextDirection(style->direction());
    254     gboolean inhtml = true;
    255 
    256     if (moz_gtk_get_widget_border(type, &left, &top, &right, &bottom, direction, inhtml) != MOZ_GTK_SUCCESS)
    257         return;
    258 
    259     // FIXME: This approach is likely to be incorrect. See other ports and layout tests to see the problem.
    260     const int xpadding = 1;
    261     const int ypadding = 1;
    262 
    263     style->setPaddingLeft(Length(xpadding + left, Fixed));
    264     style->setPaddingTop(Length(ypadding + top, Fixed));
    265     style->setPaddingRight(Length(xpadding + right, Fixed));
    266     style->setPaddingBottom(Length(ypadding + bottom, Fixed));
    267 }
    268 
    269 static void setMozillaState(const RenderTheme* theme, GtkWidgetState* state, RenderObject* o)
    270 {
    271     state->active = theme->isPressed(o);
    272     state->focused = theme->isFocused(o);
    273     state->inHover = theme->isHovered(o);
    274     // FIXME: Disabled does not always give the correct appearance for ReadOnly
    275     state->disabled = !theme->isEnabled(o) || theme->isReadOnlyControl(o);
    276     state->isDefault = false;
    277     state->canDefault = false;
    278     state->depressed = false;
    279 }
    280 
    281 static bool paintMozillaGtkWidget(const RenderThemeGtk* theme, GtkThemeWidgetType type, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
    282 {
    283     // No GdkWindow to render to, so return true to fall back
    284     if (!i.context->gdkDrawable())
    285         return true;
    286 
    287     // Painting is disabled so just claim to have succeeded
    288     if (i.context->paintingDisabled())
    289         return false;
    290 
    291     GtkWidgetState mozState;
    292     setMozillaState(theme, &mozState, o);
    293 
    294     int flags;
    295 
    296     // We might want to make setting flags the caller's job at some point rather than doing it here.
    297     switch (type) {
    298     case MOZ_GTK_BUTTON:
    299         flags = GTK_RELIEF_NORMAL;
    300         break;
    301     case MOZ_GTK_CHECKBUTTON:
    302     case MOZ_GTK_RADIOBUTTON:
    303         flags = theme->isChecked(o);
    304         break;
    305     default:
    306         flags = 0;
    307         break;
    308     }
    309 
    310     AffineTransform ctm = i.context->getCTM();
    311 
    312     IntPoint pos = ctm.mapPoint(rect.location());
    313     GdkRectangle gdkRect = IntRect(pos.x(), pos.y(), rect.width(), rect.height());
    314     GtkTextDirection direction = gtkTextDirection(o->style()->direction());
    315 
    316     // Find the clip rectangle
    317     cairo_t* cr = i.context->platformContext();
    318     double clipX1, clipX2, clipY1, clipY2;
    319     cairo_clip_extents(cr, &clipX1, &clipY1, &clipX2, &clipY2);
    320 
    321     GdkRectangle gdkClipRect;
    322     gdkClipRect.width = clipX2 - clipX1;
    323     gdkClipRect.height = clipY2 - clipY1;
    324     IntPoint clipPos = ctm.mapPoint(IntPoint(clipX1, clipY1));
    325     gdkClipRect.x = clipPos.x();
    326     gdkClipRect.y = clipPos.y();
    327 
    328     gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect);
    329 
    330     // Since the theme renderer is going to be drawing onto this GdkDrawable,
    331     // select the appropriate widgets for the drawable depth.
    332     moz_gtk_use_theme_parts(theme->partsForDrawable(i.context->gdkDrawable()));
    333     return moz_gtk_widget_paint(type, i.context->gdkDrawable(), &gdkRect, &gdkClipRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS;
    334 }
    335 
    336 static void setButtonPadding(RenderStyle* style)
    337 {
    338     // FIXME: This looks incorrect.
    339     const int padding = 8;
    340     style->setPaddingLeft(Length(padding, Fixed));
    341     style->setPaddingRight(Length(padding, Fixed));
    342     style->setPaddingTop(Length(padding / 2, Fixed));
    343     style->setPaddingBottom(Length(padding / 2, Fixed));
    344 }
    345 
    346 static void setToggleSize(const RenderThemeGtk* theme, RenderStyle* style, ControlPart appearance)
    347 {
    348     // The width and height are both specified, so we shouldn't change them.
    349     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
    350         return;
    351 
    352     // FIXME: This is probably not correct use of indicatorSize and indicatorSpacing.
    353     gint indicatorSize, indicatorSpacing;
    354 
    355     switch (appearance) {
    356     case CheckboxPart:
    357         if (moz_gtk_checkbox_get_metrics(&indicatorSize, &indicatorSpacing) != MOZ_GTK_SUCCESS)
    358             return;
    359         break;
    360     case RadioPart:
    361         if (moz_gtk_radio_get_metrics(&indicatorSize, &indicatorSpacing) != MOZ_GTK_SUCCESS)
    362             return;
    363         break;
    364     default:
    365         return;
    366     }
    367 
    368     // Other ports hard-code this to 13, but GTK+ users tend to demand the native look.
    369     // It could be made a configuration option values other than 13 actually break site compatibility.
    370     int length = indicatorSize + indicatorSpacing;
    371     if (style->width().isIntrinsicOrAuto())
    372         style->setWidth(Length(length, Fixed));
    373 
    374     if (style->height().isAuto())
    375         style->setHeight(Length(length, Fixed));
    376 }
    377 
    378 void RenderThemeGtk::setCheckboxSize(RenderStyle* style) const
    379 {
    380     setToggleSize(this, style, RadioPart);
    381 }
    382 
    383 bool RenderThemeGtk::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
    384 {
    385     return paintMozillaGtkWidget(this, MOZ_GTK_CHECKBUTTON, o, i, rect);
    386 }
    387 
    388 void RenderThemeGtk::setRadioSize(RenderStyle* style) const
    389 {
    390     setToggleSize(this, style, RadioPart);
    391 }
    392 
    393 bool RenderThemeGtk::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
    394 {
    395     return paintMozillaGtkWidget(this, MOZ_GTK_RADIOBUTTON, o, i, rect);
    396 }
    397 
    398 void RenderThemeGtk::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
    399 {
    400     // FIXME: Is this condition necessary?
    401     if (style->appearance() == PushButtonPart) {
    402         style->resetBorder();
    403         style->setHeight(Length(Auto));
    404         style->setWhiteSpace(PRE);
    405         setButtonPadding(style);
    406     } else {
    407         // FIXME: This should not be hard-coded.
    408         style->setMinHeight(Length(14, Fixed));
    409         style->resetBorderTop();
    410         style->resetBorderBottom();
    411     }
    412 }
    413 
    414 bool RenderThemeGtk::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
    415 {
    416     return paintMozillaGtkWidget(this, MOZ_GTK_BUTTON, o, i, rect);
    417 }
    418 
    419 void RenderThemeGtk::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
    420 {
    421     style->resetBorder();
    422     style->resetPadding();
    423     style->setHeight(Length(Auto));
    424     style->setWhiteSpace(PRE);
    425     adjustMozillaStyle(this, style, MOZ_GTK_DROPDOWN);
    426 }
    427 
    428 bool RenderThemeGtk::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
    429 {
    430     return paintMozillaGtkWidget(this, MOZ_GTK_DROPDOWN, o, i, rect);
    431 }
    432 
    433 void RenderThemeGtk::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    434 {
    435     style->resetBorder();
    436     style->resetPadding();
    437     style->setHeight(Length(Auto));
    438     style->setWhiteSpace(PRE);
    439     adjustMozillaStyle(this, style, MOZ_GTK_ENTRY);
    440 }
    441 
    442 bool RenderThemeGtk::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
    443 {
    444     return paintMozillaGtkWidget(this, MOZ_GTK_ENTRY, o, i, rect);
    445 }
    446 
    447 bool RenderThemeGtk::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
    448 {
    449     return paintTextField(o, i, r);
    450 }
    451 
    452 void RenderThemeGtk::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    453 {
    454     adjustSearchFieldCancelButtonStyle(selector, style, e);
    455 }
    456 
    457 bool RenderThemeGtk::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
    458 {
    459     return paintMozillaGtkWidget(this, MOZ_GTK_DROPDOWN_ARROW, o, i, rect);
    460 }
    461 
    462 void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    463 {
    464     style->resetBorder();
    465     style->resetPadding();
    466 
    467     // FIXME: This should not be hard-coded.
    468     IntSize size = IntSize(14, 14);
    469     style->setWidth(Length(size.width(), Fixed));
    470     style->setHeight(Length(size.height(), Fixed));
    471 }
    472 
    473 bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
    474 {
    475     return paintMozillaGtkWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect);
    476 }
    477 
    478 void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    479 {
    480     style->resetBorder();
    481     style->resetPadding();
    482 
    483     // FIXME: This should not be hard-coded.
    484     IntSize size = IntSize(14, 14);
    485     style->setWidth(Length(size.width(), Fixed));
    486     style->setHeight(Length(size.height(), Fixed));
    487 }
    488 
    489 bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
    490 {
    491     return paintMozillaGtkWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect);
    492 }
    493 
    494 void RenderThemeGtk::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
    495 {
    496     adjustTextFieldStyle(selector, style, e);
    497 }
    498 
    499 bool RenderThemeGtk::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
    500 {
    501     return paintTextField(o, i, rect);
    502 }
    503 
    504 void RenderThemeGtk::adjustSliderThumbSize(RenderObject* o) const
    505 {
    506 #if ENABLE(VIDEO)
    507     if (o->style()->appearance() == MediaSliderThumbPart) {
    508         o->style()->setWidth(Length(m_mediaSliderThumbWidth, Fixed));
    509         o->style()->setHeight(Length(m_mediaSliderThumbHeight, Fixed));
    510     }
    511 #endif
    512 }
    513 
    514 Color RenderThemeGtk::platformActiveSelectionBackgroundColor() const
    515 {
    516     GtkWidget* widget = gtkEntry();
    517     return widget->style->base[GTK_STATE_SELECTED];
    518 }
    519 
    520 Color RenderThemeGtk::platformInactiveSelectionBackgroundColor() const
    521 {
    522     GtkWidget* widget = gtkEntry();
    523     return widget->style->base[GTK_STATE_ACTIVE];
    524 }
    525 
    526 Color RenderThemeGtk::platformActiveSelectionForegroundColor() const
    527 {
    528     GtkWidget* widget = gtkEntry();
    529     return widget->style->text[GTK_STATE_SELECTED];
    530 }
    531 
    532 Color RenderThemeGtk::platformInactiveSelectionForegroundColor() const
    533 {
    534     GtkWidget* widget = gtkEntry();
    535     return widget->style->text[GTK_STATE_ACTIVE];
    536 }
    537 
    538 Color RenderThemeGtk::activeListBoxSelectionBackgroundColor() const
    539 {
    540     GtkWidget* widget = gtkTreeView();
    541     return widget->style->base[GTK_STATE_SELECTED];
    542 }
    543 
    544 Color RenderThemeGtk::inactiveListBoxSelectionBackgroundColor() const
    545 {
    546     GtkWidget* widget = gtkTreeView();
    547     return widget->style->base[GTK_STATE_ACTIVE];
    548 }
    549 
    550 Color RenderThemeGtk::activeListBoxSelectionForegroundColor() const
    551 {
    552     GtkWidget* widget = gtkTreeView();
    553     return widget->style->text[GTK_STATE_SELECTED];
    554 }
    555 
    556 Color RenderThemeGtk::inactiveListBoxSelectionForegroundColor() const
    557 {
    558     GtkWidget* widget = gtkTreeView();
    559     return widget->style->text[GTK_STATE_ACTIVE];
    560 }
    561 
    562 double RenderThemeGtk::caretBlinkInterval() const
    563 {
    564     GtkSettings* settings = gtk_settings_get_default();
    565 
    566     gboolean shouldBlink;
    567     gint time;
    568 
    569     g_object_get(settings, "gtk-cursor-blink", &shouldBlink, "gtk-cursor-blink-time", &time, NULL);
    570 
    571     if (!shouldBlink)
    572         return 0;
    573 
    574     return time / 2000.;
    575 }
    576 
    577 void RenderThemeGtk::systemFont(int, FontDescription&) const
    578 {
    579     // If you remove this notImplemented(), replace it with an comment that explains why.
    580     notImplemented();
    581 }
    582 
    583 static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, RenderTheme* renderTheme)
    584 {
    585     // FIXME: Make sure this function doesn't get called many times for a single GTK+ style change signal.
    586     renderTheme->platformColorsDidChange();
    587 }
    588 
    589 GtkContainer* RenderThemeGtk::gtkContainer() const
    590 {
    591     if (m_gtkContainer)
    592         return m_gtkContainer;
    593 
    594     m_gtkWindow = gtk_window_new(GTK_WINDOW_POPUP);
    595     m_gtkContainer = GTK_CONTAINER(gtk_fixed_new());
    596     g_signal_connect(m_gtkWindow, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this));
    597     gtk_container_add(GTK_CONTAINER(m_gtkWindow), GTK_WIDGET(m_gtkContainer));
    598     gtk_widget_realize(m_gtkWindow);
    599 
    600     return m_gtkContainer;
    601 }
    602 
    603 GtkWidget* RenderThemeGtk::gtkEntry() const
    604 {
    605     if (m_gtkEntry)
    606         return m_gtkEntry;
    607 
    608     m_gtkEntry = gtk_entry_new();
    609     g_signal_connect(m_gtkEntry, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this));
    610     gtk_container_add(gtkContainer(), m_gtkEntry);
    611     gtk_widget_realize(m_gtkEntry);
    612 
    613     return m_gtkEntry;
    614 }
    615 
    616 GtkWidget* RenderThemeGtk::gtkTreeView() const
    617 {
    618     if (m_gtkTreeView)
    619         return m_gtkTreeView;
    620 
    621     m_gtkTreeView = gtk_tree_view_new();
    622     g_signal_connect(m_gtkTreeView, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this));
    623     gtk_container_add(gtkContainer(), m_gtkTreeView);
    624     gtk_widget_realize(m_gtkTreeView);
    625 
    626     return m_gtkTreeView;
    627 }
    628 
    629 void RenderThemeGtk::platformColorsDidChange()
    630 {
    631 #if ENABLE(VIDEO)
    632     initMediaStyling(gtk_rc_get_style(GTK_WIDGET(gtkContainer())), true);
    633 #endif
    634     RenderTheme::platformColorsDidChange();
    635 }
    636 
    637 #if ENABLE(VIDEO)
    638 String RenderThemeGtk::extraMediaControlsStyleSheet()
    639 {
    640     return String(mediaControlsGtkUserAgentStyleSheet, sizeof(mediaControlsGtkUserAgentStyleSheet));
    641 }
    642 
    643 static inline bool paintMediaButton(GraphicsContext* context, const IntRect& r, Image* image, Color panelColor, int mediaIconSize)
    644 {
    645     context->fillRect(FloatRect(r), panelColor, DeviceColorSpace);
    646     context->drawImage(image, DeviceColorSpace,
    647                        IntRect(r.x() + (r.width() - mediaIconSize) / 2,
    648                                r.y() + (r.height() - mediaIconSize) / 2,
    649                                mediaIconSize, mediaIconSize));
    650 
    651     return false;
    652 }
    653 
    654 bool RenderThemeGtk::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    655 {
    656     return paintMediaButton(paintInfo.context, r, m_fullscreenButton.get(), m_panelColor, m_mediaIconSize);
    657 }
    658 
    659 bool RenderThemeGtk::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    660 {
    661     HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o);
    662     if (!mediaElement)
    663         return false;
    664 
    665     return paintMediaButton(paintInfo.context, r, mediaElement->muted() ? m_unmuteButton.get() : m_muteButton.get(), m_panelColor, m_mediaIconSize);
    666 }
    667 
    668 bool RenderThemeGtk::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    669 {
    670     HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o);
    671     if (!mediaElement)
    672         return false;
    673 
    674     return paintMediaButton(paintInfo.context, r, mediaElement->canPlay() ? m_playButton.get() : m_pauseButton.get(), m_panelColor, m_mediaIconSize);
    675 }
    676 
    677 bool RenderThemeGtk::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    678 {
    679     return paintMediaButton(paintInfo.context, r, m_seekBackButton.get(), m_panelColor, m_mediaIconSize);
    680 }
    681 
    682 bool RenderThemeGtk::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    683 {
    684     return paintMediaButton(paintInfo.context, r, m_seekForwardButton.get(), m_panelColor, m_mediaIconSize);
    685 }
    686 
    687 bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    688 {
    689     paintInfo.context->fillRect(FloatRect(r), m_panelColor, DeviceColorSpace);
    690     paintInfo.context->fillRect(FloatRect(IntRect(r.x(), r.y() + (r.height() - m_mediaSliderHeight) / 2,
    691                                                   r.width(), m_mediaSliderHeight)), m_sliderColor, DeviceColorSpace);
    692     return false;
    693 }
    694 
    695 bool RenderThemeGtk::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
    696 {
    697     // Make the thumb nicer with rounded corners.
    698     paintInfo.context->fillRoundedRect(r, IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), m_sliderThumbColor, DeviceColorSpace);
    699     return false;
    700 }
    701 #endif
    702 
    703 }
    704