Exemple #1
0
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;
}
Exemple #2
0
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;
}
void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
{
    int flags = 0;
    if (scrollbar->orientation() == VerticalScrollbar)
        flags |= MOZ_GTK_STEPPER_VERTICAL;

    if (part == ForwardButtonEndPart)
        flags |= (MOZ_GTK_STEPPER_DOWN | MOZ_GTK_STEPPER_BOTTOM);
    if (part == ForwardButtonStartPart)
        flags |= MOZ_GTK_STEPPER_DOWN;

    GtkWidgetState state;
    state.focused = TRUE;
    state.isDefault = TRUE;
    state.canDefault = TRUE;
    state.depressed = FALSE;

    if ((BackButtonStartPart == part && scrollbar->currentPos())
        || (BackButtonEndPart == part && scrollbar->currentPos())
        || (ForwardButtonEndPart == part && scrollbar->currentPos() != scrollbar->maximum())
        || (ForwardButtonStartPart == part && scrollbar->currentPos() != scrollbar->maximum())) {
        state.disabled = FALSE;
        state.active = part == scrollbar->pressedPart();
        state.inHover = part == scrollbar->hoveredPart();
    } else {
        state.disabled = TRUE;
        state.active = FALSE;
        state.inHover = FALSE;
    }

    WidgetRenderingContext widgetContext(context, rect);
    widgetContext.paintMozillaWidget(MOZ_GTK_SCROLLBAR_BUTTON, &state, flags);
}
Exemple #4
0
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()));
}
void ScrollbarThemeGtk::paintThumb(GraphicsContext* context, ScrollbarThemeClient* scrollbar, const IntRect& rect)
{
    GtkWidget* widget = getWidgetForScrollbar(scrollbar);
    gboolean activateSlider;
    gtk_widget_style_get(widget, "activate-slider", &activateSlider, NULL);

    GtkStateType stateType = GTK_STATE_NORMAL;
    GtkShadowType shadowType = GTK_SHADOW_OUT;
    if (activateSlider && scrollbar->pressedPart() == ThumbPart) {
        stateType = GTK_STATE_ACTIVE;
        shadowType = GTK_SHADOW_IN;
    } else if (scrollbar->pressedPart() == ThumbPart || scrollbar->hoveredPart() == ThumbPart)
        stateType = GTK_STATE_PRELIGHT;

    // The adjustment controls the rendering of the scrollbar thumb. If it's not set
    // properly the theme may not draw the thumb borders properly.
    GtkAdjustment* adjustment = gtk_range_get_adjustment(GTK_RANGE(widget));
    gtk_adjustment_set_value(adjustment, scrollbar->currentPos());
    gtk_adjustment_set_lower(adjustment, 0);
    gtk_adjustment_set_upper(adjustment, scrollbar->maximum());

    GtkOrientation orientation = GTK_ORIENTATION_HORIZONTAL;
    if (scrollbar->orientation() == VerticalScrollbar) {
        gtk_adjustment_set_page_size(adjustment, rect.height());
        orientation = GTK_ORIENTATION_VERTICAL;
    } else
        gtk_adjustment_set_page_size(adjustment, rect.width());

    WidgetRenderingContext widgetContext(context, rect);
    IntRect sliderRect(IntPoint(), rect.size());
    widgetContext.gtkPaintSlider(sliderRect, widget, stateType, shadowType, "slider", orientation);
}
void ScrollbarThemeGtk::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar)
{
    // This is unused by the moz_gtk_scrollecd_window_paint.
    GtkWidgetState state;
    IntRect fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height());
    WidgetRenderingContext widgetContext(context, fullScrollbarRect);
    widgetContext.paintMozillaWidget(MOZ_GTK_SCROLLED_WINDOW, &state, 0);
}
void ScrollbarThemeGtk::paintScrollbarBackground(GraphicsContext* context, ScrollbarThemeClient* scrollbar)
{
    IntRect fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height());

    WidgetRenderingContext widgetContext(context, fullScrollbarRect);
    widgetContext.gtkPaintBox(fullScrollbarRect, getWidgetForScrollbar(scrollbar),
                              GTK_STATE_NORMAL, GTK_SHADOW_IN, "scrolled_window");
}
bool RenderThemeGtk::paintMenuList(RenderObject* object, const PaintInfo& info, const IntRect& rect)
{
    if (paintButton(object, info, rect))
        return true;

    // Menu list button painting strategy.
    // For buttons with appears-as-list set to false (having a separator):
    // | left border | Button text | xthickness | vseparator | xthickness | arrow | xthickness | right border |
    // For buttons with appears-as-list set to true (not having a separator):
    // | left border | Button text | arrow | xthickness | right border |

    int leftBorder = 0, rightBorder = 0, bottomBorder = 0, topBorder = 0;
    getButtonInnerBorder(gtkComboBoxButton(), leftBorder, topBorder, rightBorder, bottomBorder);
    RenderStyle* style = &object->style();
    int arrowSize = comboBoxArrowSize(style);
    GtkStyle* buttonStyle = gtk_widget_get_style(gtkComboBoxButton());

    IntRect arrowRect(0, (rect.height() - arrowSize) / 2, arrowSize, arrowSize);
    if (style->direction() == RTL)
        arrowRect.setX(leftBorder + buttonStyle->xthickness);
    else
        arrowRect.setX(rect.width() - rightBorder - buttonStyle->xthickness - arrowSize);
    GtkShadowType shadowType = isPressed(object) ? GTK_SHADOW_IN : GTK_SHADOW_OUT;

    WidgetRenderingContext widgetContext(info.context, rect);
    GtkStateType stateType = getGtkStateType(this, object);
    widgetContext.gtkPaintArrow(arrowRect, gtkComboBoxArrow(), stateType, shadowType, GTK_ARROW_DOWN, "arrow");

    // Some combo boxes do not have a separator.
    GtkWidget* separator = gtkComboBoxSeparator();
    if (!separator)
        return false;

    // We want to decrease the height of the separator based on the focus padding of the button.
    gint focusPadding = 0, focusWidth = 0; 
    gtk_widget_style_get(gtkComboBoxButton(),
                         "focus-line-width", &focusWidth,
                         "focus-padding", &focusPadding, NULL);
    topBorder += focusPadding + focusWidth;
    bottomBorder += focusPadding + focusWidth;
    int separatorWidth = getComboBoxSeparatorWidth();
    IntRect separatorRect(0, topBorder, separatorWidth, rect.height() - topBorder - bottomBorder);
    if (style->direction() == RTL)
        separatorRect.setX(arrowRect.x() + arrowRect.width() + buttonStyle->xthickness + separatorWidth);
    else
        separatorRect.setX(arrowRect.x() - buttonStyle->xthickness - separatorWidth);

    gboolean hasWideSeparators = FALSE;
    gtk_widget_style_get(separator, "wide-separators", &hasWideSeparators, NULL);
    if (hasWideSeparators)
        widgetContext.gtkPaintBox(separatorRect, separator, GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, "vseparator");
    else
        widgetContext.gtkPaintVLine(separatorRect, separator, GTK_STATE_NORMAL, "vseparator");

    return false;
}
Exemple #9
0
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;
}
void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext* context, ScrollbarThemeClient* scrollbar, const IntRect& rect)
{
    // Paint the track background. If the trough-under-steppers property is true, this
    // should be the full size of the scrollbar, but if is false, it should only be the
    // track rect.
    IntRect fullScrollbarRect(rect);
    if (m_troughUnderSteppers)
        fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height());

    WidgetRenderingContext widgetContext(context, fullScrollbarRect);
    IntRect paintRect(IntPoint(), fullScrollbarRect.size());
    widgetContext.gtkPaintBox(paintRect, getWidgetForScrollbar(scrollbar),
                              GTK_STATE_ACTIVE, GTK_SHADOW_IN, "trough");
}
void ScrollbarThemeGtk::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
{
    GtkWidgetState state;
    state.focused = FALSE;
    state.isDefault = FALSE;
    state.canDefault = FALSE;
    state.disabled = FALSE;
    state.active = scrollbar->pressedPart() == ThumbPart;
    state.inHover = scrollbar->hoveredPart() == ThumbPart;
    state.maxpos = scrollbar->maximum();
    state.curpos = scrollbar->currentPos();

    GtkThemeWidgetType type = scrollbar->orientation() == VerticalScrollbar ? MOZ_GTK_SCROLLBAR_THUMB_VERTICAL : MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
    WidgetRenderingContext widgetContext(context, rect);
    widgetContext.paintMozillaWidget(type, &state, 0);
}
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;
}
void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
{
    GtkWidgetState state;
    state.focused = FALSE;
    state.isDefault = FALSE;
    state.canDefault = FALSE;
    state.disabled = FALSE;
    state.active = FALSE;
    state.inHover = FALSE;

    // Paint the track background. If the trough-under-steppers property is true, this
    // should be the full size of the scrollbar, but if is false, it should only be the
    // track rect.
    IntRect fullScrollbarRect = rect;
    if (m_troughUnderSteppers)
        fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height());

    GtkThemeWidgetType type = scrollbar->orientation() == VerticalScrollbar ? MOZ_GTK_SCROLLBAR_TRACK_VERTICAL : MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL;
    WidgetRenderingContext widgetContext(context, fullScrollbarRect);
    widgetContext.paintMozillaWidget(type, &state, 0);
}
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);
    }
}
void ScrollbarThemeGtk::paintButton(GraphicsContext* context, ScrollbarThemeClient* scrollbar, const IntRect& rect, ScrollbarPart part)
{
    // The buttons will be disabled if the thumb is as the appropriate extreme.
    GtkShadowType shadowType = GTK_SHADOW_OUT;
    GtkStateType stateType = GTK_STATE_INSENSITIVE;
    bool pressed = (part == scrollbar->pressedPart());

    if ((BackButtonStartPart == part && scrollbar->currentPos())
        || (BackButtonEndPart == part && scrollbar->currentPos())
        || (ForwardButtonEndPart == part && scrollbar->currentPos() != scrollbar->maximum())
        || (ForwardButtonStartPart == part && scrollbar->currentPos() != scrollbar->maximum())) {
        stateType = GTK_STATE_NORMAL;
        if (pressed) {
            stateType = GTK_STATE_ACTIVE;
            shadowType = GTK_SHADOW_IN;
        } else if (part == scrollbar->hoveredPart())
            stateType = GTK_STATE_PRELIGHT;
    }

    // Themes determine how to draw the button (which button to draw) based on the allocation
    // of the widget. Where the target rect is in relation to the total widget allocation
    // determines the button.
    ScrollbarOrientation orientation = scrollbar->orientation();
    int buttonSize = (orientation == VerticalScrollbar) ? rect.height() : rect.width();
    int totalAllocation = buttonSize * 5; // One space for each button and one extra.
    int buttonOffset = 0;
    if (ForwardButtonStartPart == part)
        buttonOffset = buttonSize;
    else if (BackButtonEndPart == part)
        buttonOffset = 3 * buttonSize;
    else if (ForwardButtonEndPart == part)
        buttonOffset = 4 * buttonSize;

    // Now we want the allocation to be relative to the origin of the painted rect.
    GtkWidget* widget = getWidgetForScrollbar(scrollbar);
    GtkAllocation allocation;
    gtk_widget_get_allocation(widget, &allocation);
    allocation.x = allocation.y = 0;
    allocation.width = rect.width();
    allocation.height = rect.height();

    if (orientation == VerticalScrollbar) {
        allocation.height = totalAllocation;
        allocation.y -= buttonOffset;
    } else {
        allocation.width = totalAllocation;
        allocation.x -= buttonOffset;
    }
    gtk_widget_set_allocation(widget, &allocation);

    const char* detail = orientation == VerticalScrollbar ? "vscrollbar" : "hscrollbar";
    WidgetRenderingContext widgetContext(context, rect);

    IntRect buttonRect(IntPoint(), rect.size());
    widgetContext.gtkPaintBox(buttonRect, widget, stateType, shadowType, detail);

    float arrowScaling;
    gtk_widget_style_get(widget, "arrow-scaling", &arrowScaling, NULL);
    IntSize arrowSize = rect.size();
    arrowSize.scale(arrowScaling);
    IntRect arrowRect(IntPoint(buttonRect.x() + (buttonRect.width() - arrowSize.width()) / 2,
                               buttonRect.y() + (buttonRect.height() - arrowSize.height()) / 2),
                      arrowSize);
    if (pressed) {
        int arrowDisplacementX, arrowDisplacementY;
        gtk_widget_style_get(widget,
                             "arrow-displacement-x", &arrowDisplacementX,
                             "arrow-displacement-y", &arrowDisplacementY,
                             NULL);
        arrowRect.move(arrowDisplacementX, arrowDisplacementY);
    }

    GtkArrowType arrowType = GTK_ARROW_DOWN;
    if (orientation == VerticalScrollbar) {
        if (part == BackButtonEndPart || part == BackButtonStartPart)
            arrowType = GTK_ARROW_UP;
    } else if (orientation == HorizontalScrollbar) {
        arrowType = GTK_ARROW_RIGHT;
        if (part == BackButtonEndPart || part == BackButtonStartPart)
            arrowType = GTK_ARROW_LEFT;
    }
    widgetContext.gtkPaintArrow(arrowRect, widget, stateType, shadowType, arrowType, 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;
}