summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/gtk/RenderThemeGtk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/gtk/RenderThemeGtk.cpp')
-rw-r--r--WebCore/platform/gtk/RenderThemeGtk.cpp325
1 files changed, 269 insertions, 56 deletions
diff --git a/WebCore/platform/gtk/RenderThemeGtk.cpp b/WebCore/platform/gtk/RenderThemeGtk.cpp
index 4842d68..0c157cf 100644
--- a/WebCore/platform/gtk/RenderThemeGtk.cpp
+++ b/WebCore/platform/gtk/RenderThemeGtk.cpp
@@ -24,17 +24,87 @@
#include "config.h"
#include "RenderThemeGtk.h"
-#include "TransformationMatrix.h"
+#include "CString.h"
+#include "GOwnPtr.h"
#include "GraphicsContext.h"
+#include "HTMLMediaElement.h"
+#include "HTMLNames.h"
#include "NotImplemented.h"
#include "RenderBox.h"
#include "RenderObject.h"
+#include "TransformationMatrix.h"
+#include "UserAgentStyleSheets.h"
#include "gtkdrawing.h"
#include <gdk/gdk.h>
+#include <gtk/gtk.h>
namespace WebCore {
+using namespace HTMLNames;
+
+#if ENABLE(VIDEO)
+static HTMLMediaElement* getMediaElementFromRenderObject(RenderObject* o)
+{
+ Node* node = o->node();
+ Node* mediaNode = node ? node->shadowAncestorNode() : 0;
+ if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
+ return 0;
+
+ return static_cast<HTMLMediaElement*>(mediaNode);
+}
+
+static gchar* getIconNameForTextDirection(const char* baseName)
+{
+ GString* nameWithDirection = g_string_new(baseName);
+ GtkTextDirection textDirection = gtk_widget_get_default_direction();
+
+ if (textDirection == GTK_TEXT_DIR_RTL)
+ g_string_append(nameWithDirection, "-rtl");
+ else if (textDirection == GTK_TEXT_DIR_LTR)
+ g_string_append(nameWithDirection, "-ltr");
+
+ return g_string_free(nameWithDirection, FALSE);
+}
+
+void RenderThemeGtk::initMediaStyling(GtkStyle* style, bool force)
+{
+ static bool stylingInitialized = false;
+
+ if (!stylingInitialized || force) {
+ m_panelColor = style->bg[GTK_STATE_NORMAL];
+ m_sliderColor = style->bg[GTK_STATE_ACTIVE];
+ m_sliderThumbColor = style->bg[GTK_STATE_SELECTED];
+
+ // Names of these icons can vary because of text direction.
+ gchar* playButtonIconName = getIconNameForTextDirection("gtk-media-play");
+ gchar* seekBackButtonIconName = getIconNameForTextDirection("gtk-media-rewind");
+ gchar* seekForwardButtonIconName = getIconNameForTextDirection("gtk-media-forward");
+
+ m_fullscreenButton.clear();
+ m_muteButton.clear();
+ m_unmuteButton.clear();
+ m_playButton.clear();
+ m_pauseButton.clear();
+ m_seekBackButton.clear();
+ m_seekForwardButton.clear();
+
+ m_fullscreenButton = Image::loadPlatformThemeIcon("gtk-fullscreen", m_mediaIconSize);
+ m_muteButton = Image::loadPlatformThemeIcon("audio-volume-muted", m_mediaIconSize);
+ m_unmuteButton = Image::loadPlatformThemeIcon("audio-volume-high", m_mediaIconSize);
+ m_playButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(playButtonIconName), m_mediaIconSize);
+ m_pauseButton = Image::loadPlatformThemeIcon("gtk-media-pause", m_mediaIconSize).releaseRef();
+ m_seekBackButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(seekBackButtonIconName), m_mediaIconSize);
+ m_seekForwardButton = Image::loadPlatformThemeIcon(reinterpret_cast<const char*>(seekForwardButtonIconName), m_mediaIconSize);
+
+ g_free(playButtonIconName);
+ g_free(seekBackButtonIconName);
+ g_free(seekForwardButtonIconName);
+ stylingInitialized = true;
+ }
+}
+#endif
+
PassRefPtr<RenderTheme> RenderThemeGtk::create()
{
return adoptRef(new RenderThemeGtk());
@@ -53,11 +123,34 @@ RenderThemeGtk::RenderThemeGtk()
, m_gtkContainer(0)
, m_gtkEntry(0)
, m_gtkTreeView(0)
-{
- if (!mozGtkRefCount)
+ , m_panelColor(Color::white)
+ , m_sliderColor(Color::white)
+ , m_sliderThumbColor(Color::white)
+ , m_mediaIconSize(16)
+ , m_mediaSliderHeight(14)
+ , m_mediaSliderThumbWidth(12)
+ , m_mediaSliderThumbHeight(12)
+ , m_fullscreenButton(0)
+ , m_muteButton(0)
+ , m_unmuteButton(0)
+ , m_playButton(0)
+ , m_pauseButton(0)
+ , m_seekBackButton(0)
+ , m_seekForwardButton(0)
+ , m_partsTable(adoptGRef(g_hash_table_new_full(0, 0, 0, g_free)))
+{
+ if (!mozGtkRefCount) {
moz_gtk_init();
+ // Use the theme parts for the default drawable.
+ moz_gtk_use_theme_parts(partsForDrawable(0));
+ }
+
++mozGtkRefCount;
+
+#if ENABLE(VIDEO)
+ initMediaStyling(gtk_rc_get_style(GTK_WIDGET(gtkContainer())), false);
+#endif
}
RenderThemeGtk::~RenderThemeGtk()
@@ -66,22 +159,54 @@ RenderThemeGtk::~RenderThemeGtk()
if (!mozGtkRefCount)
moz_gtk_shutdown();
+
+ m_fullscreenButton.clear();
+ m_muteButton.clear();
+ m_unmuteButton.clear();
+ m_playButton.clear();
+ m_pauseButton.clear();
+ m_seekBackButton.clear();
+ m_seekForwardButton.clear();
+
+ GList* values = g_hash_table_get_values(m_partsTable.get());
+ for (guint i = 0; i < g_list_length(values); i++)
+ moz_gtk_destroy_theme_parts_widgets(
+ static_cast<GtkThemeParts*>(g_list_nth_data(values, i)));
+}
+
+GtkThemeParts* RenderThemeGtk::partsForDrawable(GdkDrawable* drawable) const
+{
+ // A null drawable represents the default screen colormap.
+ GdkColormap* colormap = 0;
+ if (!drawable)
+ colormap = gdk_screen_get_default_colormap(gdk_screen_get_default());
+ else
+ colormap = gdk_drawable_get_colormap(drawable);
+
+ GtkThemeParts* parts = static_cast<GtkThemeParts*>(g_hash_table_lookup(m_partsTable.get(), colormap));
+ if (!parts) {
+ parts = g_new0(GtkThemeParts, 1);
+ parts->colormap = colormap;
+ g_hash_table_insert(m_partsTable.get(), colormap, parts);
+ }
+
+ return parts;
}
static bool supportsFocus(ControlPart appearance)
{
switch (appearance) {
- case PushButtonPart:
- case ButtonPart:
- case TextFieldPart:
- case TextAreaPart:
- case SearchFieldPart:
- case MenulistPart:
- case RadioPart:
- case CheckboxPart:
- return true;
- default:
- return false;
+ case PushButtonPart:
+ case ButtonPart:
+ case TextFieldPart:
+ case TextAreaPart:
+ case SearchFieldPart:
+ case MenulistPart:
+ case RadioPart:
+ case CheckboxPart:
+ return true;
+ default:
+ return false;
}
}
@@ -101,8 +226,8 @@ int RenderThemeGtk::baselinePosition(const RenderObject* o) const
return 0;
// FIXME: This strategy is possibly incorrect for the GTK+ port.
- if (o->style()->appearance() == CheckboxPart ||
- o->style()->appearance() == RadioPart) {
+ if (o->style()->appearance() == CheckboxPart
+ || o->style()->appearance() == RadioPart) {
const RenderBox* box = toRenderBox(o);
return box->marginTop() + box->height() - 2;
}
@@ -122,7 +247,7 @@ static GtkTextDirection gtkTextDirection(TextDirection direction)
}
}
-static void adjustMozStyle(RenderStyle* style, GtkThemeWidgetType type)
+static void adjustMozillaStyle(const RenderThemeGtk* theme, RenderStyle* style, GtkThemeWidgetType type)
{
gint left, top, right, bottom;
GtkTextDirection direction = gtkTextDirection(style->direction());
@@ -141,7 +266,7 @@ static void adjustMozStyle(RenderStyle* style, GtkThemeWidgetType type)
style->setPaddingBottom(Length(ypadding + bottom, Fixed));
}
-static void setMozState(RenderTheme* theme, GtkWidgetState* state, RenderObject* o)
+static void setMozillaState(const RenderTheme* theme, GtkWidgetState* state, RenderObject* o)
{
state->active = theme->isPressed(o);
state->focused = theme->isFocused(o);
@@ -153,7 +278,7 @@ static void setMozState(RenderTheme* theme, GtkWidgetState* state, RenderObject*
state->depressed = false;
}
-static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
+static bool paintMozillaGtkWidget(const RenderThemeGtk* theme, GtkThemeWidgetType type, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
// No GdkWindow to render to, so return true to fall back
if (!i.context->gdkDrawable())
@@ -164,22 +289,22 @@ static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderOb
return false;
GtkWidgetState mozState;
- setMozState(theme, &mozState, o);
+ setMozillaState(theme, &mozState, o);
int flags;
// We might want to make setting flags the caller's job at some point rather than doing it here.
switch (type) {
- case MOZ_GTK_BUTTON:
- flags = GTK_RELIEF_NORMAL;
- break;
- case MOZ_GTK_CHECKBUTTON:
- case MOZ_GTK_RADIOBUTTON:
- flags = theme->isChecked(o);
- break;
- default:
- flags = 0;
- break;
+ case MOZ_GTK_BUTTON:
+ flags = GTK_RELIEF_NORMAL;
+ break;
+ case MOZ_GTK_CHECKBUTTON:
+ case MOZ_GTK_RADIOBUTTON:
+ flags = theme->isChecked(o);
+ break;
+ default:
+ flags = 0;
+ break;
}
TransformationMatrix ctm = i.context->getCTM();
@@ -189,7 +314,7 @@ static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderOb
GtkTextDirection direction = gtkTextDirection(o->style()->direction());
// Find the clip rectangle
- cairo_t *cr = i.context->platformContext();
+ cairo_t* cr = i.context->platformContext();
double clipX1, clipX2, clipY1, clipY2;
cairo_clip_extents(cr, &clipX1, &clipY1, &clipX2, &clipY2);
@@ -202,6 +327,9 @@ static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderOb
gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect);
+ // Since the theme renderer is going to be drawing onto this GdkDrawable,
+ // select the appropriate widgets for the drawable depth.
+ moz_gtk_use_theme_parts(theme->partsForDrawable(i.context->gdkDrawable()));
return moz_gtk_widget_paint(type, i.context->gdkDrawable(), &gdkRect, &gdkClipRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS;
}
@@ -215,31 +343,31 @@ static void setButtonPadding(RenderStyle* style)
style->setPaddingBottom(Length(padding / 2, Fixed));
}
-static void setToggleSize(RenderStyle* style, ControlPart appearance)
+static void setToggleSize(const RenderThemeGtk* theme, RenderStyle* style, ControlPart appearance)
{
// The width and height are both specified, so we shouldn't change them.
if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
return;
- // FIXME: This is probably not correct use of indicator_size and indicator_spacing.
- gint indicator_size, indicator_spacing;
+ // FIXME: This is probably not correct use of indicatorSize and indicatorSpacing.
+ gint indicatorSize, indicatorSpacing;
switch (appearance) {
- case CheckboxPart:
- if (moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing) != MOZ_GTK_SUCCESS)
- return;
- break;
- case RadioPart:
- if (moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing) != MOZ_GTK_SUCCESS)
- return;
- break;
- default:
+ case CheckboxPart:
+ if (moz_gtk_checkbox_get_metrics(&indicatorSize, &indicatorSpacing) != MOZ_GTK_SUCCESS)
return;
+ break;
+ case RadioPart:
+ if (moz_gtk_radio_get_metrics(&indicatorSize, &indicatorSpacing) != MOZ_GTK_SUCCESS)
+ return;
+ break;
+ default:
+ return;
}
// Other ports hard-code this to 13, but GTK+ users tend to demand the native look.
// It could be made a configuration option values other than 13 actually break site compatibility.
- int length = indicator_size + indicator_spacing;
+ int length = indicatorSize + indicatorSpacing;
if (style->width().isIntrinsicOrAuto())
style->setWidth(Length(length, Fixed));
@@ -249,22 +377,22 @@ static void setToggleSize(RenderStyle* style, ControlPart appearance)
void RenderThemeGtk::setCheckboxSize(RenderStyle* style) const
{
- setToggleSize(style, RadioPart);
+ setToggleSize(this, style, RadioPart);
}
bool RenderThemeGtk::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
- return paintMozWidget(this, MOZ_GTK_CHECKBUTTON, o, i, rect);
+ return paintMozillaGtkWidget(this, MOZ_GTK_CHECKBUTTON, o, i, rect);
}
void RenderThemeGtk::setRadioSize(RenderStyle* style) const
{
- setToggleSize(style, RadioPart);
+ setToggleSize(this, style, RadioPart);
}
bool RenderThemeGtk::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
- return paintMozWidget(this, MOZ_GTK_RADIOBUTTON, o, i, rect);
+ return paintMozillaGtkWidget(this, MOZ_GTK_RADIOBUTTON, o, i, rect);
}
void RenderThemeGtk::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
@@ -285,7 +413,7 @@ void RenderThemeGtk::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle*
bool RenderThemeGtk::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
- return paintMozWidget(this, MOZ_GTK_BUTTON, o, i, rect);
+ return paintMozillaGtkWidget(this, MOZ_GTK_BUTTON, o, i, rect);
}
void RenderThemeGtk::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
@@ -294,12 +422,12 @@ void RenderThemeGtk::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle
style->resetPadding();
style->setHeight(Length(Auto));
style->setWhiteSpace(PRE);
- adjustMozStyle(style, MOZ_GTK_DROPDOWN);
+ adjustMozillaStyle(this, style, MOZ_GTK_DROPDOWN);
}
bool RenderThemeGtk::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
- return paintMozWidget(this, MOZ_GTK_DROPDOWN, o, i, rect);
+ return paintMozillaGtkWidget(this, MOZ_GTK_DROPDOWN, o, i, rect);
}
void RenderThemeGtk::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
@@ -308,12 +436,12 @@ void RenderThemeGtk::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyl
style->resetPadding();
style->setHeight(Length(Auto));
style->setWhiteSpace(PRE);
- adjustMozStyle(style, MOZ_GTK_ENTRY);
+ adjustMozillaStyle(this, style, MOZ_GTK_ENTRY);
}
bool RenderThemeGtk::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
- return paintMozWidget(this, MOZ_GTK_ENTRY, o, i, rect);
+ return paintMozillaGtkWidget(this, MOZ_GTK_ENTRY, o, i, rect);
}
bool RenderThemeGtk::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
@@ -328,7 +456,7 @@ void RenderThemeGtk::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selec
bool RenderThemeGtk::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
- return paintMozWidget(this, MOZ_GTK_DROPDOWN_ARROW, o, i, rect);
+ return paintMozillaGtkWidget(this, MOZ_GTK_DROPDOWN_ARROW, o, i, rect);
}
void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
@@ -344,7 +472,7 @@ void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* s
bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
- return paintMozWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect);
+ return paintMozillaGtkWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect);
}
void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
@@ -360,7 +488,7 @@ void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* select
bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect)
{
- return paintMozWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect);
+ return paintMozillaGtkWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect);
}
void RenderThemeGtk::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
@@ -373,6 +501,16 @@ bool RenderThemeGtk::paintSearchField(RenderObject* o, const RenderObject::Paint
return paintTextField(o, i, rect);
}
+void RenderThemeGtk::adjustSliderThumbSize(RenderObject* o) const
+{
+#if ENABLE(VIDEO)
+ if (o->style()->appearance() == MediaSliderThumbPart) {
+ o->style()->setWidth(Length(m_mediaSliderThumbWidth, Fixed));
+ o->style()->setHeight(Length(m_mediaSliderThumbHeight, Fixed));
+ }
+#endif
+}
+
Color RenderThemeGtk::platformActiveSelectionBackgroundColor() const
{
GtkWidget* widget = gtkEntry();
@@ -455,6 +593,7 @@ GtkContainer* RenderThemeGtk::gtkContainer() const
m_gtkWindow = gtk_window_new(GTK_WINDOW_POPUP);
m_gtkContainer = GTK_CONTAINER(gtk_fixed_new());
+ g_signal_connect(m_gtkWindow, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this));
gtk_container_add(GTK_CONTAINER(m_gtkWindow), GTK_WIDGET(m_gtkContainer));
gtk_widget_realize(m_gtkWindow);
@@ -487,4 +626,78 @@ GtkWidget* RenderThemeGtk::gtkTreeView() const
return m_gtkTreeView;
}
+void RenderThemeGtk::platformColorsDidChange()
+{
+#if ENABLE(VIDEO)
+ initMediaStyling(gtk_rc_get_style(GTK_WIDGET(gtkContainer())), true);
+#endif
+ RenderTheme::platformColorsDidChange();
+}
+
+#if ENABLE(VIDEO)
+String RenderThemeGtk::extraMediaControlsStyleSheet()
+{
+ return String(mediaControlsGtkUserAgentStyleSheet, sizeof(mediaControlsGtkUserAgentStyleSheet));
+}
+
+static inline bool paintMediaButton(GraphicsContext* context, const IntRect& r, Image* image, Color panelColor, int mediaIconSize)
+{
+ context->fillRect(FloatRect(r), panelColor, DeviceColorSpace);
+ context->drawImage(image, DeviceColorSpace,
+ IntRect(r.x() + (r.width() - mediaIconSize) / 2,
+ r.y() + (r.height() - mediaIconSize) / 2,
+ mediaIconSize, mediaIconSize));
+
+ return false;
+}
+
+bool RenderThemeGtk::paintMediaFullscreenButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ return paintMediaButton(paintInfo.context, r, m_fullscreenButton.get(), m_panelColor, m_mediaIconSize);
+}
+
+bool RenderThemeGtk::paintMediaMuteButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o);
+ if (!mediaElement)
+ return false;
+
+ return paintMediaButton(paintInfo.context, r, mediaElement->muted() ? m_unmuteButton.get() : m_muteButton.get(), m_panelColor, m_mediaIconSize);
+}
+
+bool RenderThemeGtk::paintMediaPlayButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(o);
+ if (!mediaElement)
+ return false;
+
+ return paintMediaButton(paintInfo.context, r, mediaElement->canPlay() ? m_playButton.get() : m_pauseButton.get(), m_panelColor, m_mediaIconSize);
+}
+
+bool RenderThemeGtk::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ return paintMediaButton(paintInfo.context, r, m_seekBackButton.get(), m_panelColor, m_mediaIconSize);
+}
+
+bool RenderThemeGtk::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ return paintMediaButton(paintInfo.context, r, m_seekForwardButton.get(), m_panelColor, m_mediaIconSize);
+}
+
+bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ paintInfo.context->fillRect(FloatRect(r), m_panelColor, DeviceColorSpace);
+ paintInfo.context->fillRect(FloatRect(IntRect(r.x(), r.y() + (r.height() - m_mediaSliderHeight) / 2,
+ r.width(), m_mediaSliderHeight)), m_sliderColor, DeviceColorSpace);
+ return false;
+}
+
+bool RenderThemeGtk::paintMediaSliderThumb(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r)
+{
+ // Make the thumb nicer with rounded corners.
+ paintInfo.context->fillRoundedRect(r, IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), m_sliderThumbColor, DeviceColorSpace);
+ return false;
+}
+#endif
+
}