bool RenderThemeGtk::paintMediaToggleClosedCaptionsButton(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect) { IntRect iconRect(rect.x() + (rect.width() - m_mediaIconSize) / 2, rect.y() + (rect.height() - m_mediaIconSize) / 2, m_mediaIconSize, m_mediaIconSize); GRefPtr<GdkPixbuf> icon = getStockSymbolicIconForWidgetType(GTK_TYPE_CONTAINER, "media-view-subtitles-symbolic", nullptr, gtkTextDirection(renderObject.style().direction()), gtkIconState(this, renderObject), iconRect.width()); if (!icon) icon = getStockSymbolicIconForWidgetType(GTK_TYPE_CONTAINER, "user-invisible-symbolic", GTK_STOCK_JUSTIFY_FILL, gtkTextDirection(renderObject.style().direction()), gtkIconState(this, renderObject), iconRect.width()); paintGdkPixbuf(paintInfo.context, icon.get(), iconRect); return true; }
bool RenderThemeGtk::paintRenderObject(GtkThemeWidgetType type, RenderObject* renderObject, GraphicsContext* context, const IntRect& rect, int flags) { // Painting is disabled so just claim to have succeeded if (context->paintingDisabled()) return false; GtkWidgetState widgetState; widgetState.active = isPressed(renderObject); widgetState.focused = isFocused(renderObject); // https://bugs.webkit.org/show_bug.cgi?id=18364 // The Mozilla theme drawing code, only paints a button as pressed when it's pressed // while hovered. Until we move away from the Mozila code, work-around the issue by // forcing a pressed button into the hovered state. This ensures that buttons activated // via the keyboard have the proper rendering. widgetState.inHover = isHovered(renderObject) || (type == MOZ_GTK_BUTTON && isPressed(renderObject)); // FIXME: Disabled does not always give the correct appearance for ReadOnly widgetState.disabled = !isEnabled(renderObject) || isReadOnlyControl(renderObject); widgetState.isDefault = false; widgetState.canDefault = false; widgetState.depressed = false; WidgetRenderingContext widgetContext(context, rect); return !widgetContext.paintMozillaWidget(type, &widgetState, flags, gtkTextDirection(renderObject->style()->direction())); }
bool RenderThemeGtk::paintSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect) { if (info.context->paintingDisabled()) return false; ControlPart part = object->style()->appearance(); ASSERT(part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart); GtkWidget* widget = 0; const char* detail = 0; GtkOrientation orientation; if (part == SliderThumbVerticalPart) { widget = gtkVScale(); detail = "vscale"; orientation = GTK_ORIENTATION_VERTICAL; } else { widget = gtkHScale(); detail = "hscale"; orientation = GTK_ORIENTATION_HORIZONTAL; } gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction())); // Only some themes have slider thumbs respond to clicks and some don't. This information is // gathered via the 'activate-slider' property, but it's deprecated in GTK+ 2.22 and removed in // GTK+ 3.x. The drawback of not honoring it is that slider thumbs change color when you click // on them. IntRect thumbRect(IntPoint(), rect.size()); WidgetRenderingContext widgetContext(info.context, rect); widgetContext.gtkPaintSlider(thumbRect, widget, getGtkStateType(object), GTK_SHADOW_OUT, detail, orientation); return false; }
bool RenderThemeGtk::paintSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect) { if (info.context->paintingDisabled()) return false; ControlPart part = object->style()->appearance(); ASSERT(part == SliderHorizontalPart || part == SliderVerticalPart); // We shrink the trough rect slightly to make room for the focus indicator. IntRect troughRect(IntPoint(), rect.size()); // This is relative to rect. GtkWidget* widget = 0; if (part == SliderVerticalPart) { widget = gtkVScale(); troughRect.inflateY(-gtk_widget_get_style(widget)->ythickness); } else { widget = gtkHScale(); troughRect.inflateX(-gtk_widget_get_style(widget)->xthickness); } gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction())); WidgetRenderingContext widgetContext(info.context, rect); widgetContext.gtkPaintBox(troughRect, widget, GTK_STATE_ACTIVE, GTK_SHADOW_OUT, "trough"); if (isFocused(object)) widgetContext.gtkPaintFocus(IntRect(IntPoint(), rect.size()), widget, getGtkStateType(object), "trough"); return false; }
static void getComboBoxPadding(RenderStyle* style, int& left, int& top, int& right, int& bottom) { // If this menu list button isn't drawn using the native theme, we // don't add any extra padding beyond what WebCore already uses. if (style->appearance() == NoControlPart) return; moz_gtk_get_widget_border(MOZ_GTK_DROPDOWN, &left, &top, &right, &bottom, gtkTextDirection(style->direction()), TRUE); }
bool RenderThemeGtk::paintMediaButton(const RenderObject& renderObject, GraphicsContext* context, const IntRect& rect, const char* symbolicIconName, const char* fallbackStockIconName) { IntRect iconRect(rect.x() + (rect.width() - m_mediaIconSize) / 2, rect.y() + (rect.height() - m_mediaIconSize) / 2, m_mediaIconSize, m_mediaIconSize); GRefPtr<GdkPixbuf> icon = getStockSymbolicIconForWidgetType(GTK_TYPE_CONTAINER, symbolicIconName, fallbackStockIconName, gtkTextDirection(renderObject.style().direction()), gtkIconState(this, renderObject), iconRect.width()); paintGdkPixbuf(context, icon.get(), iconRect); return true; }
bool RenderThemeGtk::paintSearchFieldCancelButton(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect) { IntRect iconRect = centerRectVerticallyInParentInputElement(renderObject, rect); if (iconRect.isEmpty()) return false; GRefPtr<GdkPixbuf> icon = getStockIconForWidgetType(GTK_TYPE_ENTRY, GTK_STOCK_CLEAR, gtkTextDirection(renderObject.style().direction()), gtkIconState(this, renderObject), getIconSizeForPixelSize(rect.height())); paintGdkPixbuf(paintInfo.context, icon.get(), iconRect); return false; }
bool RenderThemeGtk::paintButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) { if (info.context->paintingDisabled()) return false; GtkWidget* widget = gtkButton(); IntRect buttonRect(IntPoint(), rect.size()); IntRect focusRect(buttonRect); GtkStateType state = getGtkStateType(object); gtk_widget_set_state(widget, state); gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction())); if (isFocused(object)) { if (isEnabled(object)) { #if !GTK_CHECK_VERSION(2, 22, 0) GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); #endif g_object_set(widget, "has-focus", TRUE, NULL); } gboolean interiorFocus = 0, focusWidth = 0, focusPadding = 0; gtk_widget_style_get(widget, "interior-focus", &interiorFocus, "focus-line-width", &focusWidth, "focus-padding", &focusPadding, NULL); // If we are using exterior focus, we shrink the button rect down before // drawing. If we are using interior focus we shrink the focus rect. This // approach originates from the Mozilla theme drawing code (gtk2drawing.c). if (interiorFocus) { GtkStyle* style = gtk_widget_get_style(widget); focusRect.inflateX(-style->xthickness - focusPadding); focusRect.inflateY(-style->ythickness - focusPadding); } else { buttonRect.inflateX(-focusWidth - focusPadding); buttonRect.inflateY(-focusPadding - focusPadding); } } WidgetRenderingContext widgetContext(info.context, rect); GtkShadowType shadowType = state == GTK_STATE_ACTIVE ? GTK_SHADOW_IN : GTK_SHADOW_OUT; widgetContext.gtkPaintBox(buttonRect, widget, state, shadowType, "button"); if (isFocused(object)) widgetContext.gtkPaintFocus(focusRect, widget, state, "button"); #if !GTK_CHECK_VERSION(2, 22, 0) GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); #endif g_object_set(widget, "has-focus", FALSE, NULL); return false; }
static bool paintMozWidget(RenderTheme* 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()) return true; // Painting is disabled so just claim to have succeeded if (i.context->paintingDisabled()) return false; GtkWidgetState mozState; setMozState(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; } AffineTransform ctm = i.context->getCTM(); IntPoint pos = ctm.mapPoint(rect.location()); GdkRectangle gdkRect = IntRect(pos.x(), pos.y(), rect.width(), rect.height()); GtkTextDirection direction = gtkTextDirection(o->style()->direction()); // Find the clip rectangle cairo_t *cr = i.context->platformContext(); double clipX1, clipX2, clipY1, clipY2; cairo_clip_extents(cr, &clipX1, &clipY1, &clipX2, &clipY2); GdkRectangle gdkClipRect; gdkClipRect.width = clipX2 - clipX1; gdkClipRect.height = clipY2 - clipY1; IntPoint clipPos = ctm.mapPoint(IntPoint(clipX1, clipY1)); gdkClipRect.x = clipPos.x(); gdkClipRect.y = clipPos.y(); gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect); return moz_gtk_widget_paint(type, i.context->gdkDrawable(), &gdkRect, &gdkClipRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS; }
void RenderThemeGtk::setTextInputBorders(RenderStyle* style) { // If this control isn't drawn using the native theme, we don't touch the borders. if (style->appearance() == NoControlPart) return; // We cannot give a proper rendering when border radius is active, unfortunately. style->resetBorderRadius(); int left = 0, top = 0, right = 0, bottom = 0; moz_gtk_get_widget_border(MOZ_GTK_ENTRY, &left, &top, &right, &bottom, gtkTextDirection(style->direction()), TRUE); style->setBorderLeftWidth(left); style->setBorderTopWidth(top); style->setBorderRightWidth(right); style->setBorderBottomWidth(bottom); }
static void adjustMozStyle(RenderStyle* style, GtkThemeWidgetType type) { gint left, top, right, bottom; GtkTextDirection direction = gtkTextDirection(style->direction()); gboolean inhtml = true; if (moz_gtk_get_widget_border(type, &left, &top, &right, &bottom, direction, inhtml) != MOZ_GTK_SUCCESS) return; // FIXME: This approach is likely to be incorrect. See other ports and layout tests to see the problem. const int xpadding = 1; const int ypadding = 1; style->setPaddingLeft(Length(xpadding + left, Fixed)); style->setPaddingTop(Length(ypadding + top, Fixed)); style->setPaddingRight(Length(xpadding + right, Fixed)); style->setPaddingBottom(Length(ypadding + bottom, Fixed)); }
bool RenderThemeGtk::paintTextField(RenderObject* renderObject, const PaintInfo& info, const IntRect& rect) { GtkWidget* widget = gtkEntry(); bool enabled = isEnabled(renderObject) && !isReadOnlyControl(renderObject); GtkStateType backgroundState = enabled ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE; gtk_widget_set_sensitive(widget, enabled); gtk_widget_set_direction(widget, gtkTextDirection(renderObject->style().direction())); setWidgetHasFocus(widget, isFocused(renderObject)); WidgetRenderingContext widgetContext(info.context, rect); IntRect textFieldRect(IntPoint(), rect.size()); // The entry background is only painted over the interior part of the GTK+ entry, not // the entire frame. This happens in the Mozilla theme drawing code as well. IntRect interiorRect(textFieldRect); GtkStyle* style = gtk_widget_get_style(widget); interiorRect.inflateX(-style->xthickness); interiorRect.inflateY(-style->ythickness); widgetContext.gtkPaintFlatBox(interiorRect, widget, backgroundState, GTK_SHADOW_NONE, "entry_bg"); // This is responsible for drawing the actual frame. widgetContext.gtkPaintShadow(textFieldRect, widget, GTK_STATE_NORMAL, GTK_SHADOW_IN, "entry"); gboolean interiorFocus; gint focusWidth; gtk_widget_style_get(widget, "interior-focus", &interiorFocus, "focus-line-width", &focusWidth, NULL); if (isFocused(renderObject) && !interiorFocus) { // When GTK+ paints a text entry with focus, it shrinks the size of the frame area by the // focus width and paints over the previously unfocused text entry. We need to emulate that // by drawing both the unfocused frame above and the focused frame here. IntRect shadowRect(textFieldRect); shadowRect.inflate(-focusWidth); widgetContext.gtkPaintShadow(shadowRect, widget, GTK_STATE_NORMAL, GTK_SHADOW_IN, "entry"); widgetContext.gtkPaintFocus(textFieldRect, widget, GTK_STATE_NORMAL, "entry"); } return false; }
bool RenderThemeGtk::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { GtkWidget* widget = gtkProgressBar(); gtk_widget_set_direction(widget, gtkTextDirection(renderObject->style().direction())); WidgetRenderingContext widgetContext(paintInfo.context, rect); IntRect fullProgressBarRect(IntPoint(), rect.size()); widgetContext.gtkPaintBox(fullProgressBarRect, widget, GTK_STATE_NORMAL, GTK_SHADOW_IN, "trough"); GtkStyle* style = gtk_widget_get_style(widget); IntRect progressRect(fullProgressBarRect); progressRect.inflateX(-style->xthickness); progressRect.inflateY(-style->ythickness); progressRect = RenderThemeGtk::calculateProgressRect(renderObject, progressRect); if (!progressRect.isEmpty()) widgetContext.gtkPaintBox(progressRect, widget, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, "bar"); return false; }
static void paintToggle(RenderThemeGtk* theme, RenderObject* renderObject, const PaintInfo& info, const IntRect& rect, GtkWidget* widget) { // We do not call gtk_toggle_button_set_active here, because some themes begin a series of // animation frames in a "toggled" signal handler. This puts some checkboxes in a half-way // checked state. Every GTK+ theme I tested merely looks at the shadow type (and not the // 'active' property) to determine whether or not to draw the check. gtk_widget_set_sensitive(widget, theme->isEnabled(renderObject) && !theme->isReadOnlyControl(renderObject)); gtk_widget_set_direction(widget, gtkTextDirection(renderObject->style().direction())); bool indeterminate = theme->isIndeterminate(renderObject); gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(widget), indeterminate); GtkShadowType shadowType = GTK_SHADOW_OUT; if (indeterminate) // This originates from the Mozilla code. shadowType = GTK_SHADOW_ETCHED_IN; else if (theme->isChecked(renderObject)) shadowType = GTK_SHADOW_IN; WidgetRenderingContext widgetContext(info.context, rect); IntRect buttonRect(IntPoint(), rect.size()); GtkStateType toggleState = getGtkStateType(theme, renderObject); const char* detail = 0; if (GTK_IS_RADIO_BUTTON(widget)) { detail = "radiobutton"; widgetContext.gtkPaintOption(buttonRect, widget, toggleState, shadowType, detail); } else { detail = "checkbutton"; widgetContext.gtkPaintCheck(buttonRect, widget, toggleState, shadowType, detail); } if (theme->isFocused(renderObject)) { IntRect focusRect(buttonRect); adjustRectForFocus(widget, focusRect, true); widgetContext.gtkPaintFocus(focusRect, widget, toggleState, detail); } }
bool RenderThemeGtk::paintInnerSpinButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { // We expand the painted area by 2 pixels on the top and bottom and 2 pixels on the right. This // is because GTK+ themes want to draw over the text box borders, but WebCore renders the inner // spin button inside the text box. IntRect expandedRect(rect); expandedRect.inflateY(2); expandedRect.setWidth(rect.width() + 2); WidgetRenderingContext widgetContext(paintInfo.context, expandedRect); GtkWidget* widget = gtkSpinButton(); gtk_widget_set_direction(widget, gtkTextDirection(renderObject->style().direction())); IntRect fullSpinButtonRect(IntPoint(), expandedRect.size()); widgetContext.gtkPaintBox(fullSpinButtonRect, widget, GTK_STATE_NORMAL, GTK_SHADOW_IN, "spinbutton"); bool upPressed = isSpinUpButtonPartPressed(renderObject); bool upHovered = isSpinUpButtonPartHovered(renderObject); bool controlActive = isEnabled(renderObject) && !isReadOnlyControl(renderObject); GtkShadowType shadowType = upPressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; GtkStateType stateType = GTK_STATE_INSENSITIVE; if (controlActive) { if (isPressed(renderObject) && upPressed) stateType = GTK_STATE_ACTIVE; else if (isHovered(renderObject) && upHovered) stateType = GTK_STATE_PRELIGHT; else stateType = GTK_STATE_NORMAL; } IntRect topRect(IntPoint(), expandedRect.size()); topRect.setHeight(expandedRect.height() / 2); widgetContext.gtkPaintBox(topRect, widget, stateType, shadowType, "spinbutton_up"); // The arrow size/position calculation here is based on the arbitrary gymnastics that happen // in gtkspinbutton.c. It isn't pretty there and it isn't pretty here. This manages to make // the button look native for many themes though. IntRect arrowRect; int arrowSize = (expandedRect.width() - 3) / 2; arrowSize -= (arrowSize % 2) - 1; // Force odd. arrowRect.setWidth(arrowSize); arrowRect.setHeight(arrowSize); arrowRect.move((expandedRect.width() - arrowRect.width()) / 2, (topRect.height() - arrowRect.height()) / 2 + 1); widgetContext.gtkPaintArrow(arrowRect, widget, stateType, shadowType, GTK_ARROW_UP, "spinbutton"); shadowType = isPressed(renderObject) && !upPressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; if (controlActive) { if (isPressed(renderObject) && !upPressed) stateType = GTK_STATE_ACTIVE; else if (isHovered(renderObject) && !upHovered) stateType = GTK_STATE_PRELIGHT; else stateType = GTK_STATE_NORMAL; } IntRect bottomRect(IntPoint(0, expandedRect.height() / 2), expandedRect.size()); bottomRect.setHeight(expandedRect.height() - bottomRect.y()); widgetContext.gtkPaintBox(bottomRect, widget, stateType, shadowType, "spinbutton_down"); arrowRect.setY(arrowRect.y() + bottomRect.y() - 1); widgetContext.gtkPaintArrow(arrowRect, widget, stateType, shadowType, GTK_ARROW_DOWN, "spinbutton"); return false; }
bool RenderThemeGtk::paintCapsLockIndicator(const RenderObject& renderObject, const PaintInfo& paintInfo, const IntRect& rect) { // The other paint methods don't need to check whether painting is disabled because RenderTheme already checks it // before calling them, but paintCapsLockIndicator() is called by RenderTextControlSingleLine which doesn't check it. if (paintInfo.context->paintingDisabled()) return true; int iconSize = std::min(rect.width(), rect.height()); GRefPtr<GdkPixbuf> icon = getStockIconForWidgetType(GTK_TYPE_ENTRY, GTK_STOCK_CAPS_LOCK_WARNING, gtkTextDirection(renderObject.style().direction()), 0, getIconSizeForPixelSize(iconSize)); // Only re-scale the icon when it's smaller than the minimum icon size. if (iconSize >= gtkIconSizeMenu) iconSize = gdk_pixbuf_get_height(icon.get()); // GTK+ locates the icon right aligned in the entry. The given rectangle is already // centered vertically by RenderTextControlSingleLine. IntRect iconRect(rect.x() + rect.width() - iconSize, rect.y() + (rect.height() - iconSize) / 2, iconSize, iconSize); paintGdkPixbuf(paintInfo.context, icon.get(), iconRect); return true; }