760static gint spinButtonArrowSize(GtkStyleContext* context)
761{
762 const PangoFontDescription* fontDesc = gtk_style_context_get_font(context, static_cast<GtkStateFlags>(0));
763 gint fontSize = pango_font_description_get_size(fontDesc);
764 gint arrowSize = max(PANGO_PIXELS(fontSize), minSpinButtonArrowSize);
765
766 return arrowSize - arrowSize % 2; // Force even.
767}
768
769void RenderThemeGtk::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
770{
771 GtkStyleContext* context = getStyleContext(GTK_TYPE_SPIN_BUTTON);
772
773 GtkBorder padding;
774 gtk_style_context_get_padding(context, static_cast<GtkStateFlags>(0), &padding);
775
776 int width = spinButtonArrowSize(context) + padding.left + padding.right;
777 style->setWidth(Length(width, Fixed));
778 style->setMinWidth(Length(width, Fixed));
779}
780
781static void paintSpinArrowButton(RenderTheme* theme, GtkStyleContext* context, RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect, GtkArrowType arrowType)
782{
783 ASSERT(arrowType == GTK_ARROW_UP || arrowType == GTK_ARROW_DOWN);
784
785 gtk_style_context_save(context);
786 gtk_style_context_add_class(context, GTK_STYLE_CLASS_BUTTON);
787
788 GtkTextDirection direction = gtk_style_context_get_direction(context);
789 guint state = static_cast<guint>(gtk_style_context_get_state(context));
790 if (!(state & GTK_STATE_FLAG_INSENSITIVE)) {
791 if (theme->isPressed(renderObject)) {
792 if ((arrowType == GTK_ARROW_UP && theme->isSpinUpButtonPartPressed(renderObject))
793 || (arrowType == GTK_ARROW_DOWN && !theme->isSpinUpButtonPartPressed(renderObject)))
794 state |= GTK_STATE_FLAG_ACTIVE;
795 } else if (theme->isHovered(renderObject)) {
796 if ((arrowType == GTK_ARROW_UP && theme->isSpinUpButtonPartHovered(renderObject))
797 || (arrowType == GTK_ARROW_DOWN && !theme->isSpinUpButtonPartHovered(renderObject)))
798 state |= GTK_STATE_FLAG_PRELIGHT;
799 }
800 }
801 gtk_style_context_set_state(context, static_cast<GtkStateFlags>(state));
802
803 // Paint button.
804 IntRect buttonRect(rect);
805 guint junction = gtk_style_context_get_junction_sides(context);
806 if (arrowType == GTK_ARROW_UP)
807 junction |= GTK_JUNCTION_BOTTOM;
808 else {
809 junction |= GTK_JUNCTION_TOP;
810 buttonRect.move(0, rect.height() / 2);
811 }
812 buttonRect.setHeight(rect.height() / 2);
813 gtk_style_context_set_junction_sides(context, static_cast<GtkJunctionSides>(junction));
814
815 gtk_render_background(context, paintInfo.context->platformContext(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
816 gtk_render_frame(context, paintInfo.context->platformContext(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
817
818 // Paint arrow centered inside button.
819 IntRect arrowRect;
820 gdouble angle;
821 if (arrowType == GTK_ARROW_UP) {
822 angle = 0;
823 arrowRect.setY(rect.y());
824 arrowRect.setHeight(rect.height() / 2 - 2);
825 } else {
826 angle = G_PI;
827 arrowRect.setY(rect.y() + buttonRect.y());
828 arrowRect.setHeight(rect.height() - arrowRect.y() - 2);
829 }
830 arrowRect.setWidth(rect.width() - 3);
831 if (direction == GTK_TEXT_DIR_LTR)
832 arrowRect.setX(rect.x() + 1);
833 else
834 arrowRect.setX(rect.x() + 2);
835
836 gint width = arrowRect.width() / 2;
837 width -= width % 2 - 1; // Force odd.
838 gint height = (width + 1) / 2;
839
840 arrowRect.move((arrowRect.width() - width) / 2, (arrowRect.height() - height) / 2);
841 gtk_render_arrow(context, paintInfo.context->platformContext(), angle, arrowRect.x(), arrowRect.y(), width);
842
843 gtk_style_context_restore(context);
844}
845
846bool RenderThemeGtk::paintInnerSpinButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
847{
848 GtkStyleContext* context = getStyleContext(GTK_TYPE_SPIN_BUTTON);
849 gtk_style_context_save(context);
850
851 GtkTextDirection direction = static_cast<GtkTextDirection>(gtkTextDirection(renderObject->style()->direction()));
852 gtk_style_context_set_direction(context, direction);
853 gtk_style_context_set_junction_sides(context, direction == GTK_TEXT_DIR_RTL ? GTK_JUNCTION_RIGHT : GTK_JUNCTION_LEFT);
854
855 guint flags = 0;
856 if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
857 flags |= GTK_STATE_FLAG_INSENSITIVE;
858 else if (isFocused(renderObject))
859 flags |= GTK_STATE_FLAG_FOCUSED;
860 gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags));
861 gtk_style_context_remove_class(context, GTK_STYLE_CLASS_ENTRY);
862
863 paintSpinArrowButton(this, context, renderObject, paintInfo, rect, GTK_ARROW_UP);
864 paintSpinArrowButton(this, context, renderObject, paintInfo, rect, GTK_ARROW_DOWN);
865
866 gtk_style_context_restore(context);
867
868 return false;
869}
870