LCOV - code coverage report
Current view: top level - widget/gtk - gtk3drawing.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 150 1375 10.9 %
Date: 2017-07-14 16:53:18 Functions: 18 90 20.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : /*
       7             :  * This file contains painting functions for each of the gtk2 widgets.
       8             :  * Adapted from the gtkdrawing.c, and gtk+2.0 source.
       9             :  */
      10             : 
      11             : #include <gtk/gtk.h>
      12             : #include <gdk/gdkprivate.h>
      13             : #include <string.h>
      14             : #include "gtkdrawing.h"
      15             : #include "mozilla/Assertions.h"
      16             : #include "prinrval.h"
      17             : #include "WidgetStyleCache.h"
      18             : 
      19             : #include <math.h>
      20             : 
      21             : static gboolean checkbox_check_state;
      22             : static gboolean notebook_has_tab_gap;
      23             : 
      24             : static ScrollbarGTKMetrics sScrollbarMetrics[2];
      25             : 
      26             : #define ARROW_UP      0
      27             : #define ARROW_DOWN    G_PI
      28             : #define ARROW_RIGHT   G_PI_2
      29             : #define ARROW_LEFT    (G_PI+G_PI_2)
      30             : 
      31             : #if !GTK_CHECK_VERSION(3,14,0)
      32             : #define GTK_STATE_FLAG_CHECKED (1 << 11)
      33             : #endif
      34             : 
      35             : static gint
      36             : moz_gtk_get_tab_thickness(GtkStyleContext *style);
      37             : 
      38             : static gint
      39             : moz_gtk_menu_item_paint(WidgetNodeType widget, cairo_t *cr, GdkRectangle* rect,
      40             :                         GtkWidgetState* state, GtkTextDirection direction);
      41             : 
      42             : static GtkBorder
      43             : GetMarginBorderPadding(GtkStyleContext* aStyle);
      44             : 
      45             : // GetStateFlagsFromGtkWidgetState() can be safely used for the specific
      46             : // GtkWidgets that set both prelight and active flags.  For other widgets,
      47             : // either the GtkStateFlags or Gecko's GtkWidgetState need to be carefully
      48             : // adjusted to match GTK behavior.  Although GTK sets insensitive and focus
      49             : // flags in the generic GtkWidget base class, GTK adds prelight and active
      50             : // flags only to widgets that are expected to demonstrate prelight or active
      51             : // states.  This contrasts with HTML where any element may have :active and
      52             : // :hover states, and so Gecko's GtkStateFlags do not necessarily map to GTK
      53             : // flags.  Failure to restrict the flags in the same way as GTK can cause
      54             : // generic CSS selectors from some themes to unintentionally match elements
      55             : // that are not expected to change appearance on hover or mouse-down.
      56             : static GtkStateFlags
      57           0 : GetStateFlagsFromGtkWidgetState(GtkWidgetState* state)
      58             : {
      59           0 :     GtkStateFlags stateFlags = GTK_STATE_FLAG_NORMAL;
      60             : 
      61           0 :     if (state->disabled)
      62           0 :         stateFlags = GTK_STATE_FLAG_INSENSITIVE;
      63             :     else {    
      64           0 :         if (state->depressed || state->active)
      65           0 :             stateFlags = static_cast<GtkStateFlags>(stateFlags|GTK_STATE_FLAG_ACTIVE);
      66           0 :         if (state->inHover)
      67           0 :             stateFlags = static_cast<GtkStateFlags>(stateFlags|GTK_STATE_FLAG_PRELIGHT);
      68           0 :         if (state->focused)
      69           0 :             stateFlags = static_cast<GtkStateFlags>(stateFlags|GTK_STATE_FLAG_FOCUSED);
      70             :     }
      71             :   
      72           0 :     return stateFlags;
      73             : }
      74             : 
      75             : static GtkStateFlags
      76           0 : GetStateFlagsFromGtkTabFlags(GtkTabFlags flags)
      77             : {
      78           0 :     return ((flags & MOZ_GTK_TAB_SELECTED) == 0) ?
      79           0 :             GTK_STATE_FLAG_NORMAL : GTK_STATE_FLAG_ACTIVE;
      80             : }
      81             : 
      82             : gint
      83           2 : moz_gtk_init()
      84             : {
      85           4 :     if (gtk_major_version > 3 ||
      86           4 :        (gtk_major_version == 3 && gtk_minor_version >= 14))
      87           2 :         checkbox_check_state = GTK_STATE_FLAG_CHECKED;
      88             :     else
      89           0 :         checkbox_check_state = GTK_STATE_FLAG_ACTIVE;
      90             : 
      91           2 :     moz_gtk_refresh();
      92             : 
      93           2 :     return MOZ_GTK_SUCCESS;
      94             : }
      95             : 
      96             : void
      97           2 : moz_gtk_refresh()
      98             : {
      99           4 :     if (gtk_check_version(3, 12, 0) == nullptr &&
     100           2 :         gtk_check_version(3, 20, 0) != nullptr)
     101             :     {
     102             :         // Deprecated for Gtk >= 3.20+
     103           0 :         GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_TAB_TOP);
     104             :         gtk_style_context_get_style(style,
     105           0 :                                     "has-tab-gap", &notebook_has_tab_gap, NULL);
     106           0 :         ReleaseStyleContext(style);
     107             :     }
     108             :     else {
     109           2 :         notebook_has_tab_gap = true;
     110             :     }
     111             : 
     112           2 :     sScrollbarMetrics[GTK_ORIENTATION_HORIZONTAL].initialized = false;
     113           2 :     sScrollbarMetrics[GTK_ORIENTATION_VERTICAL].initialized = false;
     114           2 : }
     115             : 
     116             : gint
     117           0 : moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing)
     118             : {
     119           0 :     gtk_widget_style_get(GetWidget(MOZ_GTK_CHECKBUTTON_CONTAINER),
     120             :                          "indicator_size", indicator_size,
     121             :                          "indicator_spacing", indicator_spacing,
     122           0 :                          NULL);
     123           0 :     return MOZ_GTK_SUCCESS;
     124             : }
     125             : 
     126             : gint
     127           0 : moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing)
     128             : {
     129           0 :     gtk_widget_style_get(GetWidget(MOZ_GTK_RADIOBUTTON_CONTAINER),
     130             :                          "indicator_size", indicator_size,
     131             :                          "indicator_spacing", indicator_spacing,
     132           0 :                           NULL);
     133           0 :     return MOZ_GTK_SUCCESS;
     134             : }
     135             : 
     136             : static gint
     137           0 : moz_gtk_get_focus_outline_size(GtkStyleContext* style,
     138             :                                gint* focus_h_width, gint* focus_v_width)
     139             : {
     140             :     GtkBorder border;
     141             :     GtkBorder padding;
     142           0 :     gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
     143           0 :     gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
     144           0 :     *focus_h_width = border.left + padding.left;
     145           0 :     *focus_v_width = border.top + padding.top;
     146           0 :     return MOZ_GTK_SUCCESS;
     147             : }
     148             : 
     149             : gint
     150           0 : moz_gtk_get_focus_outline_size(gint* focus_h_width, gint* focus_v_width)
     151             : {
     152           0 :     GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_ENTRY);
     153           0 :     moz_gtk_get_focus_outline_size(style, focus_h_width, focus_v_width);
     154           0 :     ReleaseStyleContext(style);
     155           0 :     return MOZ_GTK_SUCCESS;
     156             : }
     157             : 
     158             : gint
     159           0 : moz_gtk_menuitem_get_horizontal_padding(gint* horizontal_padding)
     160             : {
     161           0 :     GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_MENUITEM);
     162             :     gtk_style_context_get_style(style,
     163             :                                 "horizontal-padding", horizontal_padding,
     164           0 :                                 nullptr);
     165           0 :     ReleaseStyleContext(style);
     166           0 :     return MOZ_GTK_SUCCESS;
     167             : }
     168             : 
     169             : gint
     170           0 : moz_gtk_checkmenuitem_get_horizontal_padding(gint* horizontal_padding)
     171             : {
     172           0 :     GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_CHECKMENUITEM);
     173             :     gtk_style_context_get_style(style,
     174             :                                 "horizontal-padding", horizontal_padding,
     175           0 :                                 nullptr);
     176           0 :     ReleaseStyleContext(style);
     177           0 :     return MOZ_GTK_SUCCESS;
     178             : }
     179             : 
     180             : gint
     181           0 : moz_gtk_button_get_default_overflow(gint* border_top, gint* border_left,
     182             :                                     gint* border_bottom, gint* border_right)
     183             : {
     184             :     GtkBorder* default_outside_border;
     185             : 
     186           0 :     GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON);
     187             :     gtk_style_context_get_style(style,
     188             :                                 "default-outside-border", &default_outside_border,
     189           0 :                                 NULL);
     190           0 :     ReleaseStyleContext(style);
     191             : 
     192           0 :     if (default_outside_border) {
     193           0 :         *border_top = default_outside_border->top;
     194           0 :         *border_left = default_outside_border->left;
     195           0 :         *border_bottom = default_outside_border->bottom;
     196           0 :         *border_right = default_outside_border->right;
     197           0 :         gtk_border_free(default_outside_border);
     198             :     } else {
     199           0 :         *border_top = *border_left = *border_bottom = *border_right = 0;
     200             :     }
     201           0 :     return MOZ_GTK_SUCCESS;
     202             : }
     203             : 
     204             : static gint
     205           0 : moz_gtk_button_get_default_border(gint* border_top, gint* border_left,
     206             :                                   gint* border_bottom, gint* border_right)
     207             : {
     208             :     GtkBorder* default_border;
     209             : 
     210           0 :     GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON);
     211             :     gtk_style_context_get_style(style,
     212             :                                 "default-border", &default_border,
     213           0 :                                 NULL);
     214           0 :     ReleaseStyleContext(style);
     215             : 
     216           0 :     if (default_border) {
     217           0 :         *border_top = default_border->top;
     218           0 :         *border_left = default_border->left;
     219           0 :         *border_bottom = default_border->bottom;
     220           0 :         *border_right = default_border->right;
     221           0 :         gtk_border_free(default_border);
     222             :     } else {
     223             :         /* see gtkbutton.c */
     224           0 :         *border_top = *border_left = *border_bottom = *border_right = 1;
     225             :     }
     226           0 :     return MOZ_GTK_SUCCESS;
     227             : }
     228             : 
     229             : gint
     230           0 : moz_gtk_splitter_get_metrics(gint orientation, gint* size)
     231             : {
     232             :     GtkStyleContext *style;
     233           0 :     if (orientation == GTK_ORIENTATION_HORIZONTAL) {
     234           0 :         style = ClaimStyleContext(MOZ_GTK_SPLITTER_HORIZONTAL);
     235             :     } else {
     236           0 :         style = ClaimStyleContext(MOZ_GTK_SPLITTER_VERTICAL);
     237             :     }
     238           0 :     gtk_style_context_get_style(style, "handle_size", size, NULL);
     239           0 :     ReleaseStyleContext(style);
     240           0 :     return MOZ_GTK_SUCCESS;
     241             : }
     242             : 
     243             : static gint
     244           9 : moz_gtk_window_paint(cairo_t *cr, GdkRectangle* rect,
     245             :                      GtkTextDirection direction)
     246             : {
     247           9 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_WINDOW, direction);
     248             : 
     249           9 :     gtk_style_context_save(style);
     250           9 :     gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
     251           9 :     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
     252           9 :     gtk_style_context_restore(style);
     253             : 
     254           9 :     ReleaseStyleContext(style);
     255             : 
     256           9 :     return MOZ_GTK_SUCCESS;
     257             : }
     258             : 
     259             : static gint
     260           0 : moz_gtk_button_paint(cairo_t *cr, GdkRectangle* rect,
     261             :                      GtkWidgetState* state,
     262             :                      GtkReliefStyle relief, GtkWidget* widget,
     263             :                      GtkTextDirection direction)
     264             : {
     265           0 :     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
     266           0 :     GtkStyleContext* style = gtk_widget_get_style_context(widget);    
     267           0 :     gint x = rect->x, y=rect->y, width=rect->width, height=rect->height;
     268             : 
     269           0 :     gtk_widget_set_direction(widget, direction);
     270             :  
     271           0 :     gtk_style_context_save(style);
     272           0 :     gtk_style_context_set_state(style, state_flags);
     273             : 
     274           0 :     if (state->isDefault && relief == GTK_RELIEF_NORMAL) {
     275             :         /* handle default borders both outside and inside the button */
     276             :         gint default_top, default_left, default_bottom, default_right;
     277             :         moz_gtk_button_get_default_overflow(&default_top, &default_left,
     278           0 :                                             &default_bottom, &default_right);
     279           0 :         x -= default_left;
     280           0 :         y -= default_top;
     281           0 :         width += default_left + default_right;
     282           0 :         height += default_top + default_bottom;
     283           0 :         gtk_render_background(style, cr, x, y, width, height);
     284           0 :         gtk_render_frame(style, cr, x, y, width, height);
     285             :         moz_gtk_button_get_default_border(&default_top, &default_left,
     286           0 :                                           &default_bottom, &default_right);
     287           0 :         x += default_left;
     288           0 :         y += default_top;
     289           0 :         width -= (default_left + default_right);
     290           0 :         height -= (default_top + default_bottom);
     291           0 :     } else if (relief != GTK_RELIEF_NONE || state->depressed ||
     292           0 :         (state_flags & GTK_STATE_FLAG_PRELIGHT)) {
     293             :         /* the following line can trigger an assertion (Crux theme)
     294             :            file ../../gdk/gdkwindow.c: line 1846 (gdk_window_clear_area):
     295             :            assertion `GDK_IS_WINDOW (window)' failed */
     296           0 :         gtk_render_background(style, cr, x, y, width, height);
     297           0 :         gtk_render_frame(style, cr, x, y, width, height);
     298             :     }
     299             : 
     300           0 :     if (state->focused) {
     301             :         GtkBorder border;
     302           0 :         gtk_style_context_get_border(style, state_flags, &border);
     303           0 :         x += border.left;
     304           0 :         y += border.top;
     305           0 :         width -= (border.left + border.right);
     306           0 :         height -= (border.top + border.bottom);
     307           0 :         gtk_render_focus(style, cr, x, y, width, height);
     308             :     }
     309           0 :     gtk_style_context_restore(style);
     310           0 :     return MOZ_GTK_SUCCESS;
     311             : }
     312             : 
     313             : static gint
     314           0 : moz_gtk_toggle_paint(cairo_t *cr, GdkRectangle* rect,
     315             :                      GtkWidgetState* state,
     316             :                      gboolean selected, gboolean inconsistent,
     317             :                      gboolean isradio, GtkTextDirection direction)
     318             : {
     319           0 :     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
     320             :     gint indicator_size, indicator_spacing;
     321             :     gint x, y, width, height;
     322             :     gint focus_x, focus_y, focus_width, focus_height;
     323             :     GtkStyleContext *style;
     324             : 
     325           0 :     GtkWidget *widget = GetWidget(isradio ? MOZ_GTK_RADIOBUTTON_CONTAINER :
     326           0 :                                             MOZ_GTK_CHECKBUTTON_CONTAINER);
     327             :     gtk_widget_style_get(widget,
     328             :                          "indicator_size", &indicator_size,
     329             :                          "indicator_spacing", &indicator_spacing,
     330           0 :                          nullptr);
     331             : 
     332             :     // XXX we should assert rect->height >= indicator_size too
     333             :     // after bug 369581 is fixed.
     334           0 :     MOZ_ASSERT(rect->width >= indicator_size,
     335             :                "GetMinimumWidgetSize was ignored");
     336             : 
     337             :     // Paint it center aligned in the rect.
     338           0 :     x = rect->x + (rect->width - indicator_size) / 2;
     339           0 :     y = rect->y + (rect->height - indicator_size) / 2;
     340           0 :     width = indicator_size;
     341           0 :     height = indicator_size;
     342             : 
     343           0 :     focus_x = x - indicator_spacing;
     344           0 :     focus_y = y - indicator_spacing;
     345           0 :     focus_width = width + 2 * indicator_spacing;
     346           0 :     focus_height = height + 2 * indicator_spacing;
     347             : 
     348           0 :     if (selected)
     349           0 :         state_flags = static_cast<GtkStateFlags>(state_flags|checkbox_check_state);
     350             : 
     351           0 :     if (inconsistent)
     352           0 :         state_flags = static_cast<GtkStateFlags>(state_flags|GTK_STATE_FLAG_INCONSISTENT);
     353             : 
     354           0 :     style = ClaimStyleContext(isradio ? MOZ_GTK_RADIOBUTTON :
     355             :                                         MOZ_GTK_CHECKBUTTON,
     356           0 :                               direction, state_flags);
     357             : 
     358           0 :     if (gtk_check_version(3, 20, 0) == nullptr) {
     359           0 :         gtk_render_background(style, cr, x, y, width, height);
     360           0 :         gtk_render_frame(style, cr, x, y, width, height);
     361             :     }
     362             : 
     363           0 :     if (isradio) {
     364           0 :         gtk_render_option(style, cr, x, y, width, height);
     365           0 :         if (state->focused) {
     366           0 :             gtk_render_focus(style, cr, focus_x, focus_y,
     367           0 :                             focus_width, focus_height);
     368             :         }
     369             :     }
     370             :     else {
     371           0 :         gtk_render_check(style, cr, x, y, width, height);
     372           0 :         if (state->focused) {
     373           0 :             gtk_render_focus(style, cr,
     374           0 :                              focus_x, focus_y, focus_width, focus_height);
     375             :         }
     376             :     }
     377             : 
     378           0 :     ReleaseStyleContext(style);
     379             : 
     380           0 :     return MOZ_GTK_SUCCESS;
     381             : }
     382             : 
     383             : static gint
     384           0 : calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect,
     385             :                             GdkRectangle* inner_rect,
     386             :                             GtkTextDirection direction)
     387             : {
     388             :     GtkStyleContext* style;
     389             :     GtkBorder border;
     390           0 :     GtkBorder padding = {0, 0, 0, 0};
     391             : 
     392           0 :     style = gtk_widget_get_style_context(button);
     393             : 
     394             :     /* This mirrors gtkbutton's child positioning */
     395           0 :     gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
     396           0 :     gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
     397             : 
     398           0 :     inner_rect->x = rect->x + border.left + padding.left;
     399           0 :     inner_rect->y = rect->y + padding.top + border.top;
     400           0 :     inner_rect->width = MAX(1, rect->width - padding.left -
     401             :        padding.right - border.left * 2);
     402           0 :     inner_rect->height = MAX(1, rect->height - padding.top -
     403             :        padding.bottom - border.top * 2);
     404             : 
     405           0 :     return MOZ_GTK_SUCCESS;
     406             : }
     407             : 
     408             : 
     409             : static gint
     410           0 : calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect,
     411             :                      GdkRectangle* arrow_rect, GtkTextDirection direction)
     412             : {
     413             :     /* defined in gtkarrow.c */
     414           0 :     gfloat arrow_scaling = 0.7;
     415             :     gfloat xalign, xpad;
     416             :     gint extent;
     417             :     gint mxpad, mypad;
     418             :     gfloat mxalign, myalign;
     419           0 :     GtkMisc* misc = GTK_MISC(arrow);
     420             : 
     421           0 :     gtk_style_context_get_style(gtk_widget_get_style_context(arrow),
     422           0 :                                 "arrow_scaling", &arrow_scaling, NULL);
     423             : 
     424           0 :     gtk_misc_get_padding(misc, &mxpad, &mypad); 
     425           0 :     extent = MIN((rect->width - mxpad * 2),
     426           0 :                  (rect->height - mypad * 2)) * arrow_scaling;
     427             : 
     428           0 :     gtk_misc_get_alignment(misc, &mxalign, &myalign);
     429             :     
     430           0 :     xalign = direction == GTK_TEXT_DIR_LTR ? mxalign : 1.0 - mxalign;
     431           0 :     xpad = mxpad + (rect->width - extent) * xalign;
     432             : 
     433           0 :     arrow_rect->x = direction == GTK_TEXT_DIR_LTR ?
     434           0 :                         floor(rect->x + xpad) : ceil(rect->x + xpad);
     435           0 :     arrow_rect->y = floor(rect->y + mypad +
     436           0 :                           ((rect->height - extent) * myalign));
     437             : 
     438           0 :     arrow_rect->width = arrow_rect->height = extent;
     439             : 
     440           0 :     return MOZ_GTK_SUCCESS;
     441             : }
     442             : 
     443             : static MozGtkSize
     444           4 : GetMinContentBox(GtkStyleContext* style)
     445             : {
     446           4 :     GtkStateFlags state_flags = gtk_style_context_get_state(style);
     447             :     gint width, height;
     448             :     gtk_style_context_get(style, state_flags,
     449             :                           "min-width", &width,
     450             :                           "min-height", &height,
     451           4 :                           nullptr);
     452           4 :     return {width, height};
     453             : }
     454             : 
     455             : /**
     456             :  * Get minimum widget size as sum of margin, padding, border and
     457             :  * min-width/min-height.
     458             :  */
     459             : static void
     460           4 : moz_gtk_get_widget_min_size(WidgetNodeType aGtkWidgetType, int* width,
     461             :                             int* height)
     462             : {
     463           4 :   GtkStyleContext* style = ClaimStyleContext(aGtkWidgetType);
     464           4 :   GtkStateFlags state_flags = gtk_style_context_get_state(style);
     465             :   gtk_style_context_get(style, state_flags,
     466             :                         "min-height", height,
     467             :                         "min-width", width,
     468           4 :                         nullptr);
     469             : 
     470             :   GtkBorder border, padding, margin;
     471           4 :   gtk_style_context_get_border(style, state_flags, &border);
     472           4 :   gtk_style_context_get_padding(style, state_flags, &padding);
     473           4 :   gtk_style_context_get_margin(style, state_flags,  &margin);
     474           4 :   ReleaseStyleContext(style);
     475             : 
     476          12 :   *width += border.left + border.right + margin.left + margin.right +
     477          12 :             padding.left + padding.right;
     478          12 :   *height += border.top + border.bottom + margin.top + margin.bottom +
     479          12 :              padding.top + padding.bottom;
     480           4 : }
     481             : 
     482             : static MozGtkSize
     483           4 : GetMinMarginBox(WidgetNodeType aNodeType)
     484             : {
     485             :     gint width, height;
     486           4 :     moz_gtk_get_widget_min_size(aNodeType, &width, &height);
     487           4 :     return {width, height};
     488             : }
     489             : 
     490             : static void
     491           0 : Inset(GdkRectangle* rect, GtkBorder& aBorder)
     492             : {
     493           0 :     MOZ_ASSERT(rect);
     494           0 :     rect->x += aBorder.left;
     495           0 :     rect->y += aBorder.top;
     496           0 :     rect->width -= aBorder.left + aBorder.right;
     497           0 :     rect->height -= aBorder.top + aBorder.bottom;
     498           0 : }
     499             : 
     500             : // Inset a rectangle by the margins specified in a style context.
     501             : static void
     502           0 : InsetByMargin(GdkRectangle* rect, GtkStyleContext* style)
     503             : {
     504           0 :     MOZ_ASSERT(rect);
     505             :     GtkBorder margin;
     506             : 
     507           0 :     gtk_style_context_get_margin(style, gtk_style_context_get_state(style),
     508           0 :                                  &margin);
     509           0 :     Inset(rect, margin);
     510           0 : }
     511             : 
     512             : // Inset a rectangle by the border and padding specified in a style context.
     513             : static void
     514           0 : InsetByBorderPadding(GdkRectangle* rect, GtkStyleContext* style)
     515             : {
     516           0 :     GtkStateFlags state = gtk_style_context_get_state(style);
     517             :     GtkBorder padding, border;
     518             : 
     519           0 :     gtk_style_context_get_padding(style, state, &padding);
     520           0 :     Inset(rect, padding);
     521           0 :     gtk_style_context_get_border(style, state, &border);
     522           0 :     Inset(rect, border);
     523           0 : }
     524             : 
     525             : static gint
     526           0 : moz_gtk_scrollbar_button_paint(cairo_t *cr, const GdkRectangle* aRect,
     527             :                                GtkWidgetState* state,
     528             :                                GtkScrollbarButtonFlags flags,
     529             :                                GtkTextDirection direction)
     530             : {
     531           0 :     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
     532             :     GdkRectangle arrow_rect;
     533             :     gdouble arrow_angle;
     534             :     GtkStyleContext* style;
     535             :     gint arrow_displacement_x, arrow_displacement_y;
     536             : 
     537             :     GtkWidget *scrollbar =
     538           0 :         GetWidget(flags & MOZ_GTK_STEPPER_VERTICAL ?
     539           0 :                   MOZ_GTK_SCROLLBAR_VERTICAL : MOZ_GTK_SCROLLBAR_HORIZONTAL);
     540             : 
     541           0 :     gtk_widget_set_direction(scrollbar, direction);
     542             : 
     543           0 :     if (flags & MOZ_GTK_STEPPER_VERTICAL) {
     544           0 :         arrow_angle = (flags & MOZ_GTK_STEPPER_DOWN) ? ARROW_DOWN : ARROW_UP;        
     545             :     } else {
     546           0 :         arrow_angle = (flags & MOZ_GTK_STEPPER_DOWN) ? ARROW_RIGHT : ARROW_LEFT;        
     547             :     }
     548             : 
     549           0 :     style = gtk_widget_get_style_context(scrollbar);
     550             :   
     551           0 :     gtk_style_context_save(style);
     552           0 :     gtk_style_context_add_class(style, GTK_STYLE_CLASS_BUTTON);
     553           0 :     gtk_style_context_set_state(style, state_flags);
     554           0 :     if (arrow_angle == ARROW_RIGHT) {
     555           0 :         gtk_style_context_add_class(style, GTK_STYLE_CLASS_RIGHT);
     556           0 :     } else if (arrow_angle == ARROW_DOWN) {
     557           0 :         gtk_style_context_add_class(style, GTK_STYLE_CLASS_BOTTOM);
     558           0 :     } else if (arrow_angle == ARROW_LEFT) {
     559           0 :         gtk_style_context_add_class(style, GTK_STYLE_CLASS_LEFT);
     560             :     } else {
     561           0 :         gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOP);
     562             :     }
     563             : 
     564           0 :     GdkRectangle rect = *aRect;
     565           0 :     if (gtk_check_version(3,20,0) == nullptr) {
     566             :       // The "trough-border" is not used since GTK 3.20.  The stepper margin
     567             :       // box occupies the full width of the "contents" gadget content box.
     568           0 :       InsetByMargin(&rect, style);
     569             :     } else {
     570             :         // Scrollbar button has to be inset by trough_border because its DOM
     571             :         // element is filling width of vertical scrollbar's track (or height
     572             :         // in case of horizontal scrollbars).
     573           0 :         GtkOrientation orientation = flags & MOZ_GTK_STEPPER_VERTICAL ?
     574           0 :             GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL;
     575           0 :         const auto& metrics = sScrollbarMetrics[orientation];
     576           0 :         if (!metrics.initialized) {
     577           0 :             NS_WARNING("Didn't measure before drawing?");
     578             :         }
     579           0 :         if (flags & MOZ_GTK_STEPPER_VERTICAL) {
     580           0 :             rect.x += metrics.border.track.left;
     581           0 :             rect.width = metrics.size.thumb.width;
     582             :         } else {
     583           0 :             rect.y += metrics.border.track.top;
     584           0 :             rect.height = metrics.size.thumb.height;
     585             :         }
     586             :     }
     587             : 
     588           0 :     gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height);
     589           0 :     gtk_render_frame(style, cr, rect.x, rect.y, rect.width, rect.height);
     590             : 
     591           0 :     arrow_rect.width = rect.width / 2;
     592           0 :     arrow_rect.height = rect.height / 2;
     593             :     
     594             :     gfloat arrow_scaling;
     595           0 :     gtk_style_context_get_style(style, "arrow-scaling", &arrow_scaling, NULL);
     596             : 
     597           0 :     gdouble arrow_size = MIN(rect.width, rect.height) * arrow_scaling;
     598           0 :     arrow_rect.x = rect.x + (rect.width - arrow_size) / 2;
     599           0 :     arrow_rect.y = rect.y + (rect.height - arrow_size) / 2;
     600             : 
     601           0 :     if (state_flags & GTK_STATE_FLAG_ACTIVE) {
     602             :         gtk_style_context_get_style(style,
     603             :                                     "arrow-displacement-x", &arrow_displacement_x,
     604             :                                     "arrow-displacement-y", &arrow_displacement_y,
     605           0 :                                     NULL);
     606             : 
     607           0 :         arrow_rect.x += arrow_displacement_x;
     608           0 :         arrow_rect.y += arrow_displacement_y;
     609             :     }
     610             :   
     611           0 :     gtk_render_arrow(style, cr, arrow_angle,
     612           0 :                      arrow_rect.x,
     613           0 :                      arrow_rect.y, 
     614           0 :                      arrow_size);
     615             :   
     616           0 :     gtk_style_context_restore(style);
     617             : 
     618           0 :     return MOZ_GTK_SUCCESS;
     619             : }
     620             : 
     621             : static void
     622           0 : moz_gtk_update_scrollbar_style(GtkStyleContext* style,
     623             :                                WidgetNodeType widget,
     624             :                                GtkTextDirection direction)
     625             : {
     626           0 :     if (widget == MOZ_GTK_SCROLLBAR_HORIZONTAL) {
     627           0 :         gtk_style_context_add_class(style, GTK_STYLE_CLASS_BOTTOM);
     628             :     } else {
     629           0 :         if (direction == GTK_TEXT_DIR_LTR) {
     630           0 :             gtk_style_context_add_class(style, GTK_STYLE_CLASS_RIGHT);
     631           0 :             gtk_style_context_remove_class(style, GTK_STYLE_CLASS_LEFT);
     632             :         } else {
     633           0 :             gtk_style_context_add_class(style, GTK_STYLE_CLASS_LEFT);
     634           0 :             gtk_style_context_remove_class(style, GTK_STYLE_CLASS_RIGHT);
     635             :         }
     636             :     }
     637           0 : }
     638             : 
     639             : static void
     640           0 : moz_gtk_draw_styled_frame(GtkStyleContext* style, cairo_t *cr,
     641             :                           const GdkRectangle* aRect, bool drawFocus)
     642             : {
     643           0 :     GdkRectangle rect = *aRect;
     644           0 :     if (gtk_check_version(3, 6, 0) == nullptr) {
     645           0 :         InsetByMargin(&rect, style);
     646             :     }
     647           0 :     gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height);
     648           0 :     gtk_render_frame(style, cr, rect.x, rect.y, rect.width, rect.height);
     649           0 :     if (drawFocus) {
     650           0 :         gtk_render_focus(style, cr,
     651           0 :                          rect.x, rect.y, rect.width, rect.height);
     652             :     }
     653           0 : }
     654             : 
     655             : static gint
     656           0 : moz_gtk_scrollbar_trough_paint(WidgetNodeType widget,
     657             :                                cairo_t *cr, const GdkRectangle* aRect,
     658             :                                GtkWidgetState* state,
     659             :                                GtkTextDirection direction)
     660             : {
     661           0 :     GdkRectangle rect = *aRect;
     662             :     GtkStyleContext* style;
     663             : 
     664           0 :     if (gtk_get_minor_version() >= 20) {
     665           0 :         WidgetNodeType thumb = widget == MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL ?
     666             :             MOZ_GTK_SCROLLBAR_THUMB_VERTICAL :
     667           0 :             MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
     668           0 :         MozGtkSize thumbSize = GetMinMarginBox(thumb);
     669           0 :         style = ClaimStyleContext(widget, direction);
     670           0 :         MozGtkSize trackSize = GetMinContentBox(style);
     671           0 :         trackSize.Include(thumbSize);
     672           0 :         trackSize += GetMarginBorderPadding(style);
     673             :         // Gecko's trough |aRect| fills available breadth, but GTK's trough is
     674             :         // centered in the contents_gadget.  The centering here round left
     675             :         // and up, like gtk_box_gadget_allocate_child().
     676           0 :         if (widget == MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL) {
     677           0 :             rect.x += (rect.width - trackSize.width)/2;
     678           0 :             rect.width = trackSize.width;
     679             :         } else {
     680           0 :             rect.y += (rect.height - trackSize.height)/2;
     681           0 :             rect.height = trackSize.height;
     682             :         }
     683             :     } else {
     684           0 :         style = ClaimStyleContext(widget, direction);
     685             :     }
     686             : 
     687           0 :     moz_gtk_draw_styled_frame(style, cr, &rect, state->focused);
     688           0 :     ReleaseStyleContext(style);
     689             : 
     690           0 :     return MOZ_GTK_SUCCESS;
     691             : }
     692             : 
     693             : static gint
     694           0 : moz_gtk_scrollbar_paint(WidgetNodeType widget,
     695             :                         cairo_t *cr, const GdkRectangle* rect,
     696             :                         GtkWidgetState* state,
     697             :                         GtkTextDirection direction)
     698             : {
     699           0 :     GtkStyleContext* style = ClaimStyleContext(widget, direction);
     700           0 :     moz_gtk_update_scrollbar_style(style, widget, direction);
     701             : 
     702           0 :     moz_gtk_draw_styled_frame(style, cr, rect, state->focused);
     703             : 
     704           0 :     ReleaseStyleContext(style);
     705           0 :     style = ClaimStyleContext((widget == MOZ_GTK_SCROLLBAR_HORIZONTAL) ?
     706             :                               MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL :
     707             :                               MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL,
     708           0 :                               direction);
     709           0 :     moz_gtk_draw_styled_frame(style, cr, rect, state->focused);
     710           0 :     ReleaseStyleContext(style);
     711             : 
     712           0 :     return MOZ_GTK_SUCCESS;
     713             : }
     714             : 
     715             : static gint
     716           0 : moz_gtk_scrollbar_thumb_paint(WidgetNodeType widget,
     717             :                               cairo_t *cr, const GdkRectangle* aRect,
     718             :                               GtkWidgetState* state,
     719             :                               GtkTextDirection direction)
     720             : {
     721           0 :     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
     722             : 
     723           0 :     GdkRectangle rect = *aRect;
     724           0 :     GtkStyleContext* style = ClaimStyleContext(widget, direction, state_flags);
     725           0 :     InsetByMargin(&rect, style);
     726             : 
     727           0 :     gtk_render_slider(style, cr,
     728           0 :                       rect.x,
     729           0 :                       rect.y,
     730           0 :                       rect.width,
     731           0 :                       rect.height,
     732             :                      (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ?
     733           0 :                      GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
     734             : 
     735           0 :     ReleaseStyleContext(style);
     736             : 
     737           0 :     return MOZ_GTK_SUCCESS;
     738             : }
     739             : 
     740             : static gint
     741           0 : moz_gtk_spin_paint(cairo_t *cr, GdkRectangle* rect,
     742             :                    GtkTextDirection direction)
     743             : {
     744           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SPINBUTTON, direction);
     745           0 :     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
     746           0 :     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
     747           0 :     ReleaseStyleContext(style);
     748           0 :     return MOZ_GTK_SUCCESS;
     749             : }
     750             : 
     751             : static gint
     752           0 : moz_gtk_spin_updown_paint(cairo_t *cr, GdkRectangle* rect,
     753             :                           gboolean isDown, GtkWidgetState* state,
     754             :                           GtkTextDirection direction)
     755             : {
     756           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SPINBUTTON, direction,
     757           0 :                                  GetStateFlagsFromGtkWidgetState(state));
     758             : 
     759           0 :     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
     760           0 :     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
     761             : 
     762             :     /* hard code these values */
     763             :     GdkRectangle arrow_rect;
     764           0 :     arrow_rect.width = 6;
     765           0 :     arrow_rect.height = 6;
     766           0 :     arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
     767           0 :     arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
     768           0 :     arrow_rect.y += isDown ? -1 : 1;
     769             : 
     770           0 :     gtk_render_arrow(style, cr, 
     771             :                     isDown ? ARROW_DOWN : ARROW_UP,
     772           0 :                     arrow_rect.x, arrow_rect.y,
     773           0 :                     arrow_rect.width);
     774             : 
     775           0 :     ReleaseStyleContext(style);
     776           0 :     return MOZ_GTK_SUCCESS;
     777             : }
     778             : 
     779             : /* See gtk_range_draw() for reference.
     780             : */
     781             : static gint
     782           0 : moz_gtk_scale_paint(cairo_t *cr, GdkRectangle* rect,
     783             :                     GtkWidgetState* state,
     784             :                     GtkOrientation flags, GtkTextDirection direction)
     785             : {
     786           0 :   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
     787             :   gint x, y, width, height, min_width, min_height;
     788             :   GtkStyleContext* style;
     789             :   GtkBorder margin;
     790             : 
     791           0 :   moz_gtk_get_scale_metrics(flags, &min_width, &min_height);
     792             : 
     793           0 :   WidgetNodeType widget = (flags == GTK_ORIENTATION_HORIZONTAL) ?
     794             :                           MOZ_GTK_SCALE_TROUGH_HORIZONTAL :
     795           0 :                           MOZ_GTK_SCALE_TROUGH_VERTICAL;
     796           0 :   style = ClaimStyleContext(widget, direction, state_flags);
     797           0 :   gtk_style_context_get_margin(style, state_flags, &margin);
     798             : 
     799             :   // Clamp the dimension perpendicular to the direction that the slider crosses
     800             :   // to the minimum size.
     801           0 :   if (flags == GTK_ORIENTATION_HORIZONTAL) {
     802           0 :     width = rect->width - (margin.left + margin.right);
     803           0 :     height = min_height - (margin.top + margin.bottom);
     804           0 :     x = rect->x + margin.left;
     805           0 :     y = rect->y + (rect->height - height)/2;
     806             :   } else {
     807           0 :     width = min_width - (margin.left + margin.right);
     808           0 :     height = rect->height - (margin.top + margin.bottom);
     809           0 :     x = rect->x + (rect->width - width)/2;
     810           0 :     y = rect->y + margin.top;
     811             :   }
     812             : 
     813           0 :   gtk_render_background(style, cr, x, y, width, height);
     814           0 :   gtk_render_frame(style, cr, x, y, width, height);
     815             : 
     816           0 :   if (state->focused)
     817           0 :     gtk_render_focus(style, cr, 
     818           0 :                     rect->x, rect->y, rect->width, rect->height);
     819             : 
     820           0 :   ReleaseStyleContext(style);
     821           0 :   return MOZ_GTK_SUCCESS;
     822             : }
     823             : 
     824             : static gint
     825           0 : moz_gtk_scale_thumb_paint(cairo_t *cr, GdkRectangle* rect,
     826             :                           GtkWidgetState* state,
     827             :                           GtkOrientation flags, GtkTextDirection direction)
     828             : {
     829           0 :   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
     830             :   GtkStyleContext* style;
     831             :   gint thumb_width, thumb_height, x, y;
     832             : 
     833             :   /* determine the thumb size, and position the thumb in the center in the opposite axis 
     834             :   */
     835           0 :   if (flags == GTK_ORIENTATION_HORIZONTAL) {
     836           0 :     moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_width, &thumb_height);
     837           0 :     x = rect->x;
     838           0 :     y = rect->y + (rect->height - thumb_height) / 2;
     839             :   }
     840             :   else {
     841           0 :     moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_width);
     842           0 :     x = rect->x + (rect->width - thumb_width) / 2;
     843           0 :     y = rect->y;
     844             :   }
     845             : 
     846           0 :   WidgetNodeType widget = (flags == GTK_ORIENTATION_HORIZONTAL) ?
     847             :                           MOZ_GTK_SCALE_THUMB_HORIZONTAL :
     848           0 :                           MOZ_GTK_SCALE_THUMB_VERTICAL;
     849           0 :   style = ClaimStyleContext(widget, direction, state_flags);
     850           0 :   gtk_render_slider(style, cr, x, y, thumb_width, thumb_height, flags);
     851           0 :   ReleaseStyleContext(style);
     852             : 
     853           0 :   return MOZ_GTK_SUCCESS;
     854             : }
     855             : 
     856             : static gint
     857           0 : moz_gtk_gripper_paint(cairo_t *cr, GdkRectangle* rect,
     858             :                       GtkWidgetState* state,
     859             :                       GtkTextDirection direction)
     860             : {
     861             :     GtkStyleContext* style =
     862           0 :             ClaimStyleContext(MOZ_GTK_GRIPPER, direction,
     863           0 :                               GetStateFlagsFromGtkWidgetState(state));
     864           0 :     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
     865           0 :     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
     866           0 :     ReleaseStyleContext(style);
     867           0 :     return MOZ_GTK_SUCCESS;
     868             : }
     869             : 
     870             : static gint
     871           0 : moz_gtk_hpaned_paint(cairo_t *cr, GdkRectangle* rect,
     872             :                      GtkWidgetState* state)
     873             : {
     874             :     GtkStyleContext* style =
     875           0 :         ClaimStyleContext(MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL,
     876             :                           GTK_TEXT_DIR_LTR,
     877           0 :                           GetStateFlagsFromGtkWidgetState(state));
     878           0 :     gtk_render_handle(style, cr,
     879           0 :                       rect->x, rect->y, rect->width, rect->height);
     880           0 :     ReleaseStyleContext(style);
     881           0 :     return MOZ_GTK_SUCCESS;
     882             : }
     883             : 
     884             : static gint
     885           0 : moz_gtk_vpaned_paint(cairo_t *cr, GdkRectangle* rect,
     886             :                      GtkWidgetState* state)
     887             : {
     888             :     GtkStyleContext* style =
     889           0 :         ClaimStyleContext(MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL,
     890             :                           GTK_TEXT_DIR_LTR,
     891           0 :                           GetStateFlagsFromGtkWidgetState(state));
     892           0 :     gtk_render_handle(style, cr,
     893           0 :                       rect->x, rect->y, rect->width, rect->height);                     
     894           0 :     ReleaseStyleContext(style);
     895           0 :     return MOZ_GTK_SUCCESS;
     896             : }
     897             : 
     898             : // See gtk_entry_draw() for reference.
     899             : static gint
     900           0 : moz_gtk_entry_paint(cairo_t *cr, GdkRectangle* rect,
     901             :                     GtkWidgetState* state,
     902             :                     GtkStyleContext* style)
     903             : {
     904           0 :     gint x = rect->x, y = rect->y, width = rect->width, height = rect->height;
     905           0 :     int draw_focus_outline_only = state->depressed; // NS_THEME_FOCUS_OUTLINE
     906             : 
     907           0 :     if (draw_focus_outline_only) {
     908             :         // Inflate the given 'rect' with the focus outline size.
     909             :         gint h, v;
     910           0 :         moz_gtk_get_focus_outline_size(style, &h, &v);
     911           0 :         rect->x -= h;
     912           0 :         rect->width += 2 * h;
     913           0 :         rect->y -= v;
     914           0 :         rect->height += 2 * v;
     915           0 :         width = rect->width;
     916           0 :         height = rect->height;
     917             :     } else {
     918           0 :         gtk_render_background(style, cr, x, y, width, height);
     919             :     }
     920           0 :     gtk_render_frame(style, cr, x, y, width, height);
     921             : 
     922           0 :     return MOZ_GTK_SUCCESS;
     923             : }
     924             : 
     925             : static gint
     926           0 : moz_gtk_text_view_paint(cairo_t *cr, GdkRectangle* aRect,
     927             :                         GtkWidgetState* state,
     928             :                         GtkTextDirection direction)
     929             : {
     930             :     // GtkTextView and GtkScrolledWindow do not set active and prelight flags.
     931             :     // The use of focus with MOZ_GTK_SCROLLED_WINDOW here is questionable
     932             :     // because a parent widget will not have focus when its child GtkTextView
     933             :     // has focus, but perhaps this may help identify a focused textarea with
     934             :     // some themes as GtkTextView backgrounds do not typically render
     935             :     // differently with focus.
     936             :     GtkStateFlags state_flags =
     937           0 :         state->disabled ? GTK_STATE_FLAG_INSENSITIVE :
     938           0 :         state->focused ? GTK_STATE_FLAG_FOCUSED :
     939           0 :         GTK_STATE_FLAG_NORMAL;
     940             : 
     941             :     GtkStyleContext* style_frame =
     942           0 :         ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction, state_flags);
     943           0 :     gtk_render_frame(style_frame, cr,
     944           0 :                      aRect->x, aRect->y, aRect->width, aRect->height);
     945             : 
     946           0 :     GdkRectangle rect = *aRect;
     947           0 :     InsetByBorderPadding(&rect, style_frame);
     948             : 
     949           0 :     ReleaseStyleContext(style_frame);
     950             : 
     951             :     GtkStyleContext* style =
     952           0 :         ClaimStyleContext(MOZ_GTK_TEXT_VIEW, direction, state_flags);
     953           0 :     gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height);
     954           0 :     ReleaseStyleContext(style);
     955             :     // There is a separate "text" window, which usually provides the
     956             :     // background behind the text.  However, this is transparent in Ambiance
     957             :     // for GTK 3.20, in which case the MOZ_GTK_TEXT_VIEW background is
     958             :     // visible.
     959           0 :     style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW_TEXT, direction, state_flags);
     960           0 :     gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height);
     961           0 :     ReleaseStyleContext(style);
     962             : 
     963           0 :     return MOZ_GTK_SUCCESS;
     964             : }
     965             : 
     966             : static gint 
     967           0 : moz_gtk_treeview_paint(cairo_t *cr, GdkRectangle* rect,
     968             :                        GtkWidgetState* state,
     969             :                        GtkTextDirection direction)
     970             : {
     971             :     gint xthickness, ythickness;
     972             :     GtkStyleContext *style;
     973             :     GtkStyleContext *style_tree;
     974             :     GtkStateFlags state_flags;
     975             :     GtkBorder border;
     976             : 
     977             :     /* only handle disabled and normal states, otherwise the whole background
     978             :      * area will be painted differently with other states */
     979           0 :     state_flags = state->disabled ? GTK_STATE_FLAG_INSENSITIVE : GTK_STATE_FLAG_NORMAL;
     980             : 
     981           0 :     style = ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction);
     982           0 :     gtk_style_context_get_border(style, state_flags, &border);
     983           0 :     xthickness = border.left;
     984           0 :     ythickness = border.top;    
     985           0 :     ReleaseStyleContext(style);
     986             : 
     987           0 :     style_tree = ClaimStyleContext(MOZ_GTK_TREEVIEW_VIEW, direction);
     988           0 :     gtk_render_background(style_tree, cr,
     989           0 :                           rect->x + xthickness, rect->y + ythickness,
     990           0 :                           rect->width - 2 * xthickness,
     991           0 :                           rect->height - 2 * ythickness);
     992           0 :     ReleaseStyleContext(style_tree);
     993             : 
     994           0 :     style = ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction);
     995           0 :     gtk_render_frame(style, cr, 
     996           0 :                      rect->x, rect->y, rect->width, rect->height); 
     997           0 :     ReleaseStyleContext(style);
     998           0 :     return MOZ_GTK_SUCCESS;
     999             : }
    1000             : 
    1001             : static gint
    1002           0 : moz_gtk_tree_header_cell_paint(cairo_t *cr, GdkRectangle* rect,
    1003             :                                GtkWidgetState* state,
    1004             :                                gboolean isSorted, GtkTextDirection direction)
    1005             : {
    1006           0 :     moz_gtk_button_paint(cr, rect, state, GTK_RELIEF_NORMAL,
    1007           0 :                          GetWidget(MOZ_GTK_TREE_HEADER_CELL), direction);
    1008           0 :     return MOZ_GTK_SUCCESS;
    1009             : }
    1010             : 
    1011             : static gint
    1012           0 : moz_gtk_tree_header_sort_arrow_paint(cairo_t *cr, GdkRectangle* rect,
    1013             :                                      GtkWidgetState* state, GtkArrowType arrow_type,
    1014             :                                      GtkTextDirection direction)
    1015             : {
    1016             :     GdkRectangle arrow_rect;
    1017             :     gdouble arrow_angle;
    1018             :     GtkStyleContext* style;
    1019             : 
    1020             :     /* hard code these values */
    1021           0 :     arrow_rect.width = 11;
    1022           0 :     arrow_rect.height = 11;
    1023           0 :     arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
    1024           0 :     arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
    1025           0 :     style = ClaimStyleContext(MOZ_GTK_TREE_HEADER_SORTARROW, direction,
    1026           0 :                               GetStateFlagsFromGtkWidgetState(state));
    1027           0 :     switch (arrow_type) {
    1028             :     case GTK_ARROW_LEFT:
    1029           0 :         arrow_angle = ARROW_LEFT;
    1030           0 :         break;
    1031             :     case GTK_ARROW_RIGHT:
    1032           0 :         arrow_angle = ARROW_RIGHT;
    1033           0 :         break;
    1034             :     case GTK_ARROW_DOWN:
    1035           0 :         arrow_angle = ARROW_DOWN;
    1036           0 :         break;
    1037             :     default:
    1038           0 :         arrow_angle = ARROW_UP;
    1039           0 :         break;
    1040             :     }
    1041           0 :     if (arrow_type != GTK_ARROW_NONE)
    1042           0 :         gtk_render_arrow(style, cr, arrow_angle,
    1043           0 :                          arrow_rect.x, arrow_rect.y,
    1044           0 :                          arrow_rect.width);
    1045           0 :     ReleaseStyleContext(style);
    1046           0 :     return MOZ_GTK_SUCCESS;
    1047             : }
    1048             : 
    1049             : /* See gtk_expander_paint() for reference. 
    1050             :  */
    1051             : static gint
    1052           0 : moz_gtk_treeview_expander_paint(cairo_t *cr, GdkRectangle* rect,
    1053             :                                 GtkWidgetState* state,
    1054             :                                 GtkExpanderStyle expander_state,
    1055             :                                 GtkTextDirection direction)
    1056             : {
    1057             :     /* Because the frame we get is of the entire treeview, we can't get the precise
    1058             :      * event state of one expander, thus rendering hover and active feedback useless. */
    1059           0 :     GtkStateFlags state_flags = state->disabled ? GTK_STATE_FLAG_INSENSITIVE :
    1060           0 :                                                   GTK_STATE_FLAG_NORMAL;
    1061             : 
    1062             :     /* GTK_STATE_FLAG_ACTIVE controls expanded/colapsed state rendering
    1063             :      * in gtk_render_expander()
    1064             :      */
    1065           0 :     if (expander_state == GTK_EXPANDER_EXPANDED)
    1066           0 :         state_flags = static_cast<GtkStateFlags>(state_flags|checkbox_check_state);
    1067             :     else
    1068           0 :         state_flags = static_cast<GtkStateFlags>(state_flags&~(checkbox_check_state));
    1069             : 
    1070             :     GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_TREEVIEW_EXPANDER,
    1071           0 :                                                direction, state_flags);
    1072           0 :     gtk_render_expander(style, cr,
    1073           0 :                         rect->x,
    1074           0 :                         rect->y,
    1075           0 :                         rect->width,
    1076           0 :                         rect->height);
    1077             : 
    1078           0 :     ReleaseStyleContext(style);
    1079           0 :     return MOZ_GTK_SUCCESS;
    1080             : }
    1081             : 
    1082             : /* See gtk_separator_draw() for reference.
    1083             : */
    1084             : static gint
    1085           0 : moz_gtk_combo_box_paint(cairo_t *cr, GdkRectangle* rect,
    1086             :                         GtkWidgetState* state,
    1087             :                         GtkTextDirection direction)
    1088             : {
    1089             :     GdkRectangle arrow_rect, real_arrow_rect;
    1090             :     gint separator_width;
    1091             :     gboolean wide_separators;
    1092             :     GtkStyleContext* style;
    1093             :     GtkRequisition arrow_req;
    1094             : 
    1095           0 :     GtkWidget* comboBoxButton = GetWidget(MOZ_GTK_COMBOBOX_BUTTON);
    1096           0 :     GtkWidget* comboBoxArrow = GetWidget(MOZ_GTK_COMBOBOX_ARROW);
    1097             : 
    1098             :     /* Also sets the direction on gComboBoxButtonWidget, which is then
    1099             :      * inherited by the separator and arrow */
    1100             :     moz_gtk_button_paint(cr, rect, state, GTK_RELIEF_NORMAL,
    1101           0 :                          comboBoxButton, direction);
    1102             : 
    1103           0 :     calculate_button_inner_rect(comboBoxButton, rect, &arrow_rect, direction);
    1104             :     /* Now arrow_rect contains the inner rect ; we want to correct the width
    1105             :      * to what the arrow needs (see gtk_combo_box_size_allocate) */
    1106           0 :     gtk_widget_get_preferred_size(comboBoxArrow, NULL, &arrow_req);
    1107             : 
    1108           0 :     if (direction == GTK_TEXT_DIR_LTR)
    1109           0 :         arrow_rect.x += arrow_rect.width - arrow_req.width;
    1110           0 :     arrow_rect.width = arrow_req.width;
    1111             : 
    1112             :     calculate_arrow_rect(comboBoxArrow,
    1113           0 :                          &arrow_rect, &real_arrow_rect, direction);
    1114             : 
    1115           0 :     style = ClaimStyleContext(MOZ_GTK_COMBOBOX_ARROW);
    1116           0 :     gtk_render_arrow(style, cr, ARROW_DOWN,
    1117           0 :                      real_arrow_rect.x, real_arrow_rect.y,
    1118           0 :                      real_arrow_rect.width);
    1119           0 :     ReleaseStyleContext(style);
    1120             : 
    1121             :     /* If there is no separator in the theme, there's nothing left to do. */
    1122           0 :     GtkWidget* widget = GetWidget(MOZ_GTK_COMBOBOX_SEPARATOR);
    1123           0 :     if (!widget)
    1124           0 :         return MOZ_GTK_SUCCESS;
    1125           0 :     style = gtk_widget_get_style_context(widget);
    1126             :     gtk_style_context_get_style(style,
    1127             :                                 "wide-separators", &wide_separators,
    1128             :                                 "separator-width", &separator_width,
    1129           0 :                                 NULL);
    1130             : 
    1131           0 :     if (wide_separators) {
    1132           0 :         if (direction == GTK_TEXT_DIR_LTR)
    1133           0 :             arrow_rect.x -= separator_width;
    1134             :         else
    1135           0 :             arrow_rect.x += arrow_rect.width;
    1136             :         
    1137           0 :         gtk_render_frame(style, cr, arrow_rect.x, arrow_rect.y, separator_width, arrow_rect.height);
    1138             :     } else {
    1139           0 :         if (direction == GTK_TEXT_DIR_LTR) {
    1140             :             GtkBorder padding;
    1141           0 :             GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
    1142           0 :             gtk_style_context_get_padding(style, state_flags, &padding);
    1143           0 :             arrow_rect.x -= padding.left;
    1144             :         }
    1145             :         else
    1146           0 :             arrow_rect.x += arrow_rect.width;
    1147             :         
    1148           0 :         gtk_render_line(style, cr, 
    1149           0 :                         arrow_rect.x, arrow_rect.y, 
    1150           0 :                         arrow_rect.x, arrow_rect.y + arrow_rect.height);
    1151             :     }
    1152           0 :     return MOZ_GTK_SUCCESS;
    1153             : }
    1154             : 
    1155             : static gint
    1156           0 : moz_gtk_arrow_paint(cairo_t *cr, GdkRectangle* rect,
    1157             :                     GtkWidgetState* state,
    1158             :                     GtkArrowType arrow_type, GtkTextDirection direction)
    1159             : {
    1160             :     GdkRectangle arrow_rect;
    1161             :     gdouble arrow_angle;
    1162             : 
    1163           0 :     if (direction == GTK_TEXT_DIR_RTL) {
    1164           0 :         if (arrow_type == GTK_ARROW_LEFT) {
    1165           0 :             arrow_type = GTK_ARROW_RIGHT;
    1166           0 :         } else if (arrow_type == GTK_ARROW_RIGHT) {
    1167           0 :             arrow_type = GTK_ARROW_LEFT;
    1168             :         }
    1169             :     }
    1170           0 :     switch (arrow_type) {
    1171             :     case GTK_ARROW_LEFT:
    1172           0 :         arrow_angle = ARROW_LEFT;
    1173           0 :         break;
    1174             :     case GTK_ARROW_RIGHT:
    1175           0 :         arrow_angle = ARROW_RIGHT;
    1176           0 :         break;
    1177             :     case GTK_ARROW_DOWN:
    1178           0 :         arrow_angle = ARROW_DOWN;
    1179           0 :         break;
    1180             :     default:
    1181           0 :         arrow_angle = ARROW_UP;
    1182           0 :         break;
    1183             :     }
    1184           0 :     if (arrow_type == GTK_ARROW_NONE)
    1185           0 :         return MOZ_GTK_SUCCESS;
    1186             : 
    1187           0 :     calculate_arrow_rect(GetWidget(MOZ_GTK_BUTTON_ARROW), rect, &arrow_rect,
    1188           0 :                          direction);
    1189           0 :     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
    1190             :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_BUTTON_ARROW,
    1191           0 :                                                direction, state_flags);
    1192           0 :     gtk_render_arrow(style, cr, arrow_angle,
    1193           0 :                      arrow_rect.x, arrow_rect.y, arrow_rect.width);
    1194           0 :     ReleaseStyleContext(style);
    1195           0 :     return MOZ_GTK_SUCCESS;
    1196             : }
    1197             : 
    1198             : static gint
    1199           0 : moz_gtk_combo_box_entry_button_paint(cairo_t *cr, GdkRectangle* rect,
    1200             :                                      GtkWidgetState* state,
    1201             :                                      gboolean input_focus,
    1202             :                                      GtkTextDirection direction)
    1203             : {
    1204             :     gint x_displacement, y_displacement;
    1205             :     GdkRectangle arrow_rect, real_arrow_rect;
    1206           0 :     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
    1207             :     GtkStyleContext* style;
    1208             : 
    1209           0 :     GtkWidget* comboBoxEntry = GetWidget(MOZ_GTK_COMBOBOX_ENTRY_BUTTON);
    1210             :     moz_gtk_button_paint(cr, rect, state, GTK_RELIEF_NORMAL,
    1211           0 :                          comboBoxEntry, direction);
    1212           0 :     calculate_button_inner_rect(comboBoxEntry, rect, &arrow_rect, direction);
    1213             : 
    1214           0 :     if (state_flags & GTK_STATE_FLAG_ACTIVE) {
    1215           0 :         style = gtk_widget_get_style_context(comboBoxEntry);
    1216             :         gtk_style_context_get_style(style,
    1217             :                                     "child-displacement-x", &x_displacement,
    1218             :                                     "child-displacement-y", &y_displacement,
    1219           0 :                                     NULL);
    1220           0 :         arrow_rect.x += x_displacement;
    1221           0 :         arrow_rect.y += y_displacement;
    1222             :     }
    1223             : 
    1224           0 :     calculate_arrow_rect(GetWidget(MOZ_GTK_COMBOBOX_ENTRY_ARROW),
    1225           0 :                          &arrow_rect, &real_arrow_rect, direction);
    1226             : 
    1227           0 :     style = ClaimStyleContext(MOZ_GTK_COMBOBOX_ENTRY_ARROW);
    1228           0 :     gtk_render_arrow(style, cr, ARROW_DOWN,
    1229           0 :                     real_arrow_rect.x, real_arrow_rect.y,
    1230           0 :                     real_arrow_rect.width);
    1231           0 :     ReleaseStyleContext(style);
    1232           0 :     return MOZ_GTK_SUCCESS;
    1233             : }
    1234             : 
    1235             : static gint
    1236           0 : moz_gtk_container_paint(cairo_t *cr, GdkRectangle* rect,
    1237             :                         GtkWidgetState* state, 
    1238             :                         WidgetNodeType  widget_type,
    1239             :                         GtkTextDirection direction)
    1240             : {
    1241           0 :     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
    1242             :     GtkStyleContext* style = ClaimStyleContext(widget_type, direction,
    1243           0 :                                                state_flags);
    1244             :     /* this is for drawing a prelight box */
    1245           0 :     if (state_flags & GTK_STATE_FLAG_PRELIGHT) {
    1246           0 :         gtk_render_background(style, cr,
    1247           0 :                               rect->x, rect->y, rect->width, rect->height);
    1248             :     }
    1249             : 
    1250           0 :     ReleaseStyleContext(style);
    1251           0 :     return MOZ_GTK_SUCCESS;
    1252             : }
    1253             : 
    1254             : static gint
    1255           0 : moz_gtk_toggle_label_paint(cairo_t *cr, GdkRectangle* rect,
    1256             :                            GtkWidgetState* state, 
    1257             :                            gboolean isradio, GtkTextDirection direction)
    1258             : {
    1259           0 :     if (!state->focused)
    1260           0 :         return MOZ_GTK_SUCCESS;
    1261             : 
    1262             :     GtkStyleContext *style =
    1263           0 :         ClaimStyleContext(isradio ? MOZ_GTK_RADIOBUTTON_CONTAINER :
    1264             :                                     MOZ_GTK_CHECKBUTTON_CONTAINER,
    1265             :                           direction,
    1266           0 :                           GetStateFlagsFromGtkWidgetState(state));
    1267           0 :     gtk_render_focus(style, cr,
    1268           0 :                     rect->x, rect->y, rect->width, rect->height);
    1269             : 
    1270           0 :     ReleaseStyleContext(style);
    1271             : 
    1272           0 :     return MOZ_GTK_SUCCESS;
    1273             : }
    1274             : 
    1275             : static gint
    1276           0 : moz_gtk_toolbar_paint(cairo_t *cr, GdkRectangle* rect,
    1277             :                       GtkTextDirection direction)
    1278             : {
    1279           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLBAR, direction);
    1280           0 :     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
    1281           0 :     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
    1282           0 :     ReleaseStyleContext(style);
    1283           0 :     return MOZ_GTK_SUCCESS;
    1284             : }
    1285             : 
    1286             : /* See _gtk_toolbar_paint_space_line() for reference.
    1287             : */
    1288             : static gint
    1289           0 : moz_gtk_toolbar_separator_paint(cairo_t *cr, GdkRectangle* rect,
    1290             :                                 GtkTextDirection direction)
    1291             : {
    1292             :     gint     separator_width;
    1293             :     gint     paint_width;
    1294             :     gboolean wide_separators;
    1295             :     
    1296             :     /* Defined as constants in GTK+ 2.10.14 */
    1297           0 :     const double start_fraction = 0.2;
    1298           0 :     const double end_fraction = 0.8;
    1299             : 
    1300           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLBAR);
    1301             :     gtk_style_context_get_style(style,
    1302             :                                 "wide-separators", &wide_separators,
    1303             :                                 "separator-width", &separator_width,
    1304           0 :                                 NULL);
    1305           0 :     ReleaseStyleContext(style);
    1306             : 
    1307           0 :     style = ClaimStyleContext(MOZ_GTK_TOOLBAR_SEPARATOR, direction);
    1308           0 :     if (wide_separators) {
    1309           0 :         if (separator_width > rect->width)
    1310           0 :             separator_width = rect->width;
    1311             :         
    1312           0 :         gtk_render_frame(style, cr,
    1313           0 :                           rect->x + (rect->width - separator_width) / 2,
    1314           0 :                           rect->y + rect->height * start_fraction,
    1315             :                           separator_width,
    1316           0 :                           rect->height * (end_fraction - start_fraction));
    1317             :     } else {
    1318             :         GtkBorder padding;
    1319           0 :         gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
    1320             :     
    1321           0 :         paint_width = padding.left;
    1322           0 :         if (paint_width > rect->width)
    1323           0 :             paint_width = rect->width;
    1324             :         
    1325           0 :         gtk_render_line(style, cr, 
    1326           0 :                         rect->x + (rect->width - paint_width) / 2,
    1327           0 :                         rect->y + rect->height * start_fraction,
    1328           0 :                         rect->x + (rect->width - paint_width) / 2,
    1329           0 :                         rect->y + rect->height * end_fraction);
    1330             :     }
    1331           0 :     ReleaseStyleContext(style);
    1332           0 :     return MOZ_GTK_SUCCESS;
    1333             : }
    1334             : 
    1335             : static gint
    1336           0 : moz_gtk_tooltip_paint(cairo_t *cr, const GdkRectangle* aRect,
    1337             :                       GtkTextDirection direction)
    1338             : {
    1339             :     // Tooltip widget is made in GTK3 as following tree:
    1340             :     // Tooltip window
    1341             :     //   Horizontal Box
    1342             :     //     Icon (not supported by Firefox)
    1343             :     //     Label
    1344             :     // Each element can be fully styled by CSS of GTK theme.
    1345             :     // We have to draw all elements with appropriate offset and right dimensions.
    1346             : 
    1347             :     // Tooltip drawing
    1348           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLTIP, direction);
    1349           0 :     GdkRectangle rect = *aRect;
    1350           0 :     gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height);
    1351           0 :     gtk_render_frame(style, cr, rect.x, rect.y, rect.width, rect.height);
    1352           0 :     ReleaseStyleContext(style);
    1353             : 
    1354             :     // Horizontal Box drawing
    1355             :     //
    1356             :     // The box element has hard-coded 6px margin-* GtkWidget properties, which
    1357             :     // are added between the window dimensions and the CSS margin box of the
    1358             :     // horizontal box.  The frame of the tooltip window is drawn in the
    1359             :     // 6px margin.
    1360             :     // For drawing Horizontal Box we have to inset drawing area by that 6px
    1361             :     // plus its CSS margin.
    1362           0 :     GtkStyleContext* boxStyle = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX, direction);
    1363             : 
    1364           0 :     rect.x += 6;
    1365           0 :     rect.y += 6;
    1366           0 :     rect.width -= 12;
    1367           0 :     rect.height -= 12;
    1368             : 
    1369           0 :     InsetByMargin(&rect, boxStyle);
    1370           0 :     gtk_render_background(boxStyle, cr, rect.x, rect.y, rect.width, rect.height);
    1371           0 :     gtk_render_frame(boxStyle, cr, rect.x, rect.y, rect.width, rect.height);
    1372             : 
    1373             :     // Label drawing
    1374           0 :     InsetByBorderPadding(&rect, boxStyle);
    1375           0 :     ReleaseStyleContext(boxStyle);
    1376             : 
    1377             :     GtkStyleContext* labelStyle =
    1378           0 :         ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL, direction);
    1379           0 :     moz_gtk_draw_styled_frame(labelStyle, cr, &rect, false);
    1380           0 :     ReleaseStyleContext(labelStyle);
    1381             : 
    1382           0 :     return MOZ_GTK_SUCCESS;
    1383             : }
    1384             : 
    1385             : static gint
    1386           0 : moz_gtk_resizer_paint(cairo_t *cr, GdkRectangle* rect,
    1387             :                       GtkWidgetState* state,
    1388             :                       GtkTextDirection direction)
    1389             : {
    1390             :     GtkStyleContext* style =
    1391           0 :         ClaimStyleContext(MOZ_GTK_RESIZER, GTK_TEXT_DIR_LTR,
    1392           0 :                           GetStateFlagsFromGtkWidgetState(state));
    1393             : 
    1394             :     // Workaround unico not respecting the text direction for resizers.
    1395             :     // See bug 1174248.
    1396           0 :     cairo_save(cr);
    1397           0 :     if (direction == GTK_TEXT_DIR_RTL) {
    1398             :       cairo_matrix_t mat;
    1399           0 :       cairo_matrix_init_translate(&mat, 2 * rect->x + rect->width, 0);
    1400           0 :       cairo_matrix_scale(&mat, -1, 1);
    1401           0 :       cairo_transform(cr, &mat);
    1402             :     }
    1403             : 
    1404           0 :     gtk_render_handle(style, cr, rect->x, rect->y, rect->width, rect->height);
    1405           0 :     cairo_restore(cr);
    1406           0 :     ReleaseStyleContext(style);
    1407             : 
    1408           0 :     return MOZ_GTK_SUCCESS;
    1409             : }
    1410             : 
    1411             : static gint
    1412           0 : moz_gtk_frame_paint(cairo_t *cr, GdkRectangle* rect,
    1413             :                     GtkTextDirection direction)
    1414             : {
    1415           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_FRAME, direction);
    1416           0 :     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
    1417           0 :     ReleaseStyleContext(style);
    1418           0 :     return MOZ_GTK_SUCCESS;
    1419             : }
    1420             : 
    1421             : static gint
    1422           0 : moz_gtk_progressbar_paint(cairo_t *cr, GdkRectangle* rect,
    1423             :                           GtkTextDirection direction)
    1424             : {
    1425             :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_PROGRESS_TROUGH,
    1426           0 :                                                direction);
    1427           0 :     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
    1428           0 :     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
    1429           0 :     ReleaseStyleContext(style);
    1430             : 
    1431           0 :     return MOZ_GTK_SUCCESS;
    1432             : }
    1433             : 
    1434             : static gint
    1435           0 : moz_gtk_progress_chunk_paint(cairo_t *cr, GdkRectangle* rect,
    1436             :                              GtkTextDirection direction,
    1437             :                              WidgetNodeType widget)
    1438             : {
    1439             :     GtkStyleContext* style =
    1440           0 :         ClaimStyleContext(MOZ_GTK_PROGRESS_CHUNK, direction);
    1441             : 
    1442           0 :     if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE ||
    1443             :         widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) {
    1444             :       /**
    1445             :        * The bar's size and the bar speed are set depending of the progress'
    1446             :        * size. These could also be constant for all progress bars easily.
    1447             :        */
    1448           0 :       gboolean vertical = (widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE);
    1449             : 
    1450             :       /* The size of the dimension we are going to use for the animation. */
    1451           0 :       const gint progressSize = vertical ? rect->height : rect->width;
    1452             : 
    1453             :       /* The bar is using a fifth of the element size, based on GtkProgressBar
    1454             :        * activity-blocks property. */
    1455           0 :       const gint barSize = MAX(1, progressSize / 5);
    1456             : 
    1457             :       /* Represents the travel that has to be done for a complete cycle. */
    1458           0 :       const gint travel = 2 * (progressSize - barSize);
    1459             : 
    1460             :       /* period equals to travel / pixelsPerMillisecond
    1461             :        * where pixelsPerMillisecond equals progressSize / 1000.0.
    1462             :        * This is equivalent to 1600. */
    1463             :       static const guint period = 1600;
    1464           0 :       const gint t = PR_IntervalToMilliseconds(PR_IntervalNow()) % period;
    1465           0 :       const gint dx = travel * t / period;
    1466             : 
    1467           0 :       if (vertical) {
    1468           0 :         rect->y += (dx < travel / 2) ? dx : travel - dx;
    1469           0 :         rect->height = barSize;
    1470             :       } else {
    1471           0 :         rect->x += (dx < travel / 2) ? dx : travel - dx;
    1472           0 :         rect->width = barSize;
    1473             :       }
    1474             :     }
    1475             : 
    1476             :     // gtk_render_activity was used to render progress chunks on GTK versions
    1477             :     // before 3.13.7, see bug 1173907.
    1478           0 :     if (!gtk_check_version(3, 13, 7)) {
    1479           0 :       gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
    1480           0 :       gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
    1481             :     } else {
    1482           0 :       gtk_render_activity(style, cr, rect->x, rect->y, rect->width, rect->height);
    1483             :     }
    1484           0 :     ReleaseStyleContext(style);
    1485             : 
    1486           0 :     return MOZ_GTK_SUCCESS;
    1487             : }
    1488             : 
    1489             : static gint
    1490           0 : moz_gtk_get_tab_thickness(GtkStyleContext *style)
    1491             : {
    1492           0 :     if (!notebook_has_tab_gap)
    1493           0 :       return 0; /* tabs do not overdraw the tabpanel border with "no gap" style */
    1494             : 
    1495             :     GtkBorder border;
    1496           0 :     gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
    1497           0 :     if (border.top < 2)
    1498           0 :         return 2; /* some themes don't set ythickness correctly */
    1499             : 
    1500           0 :     return border.top;
    1501             : }
    1502             : 
    1503             : gint
    1504           0 : moz_gtk_get_tab_thickness(WidgetNodeType aNodeType)
    1505             : {
    1506           0 :     GtkStyleContext *style = ClaimStyleContext(aNodeType);
    1507           0 :     int thickness = moz_gtk_get_tab_thickness(style);
    1508           0 :     ReleaseStyleContext(style);
    1509           0 :     return thickness;
    1510             : }
    1511             : 
    1512             : /* actual small tabs */
    1513             : static gint
    1514           0 : moz_gtk_tab_paint(cairo_t *cr, GdkRectangle* rect,
    1515             :                   GtkWidgetState* state,
    1516             :                   GtkTabFlags flags, GtkTextDirection direction,
    1517             :                   WidgetNodeType widget)
    1518             : {
    1519             :     /* When the tab isn't selected, we just draw a notebook extension.
    1520             :      * When it is selected, we overwrite the adjacent border of the tabpanel
    1521             :      * touching the tab with a pierced border (called "the gap") to make the
    1522             :      * tab appear physically attached to the tabpanel; see details below. */
    1523             : 
    1524             :     GtkStyleContext* style;
    1525             :     GdkRectangle tabRect;
    1526             :     GdkRectangle focusRect;
    1527             :     GdkRectangle backRect;
    1528           0 :     int initial_gap = 0;
    1529           0 :     bool isBottomTab = (widget == MOZ_GTK_TAB_BOTTOM);
    1530             : 
    1531           0 :     style = ClaimStyleContext(widget, direction,
    1532           0 :                               GetStateFlagsFromGtkTabFlags(flags));
    1533           0 :     tabRect = *rect;
    1534             : 
    1535           0 :     if (flags & MOZ_GTK_TAB_FIRST) {
    1536           0 :         gtk_style_context_get_style(style, "initial-gap", &initial_gap, NULL);
    1537           0 :         tabRect.width -= initial_gap;
    1538             : 
    1539           0 :         if (direction != GTK_TEXT_DIR_RTL) {
    1540           0 :             tabRect.x += initial_gap;
    1541             :         }
    1542             :     }
    1543             : 
    1544           0 :     focusRect = backRect = tabRect;
    1545             : 
    1546           0 :     if (notebook_has_tab_gap) {
    1547           0 :         if ((flags & MOZ_GTK_TAB_SELECTED) == 0) {
    1548             :             /* Only draw the tab */
    1549           0 :             gtk_render_extension(style, cr,
    1550           0 :                                  tabRect.x, tabRect.y, tabRect.width, tabRect.height,
    1551           0 :                                  isBottomTab ? GTK_POS_TOP : GTK_POS_BOTTOM );
    1552             :         } else {
    1553             :             /* Draw the tab and the gap
    1554             :              * We want the gap to be positioned exactly on the tabpanel top
    1555             :              * border; since tabbox.css may set a negative margin so that the tab
    1556             :              * frame rect already overlaps the tabpanel frame rect, we need to take
    1557             :              * that into account when drawing. To that effect, nsNativeThemeGTK
    1558             :              * passes us this negative margin (bmargin in the graphic below) in the
    1559             :              * lowest bits of |flags|.  We use it to set gap_voffset, the distance
    1560             :              * between the top of the gap and the bottom of the tab (resp. the
    1561             :              * bottom of the gap and the top of the tab when we draw a bottom tab),
    1562             :              * while ensuring that the gap always touches the border of the tab,
    1563             :              * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results
    1564             :              * with big negative or positive margins.
    1565             :              * Here is a graphical explanation in the case of top tabs:
    1566             :              *             ___________________________
    1567             :              *            /                           \
    1568             :              *           |            T A B            |
    1569             :              * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel
    1570             :              *           :    ^       bmargin          :  ^
    1571             :              *           :    | (-negative margin,     :  |
    1572             :              *  bottom   :    v  passed in flags)      :  |       gap_height
    1573             :              *    of  -> :.............................:  |    (the size of the
    1574             :              * the tab   .       part of the gap       .  |  tabpanel top border)
    1575             :              *           .      outside of the tab     .  v
    1576             :              * ----------------------------------------------
    1577             :              *
    1578             :              * To draw the gap, we use gtk_render_frame_gap(), see comment in
    1579             :              * moz_gtk_tabpanels_paint(). This gap is made 3 * gap_height tall,
    1580             :              * which should suffice to ensure that the only visible border is the
    1581             :              * pierced one.  If the tab is in the middle, we make the box_gap begin
    1582             :              * a bit to the left of the tab and end a bit to the right, adjusting
    1583             :              * the gap position so it still is under the tab, because we want the
    1584             :              * rendering of a gap in the middle of a tabpanel.  This is the role of
    1585             :              * the gints gap_{l,r}_offset. On the contrary, if the tab is the
    1586             :              * first, we align the start border of the box_gap with the start
    1587             :              * border of the tab (left if LTR, right if RTL), by setting the
    1588             :              * appropriate offset to 0.*/
    1589             :             gint gap_loffset, gap_roffset, gap_voffset, gap_height;
    1590             : 
    1591             :             /* Get height needed by the gap */
    1592           0 :             gap_height = moz_gtk_get_tab_thickness(style);
    1593             : 
    1594             :             /* Extract gap_voffset from the first bits of flags */
    1595           0 :             gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK;
    1596           0 :             if (gap_voffset > gap_height)
    1597           0 :                 gap_voffset = gap_height;
    1598             : 
    1599             :             /* Set gap_{l,r}_offset to appropriate values */
    1600           0 :             gap_loffset = gap_roffset = 20; /* should be enough */
    1601           0 :             if (flags & MOZ_GTK_TAB_FIRST) {
    1602           0 :                 if (direction == GTK_TEXT_DIR_RTL)
    1603           0 :                     gap_roffset = initial_gap;
    1604             :                 else
    1605           0 :                     gap_loffset = initial_gap;
    1606             :             }
    1607             : 
    1608             :             GtkStyleContext* panelStyle =
    1609           0 :                 ClaimStyleContext(MOZ_GTK_TABPANELS, direction);
    1610             : 
    1611           0 :             if (isBottomTab) {
    1612             :                 /* Draw the tab on bottom */
    1613           0 :                 focusRect.y += gap_voffset;
    1614           0 :                 focusRect.height -= gap_voffset;
    1615             : 
    1616           0 :                 gtk_render_extension(style, cr,
    1617           0 :                                      tabRect.x, tabRect.y + gap_voffset, tabRect.width,
    1618           0 :                                      tabRect.height - gap_voffset, GTK_POS_TOP);
    1619             : 
    1620           0 :                 backRect.y += (gap_voffset - gap_height);
    1621           0 :                 backRect.height = gap_height;
    1622             : 
    1623             :                 /* Draw the gap; erase with background color before painting in
    1624             :                  * case theme does not */
    1625           0 :                 gtk_render_background(panelStyle, cr, backRect.x, backRect.y,
    1626           0 :                                      backRect.width, backRect.height);
    1627           0 :                 cairo_save(cr);
    1628           0 :                 cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
    1629           0 :                 cairo_clip(cr);
    1630             : 
    1631           0 :                 gtk_render_frame_gap(panelStyle, cr,
    1632           0 :                                      tabRect.x - gap_loffset,
    1633           0 :                                      tabRect.y + gap_voffset - 3 * gap_height,
    1634           0 :                                      tabRect.width + gap_loffset + gap_roffset,
    1635           0 :                                      3 * gap_height, GTK_POS_BOTTOM,
    1636           0 :                                      gap_loffset, gap_loffset + tabRect.width);
    1637           0 :                 cairo_restore(cr);
    1638             :             } else {
    1639             :                 /* Draw the tab on top */
    1640           0 :                 focusRect.height -= gap_voffset;
    1641           0 :                 gtk_render_extension(style, cr,
    1642           0 :                                      tabRect.x, tabRect.y, tabRect.width,
    1643           0 :                                      tabRect.height - gap_voffset, GTK_POS_BOTTOM);
    1644             : 
    1645           0 :                 backRect.y += (tabRect.height - gap_voffset);
    1646           0 :                 backRect.height = gap_height;
    1647             : 
    1648             :                 /* Draw the gap; erase with background color before painting in
    1649             :                  * case theme does not */
    1650           0 :                 gtk_render_background(panelStyle, cr, backRect.x, backRect.y,
    1651           0 :                                       backRect.width, backRect.height);
    1652             : 
    1653           0 :                 cairo_save(cr);
    1654           0 :                 cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
    1655           0 :                 cairo_clip(cr);
    1656             : 
    1657           0 :                 gtk_render_frame_gap(panelStyle, cr,
    1658           0 :                                      tabRect.x - gap_loffset,
    1659           0 :                                      tabRect.y + tabRect.height - gap_voffset,
    1660           0 :                                      tabRect.width + gap_loffset + gap_roffset,
    1661           0 :                                      3 * gap_height, GTK_POS_TOP,
    1662           0 :                                      gap_loffset, gap_loffset + tabRect.width);
    1663           0 :                 cairo_restore(cr);
    1664             :             }
    1665             :         }
    1666             :     } else {
    1667           0 :         gtk_render_background(style, cr, tabRect.x, tabRect.y, tabRect.width, tabRect.height);
    1668           0 :         gtk_render_frame(style, cr, tabRect.x, tabRect.y, tabRect.width, tabRect.height);
    1669             :     }
    1670             : 
    1671           0 :     if (state->focused) {
    1672             :       /* Paint the focus ring */
    1673             :       GtkBorder padding;
    1674           0 :       gtk_style_context_get_padding(style, GetStateFlagsFromGtkWidgetState(state), &padding);
    1675             : 
    1676           0 :       focusRect.x += padding.left;
    1677           0 :       focusRect.width -= (padding.left + padding.right);
    1678           0 :       focusRect.y += padding.top;
    1679           0 :       focusRect.height -= (padding.top + padding.bottom);
    1680             : 
    1681           0 :       gtk_render_focus(style, cr,
    1682           0 :                       focusRect.x, focusRect.y, focusRect.width, focusRect.height);
    1683             :     }
    1684           0 :     ReleaseStyleContext(style);
    1685             : 
    1686           0 :     return MOZ_GTK_SUCCESS;
    1687             : }
    1688             : 
    1689             : /* tab area*/
    1690             : static gint
    1691           0 : moz_gtk_tabpanels_paint(cairo_t *cr, GdkRectangle* rect,
    1692             :                         GtkTextDirection direction)
    1693             : {
    1694           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TABPANELS, direction);
    1695           0 :     gtk_render_background(style, cr, rect->x, rect->y, 
    1696           0 :                           rect->width, rect->height);
    1697             :     /*
    1698             :      * The gap size is not needed in moz_gtk_tabpanels_paint because 
    1699             :      * the gap will be painted with the foreground tab in moz_gtk_tab_paint.
    1700             :      *
    1701             :      * However, if moz_gtk_tabpanels_paint just uses gtk_render_frame(), 
    1702             :      * the theme will think that there are no tabs and may draw something 
    1703             :      * different.Hence the trick of using two clip regions, and drawing the 
    1704             :      * gap outside each clip region, to get the correct frame for 
    1705             :      * a tabpanel with tabs.
    1706             :      */
    1707             :     /* left side */
    1708           0 :     cairo_save(cr);
    1709           0 :     cairo_rectangle(cr, rect->x, rect->y,
    1710           0 :                     rect->x + rect->width / 2,
    1711           0 :                     rect->y + rect->height);
    1712           0 :     cairo_clip(cr);
    1713           0 :     gtk_render_frame_gap(style, cr,
    1714           0 :                          rect->x, rect->y,
    1715           0 :                          rect->width, rect->height,
    1716           0 :                          GTK_POS_TOP, rect->width - 1, rect->width);
    1717           0 :     cairo_restore(cr);
    1718             : 
    1719             :     /* right side */
    1720           0 :     cairo_save(cr);
    1721           0 :     cairo_rectangle(cr, rect->x + rect->width / 2, rect->y,
    1722           0 :                     rect->x + rect->width,
    1723           0 :                     rect->y + rect->height);
    1724           0 :     cairo_clip(cr);
    1725           0 :     gtk_render_frame_gap(style, cr,
    1726           0 :                          rect->x, rect->y,
    1727           0 :                          rect->width, rect->height,
    1728           0 :                          GTK_POS_TOP, 0, 1);
    1729           0 :     cairo_restore(cr);
    1730             : 
    1731           0 :     ReleaseStyleContext(style);
    1732           0 :     return MOZ_GTK_SUCCESS;
    1733             : }
    1734             : 
    1735             : static gint
    1736           0 : moz_gtk_tab_scroll_arrow_paint(cairo_t *cr, GdkRectangle* rect,
    1737             :                                GtkWidgetState* state,
    1738             :                                GtkArrowType arrow_type,
    1739             :                                GtkTextDirection direction)
    1740             : {
    1741             :     GtkStyleContext* style;
    1742             :     gdouble arrow_angle;
    1743           0 :     gint arrow_size = MIN(rect->width, rect->height);
    1744           0 :     gint x = rect->x + (rect->width - arrow_size) / 2;
    1745           0 :     gint y = rect->y + (rect->height - arrow_size) / 2;
    1746             : 
    1747           0 :     if (direction == GTK_TEXT_DIR_RTL) {
    1748           0 :         arrow_type = (arrow_type == GTK_ARROW_LEFT) ?
    1749             :                          GTK_ARROW_RIGHT : GTK_ARROW_LEFT;
    1750             :     }    
    1751           0 :     switch (arrow_type) {
    1752             :     case GTK_ARROW_LEFT:
    1753           0 :         arrow_angle = ARROW_LEFT;
    1754           0 :         break;
    1755             :     case GTK_ARROW_RIGHT:
    1756           0 :         arrow_angle = ARROW_RIGHT;
    1757           0 :         break;
    1758             :     case GTK_ARROW_DOWN:
    1759           0 :         arrow_angle = ARROW_DOWN;
    1760           0 :         break;
    1761             :     default:
    1762           0 :         arrow_angle = ARROW_UP;
    1763           0 :         break;      
    1764             :     }
    1765           0 :     if (arrow_type != GTK_ARROW_NONE)  {        
    1766           0 :         style = ClaimStyleContext(MOZ_GTK_TAB_SCROLLARROW, direction,
    1767           0 :                                   GetStateFlagsFromGtkWidgetState(state));
    1768           0 :         gtk_render_arrow(style, cr, arrow_angle,
    1769           0 :                          x, y, arrow_size);
    1770           0 :         ReleaseStyleContext(style);
    1771             :     }
    1772           0 :     return MOZ_GTK_SUCCESS;
    1773             : }
    1774             : 
    1775             : static gint
    1776           9 : moz_gtk_menu_bar_paint(cairo_t *cr, GdkRectangle* rect,
    1777             :                        GtkTextDirection direction)
    1778             : {
    1779             :     GtkStyleContext* style;
    1780             : 
    1781           9 :     GtkWidget* widget = GetWidget(MOZ_GTK_MENUBAR);
    1782           9 :     gtk_widget_set_direction(widget, direction);
    1783             : 
    1784           9 :     style = gtk_widget_get_style_context(widget);
    1785           9 :     gtk_style_context_save(style);
    1786           9 :     gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
    1787           9 :     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
    1788           9 :     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
    1789           9 :     gtk_style_context_restore(style);
    1790             :     
    1791           9 :     return MOZ_GTK_SUCCESS;
    1792             : }
    1793             : 
    1794             : static gint
    1795           0 : moz_gtk_menu_popup_paint(cairo_t *cr, GdkRectangle* rect,
    1796             :                          GtkTextDirection direction)
    1797             : {
    1798             :     GtkStyleContext* style;
    1799             : 
    1800           0 :     GtkWidget* widget = GetWidget(MOZ_GTK_MENUPOPUP);
    1801           0 :     gtk_widget_set_direction(widget, direction);
    1802             : 
    1803             :     // Draw a backing toplevel. This fixes themes that don't provide a menu
    1804             :     // background, and depend on the GtkMenu's implementation window to provide it.
    1805           0 :     moz_gtk_window_paint(cr, rect, direction);
    1806             : 
    1807           0 :     style = gtk_widget_get_style_context(widget);
    1808           0 :     gtk_style_context_save(style);
    1809           0 :     gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENU);
    1810             : 
    1811           0 :     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
    1812           0 :     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
    1813           0 :     gtk_style_context_restore(style);
    1814             : 
    1815           0 :     return MOZ_GTK_SUCCESS;
    1816             : }
    1817             : 
    1818             : // See gtk_menu_item_draw() for reference.
    1819             : static gint
    1820           0 : moz_gtk_menu_separator_paint(cairo_t *cr, GdkRectangle* rect,
    1821             :                              GtkTextDirection direction)
    1822             : {
    1823           0 :     GtkWidgetState defaultState = { 0 };
    1824             :     moz_gtk_menu_item_paint(MOZ_GTK_MENUSEPARATOR, cr, rect,
    1825           0 :                             &defaultState, direction);
    1826             : 
    1827           0 :     if (gtk_get_minor_version() >= 20)
    1828           0 :         return MOZ_GTK_SUCCESS;
    1829             : 
    1830             :     GtkStyleContext* style;
    1831             :     gboolean wide_separators;
    1832             :     gint separator_height;
    1833             :     gint x, y, w;
    1834             :     GtkBorder padding;
    1835             : 
    1836           0 :     style = ClaimStyleContext(MOZ_GTK_MENUSEPARATOR, direction);
    1837           0 :     gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
    1838             : 
    1839           0 :     x = rect->x;
    1840           0 :     y = rect->y;
    1841           0 :     w = rect->width;
    1842             : 
    1843           0 :     gtk_style_context_save(style);
    1844           0 :     gtk_style_context_add_class(style, GTK_STYLE_CLASS_SEPARATOR);
    1845             : 
    1846             :     gtk_style_context_get_style(style,
    1847             :                                 "wide-separators",    &wide_separators,
    1848             :                                 "separator-height",   &separator_height,
    1849           0 :                                 NULL);
    1850             : 
    1851           0 :     if (wide_separators) {
    1852           0 :       gtk_render_frame(style, cr,
    1853           0 :                        x + padding.left,
    1854           0 :                        y + padding.top,
    1855           0 :                        w - padding.left - padding.right,
    1856           0 :                        separator_height);
    1857             :     } else {
    1858           0 :       gtk_render_line(style, cr,
    1859           0 :                       x + padding.left,
    1860           0 :                       y + padding.top,
    1861           0 :                       x + w - padding.right - 1,
    1862           0 :                       y + padding.top);
    1863             :     }
    1864             : 
    1865           0 :     gtk_style_context_restore(style);
    1866           0 :     ReleaseStyleContext(style);
    1867             : 
    1868           0 :     return MOZ_GTK_SUCCESS;
    1869             : }
    1870             : 
    1871             : // See gtk_menu_item_draw() for reference.
    1872             : static gint
    1873           0 : moz_gtk_menu_item_paint(WidgetNodeType widget, cairo_t *cr, GdkRectangle* rect,
    1874             :                         GtkWidgetState* state, GtkTextDirection direction)
    1875             : {
    1876             :     gint x, y, w, h;
    1877           0 :     guint minorVersion = gtk_get_minor_version();
    1878           0 :     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
    1879             : 
    1880             :     // GTK versions prior to 3.8 render the background and frame only when not
    1881             :     // a separator and in hover prelight.
    1882           0 :     if (minorVersion < 8 && (widget == MOZ_GTK_MENUSEPARATOR ||
    1883           0 :                              !(state_flags & GTK_STATE_FLAG_PRELIGHT)))
    1884           0 :         return MOZ_GTK_SUCCESS;
    1885             : 
    1886           0 :     GtkStyleContext* style = ClaimStyleContext(widget, direction, state_flags);
    1887             : 
    1888           0 :     if (minorVersion < 6) {
    1889             :         // GTK+ 3.4 saves the style context and adds the menubar class to
    1890             :         // menubar children, but does each of these only when drawing, not
    1891             :         // during layout.
    1892           0 :         gtk_style_context_save(style);
    1893           0 :         if (widget == MOZ_GTK_MENUBARITEM) {
    1894           0 :             gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
    1895             :         }
    1896             :     }
    1897             : 
    1898           0 :     x = rect->x;
    1899           0 :     y = rect->y;
    1900           0 :     w = rect->width;
    1901           0 :     h = rect->height;
    1902             : 
    1903           0 :     gtk_render_background(style, cr, x, y, w, h);
    1904           0 :     gtk_render_frame(style, cr, x, y, w, h);
    1905             : 
    1906           0 :     if (minorVersion < 6) {
    1907           0 :         gtk_style_context_restore(style);
    1908             :     }
    1909           0 :     ReleaseStyleContext(style);
    1910             : 
    1911           0 :     return MOZ_GTK_SUCCESS;
    1912             : }
    1913             : 
    1914             : static gint
    1915           0 : moz_gtk_menu_arrow_paint(cairo_t *cr, GdkRectangle* rect,
    1916             :                          GtkWidgetState* state,
    1917             :                          GtkTextDirection direction)
    1918             : {
    1919           0 :     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
    1920             :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_MENUITEM,
    1921           0 :                                                direction, state_flags);
    1922           0 :     gtk_render_arrow(style, cr,
    1923             :                     (direction == GTK_TEXT_DIR_LTR) ? ARROW_RIGHT : ARROW_LEFT,
    1924           0 :                     rect->x, rect->y, rect->width);
    1925           0 :     ReleaseStyleContext(style);
    1926           0 :     return MOZ_GTK_SUCCESS;
    1927             : }
    1928             : 
    1929             : // For reference, see gtk_check_menu_item_size_allocate() in GTK versions after
    1930             : // 3.20 and gtk_real_check_menu_item_draw_indicator() in earlier versions.
    1931             : static gint
    1932           0 : moz_gtk_check_menu_item_paint(WidgetNodeType widgetType,
    1933             :                               cairo_t *cr, GdkRectangle* rect,
    1934             :                               GtkWidgetState* state,
    1935             :                               gboolean checked, GtkTextDirection direction)
    1936             : {
    1937           0 :     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
    1938             :     GtkStyleContext* style;
    1939             :     gint indicator_size, horizontal_padding;
    1940             :     gint x, y;
    1941             : 
    1942           0 :     moz_gtk_menu_item_paint(MOZ_GTK_MENUITEM, cr, rect, state, direction);
    1943             : 
    1944           0 :     if (checked) {
    1945           0 :       state_flags = static_cast<GtkStateFlags>(state_flags|checkbox_check_state);
    1946             :     }
    1947             : 
    1948           0 :     bool pre_3_20 = gtk_get_minor_version() < 20;
    1949             :     gint offset;
    1950           0 :     style = ClaimStyleContext(widgetType, direction);
    1951             :     gtk_style_context_get_style(style,
    1952             :                                 "indicator-size", &indicator_size,
    1953             :                                 "horizontal-padding", &horizontal_padding,
    1954           0 :                                 NULL);
    1955           0 :     if (pre_3_20) {
    1956             :         GtkBorder padding;
    1957           0 :         gtk_style_context_get_padding(style, state_flags, &padding);
    1958           0 :         offset = horizontal_padding + padding.left + 2;
    1959             :     } else {
    1960           0 :         GdkRectangle r = { 0 };
    1961           0 :         InsetByMargin(&r, style);
    1962           0 :         InsetByBorderPadding(&r, style);
    1963           0 :         offset = r.x;
    1964             :     }
    1965           0 :     ReleaseStyleContext(style);
    1966             : 
    1967           0 :     bool isRadio = (widgetType == MOZ_GTK_RADIOMENUITEM);
    1968           0 :     WidgetNodeType indicatorType = isRadio ? MOZ_GTK_RADIOMENUITEM_INDICATOR
    1969           0 :                                            : MOZ_GTK_CHECKMENUITEM_INDICATOR;
    1970           0 :     style = ClaimStyleContext(indicatorType, direction, state_flags);
    1971             : 
    1972           0 :     if (direction == GTK_TEXT_DIR_RTL) {
    1973           0 :         x = rect->width - indicator_size - offset;
    1974             :     }
    1975             :     else {
    1976           0 :         x = rect->x + offset;
    1977             :     }
    1978           0 :     y = rect->y + (rect->height - indicator_size) / 2;
    1979             : 
    1980           0 :     if (!pre_3_20) {
    1981           0 :         gtk_render_background(style, cr, x, y, indicator_size, indicator_size);
    1982           0 :         gtk_render_frame(style, cr, x, y, indicator_size, indicator_size);
    1983             :     }
    1984             : 
    1985           0 :     if (isRadio) {
    1986           0 :       gtk_render_option(style, cr, x, y, indicator_size, indicator_size);
    1987             :     } else {
    1988           0 :       gtk_render_check(style, cr, x, y, indicator_size, indicator_size);
    1989             :     }
    1990           0 :     ReleaseStyleContext(style);
    1991             : 
    1992           0 :     return MOZ_GTK_SUCCESS;
    1993             : }
    1994             : 
    1995             : static gint
    1996           0 : moz_gtk_info_bar_paint(cairo_t *cr, GdkRectangle* rect,
    1997             :                        GtkWidgetState* state)
    1998             : {
    1999             :     GtkStyleContext *style =
    2000           0 :         ClaimStyleContext(MOZ_GTK_INFO_BAR, GTK_TEXT_DIR_LTR,
    2001           0 :                           GetStateFlagsFromGtkWidgetState(state));
    2002           0 :     gtk_render_background(style, cr, rect->x, rect->y, rect->width,
    2003           0 :                           rect->height);
    2004           0 :     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
    2005           0 :     ReleaseStyleContext(style);
    2006             : 
    2007           0 :     return MOZ_GTK_SUCCESS;
    2008             : }
    2009             : 
    2010             : static void
    2011          13 : moz_gtk_add_style_margin(GtkStyleContext* style,
    2012             :                          gint* left, gint* top, gint* right, gint* bottom)
    2013             : {
    2014             :     GtkBorder margin;
    2015             : 
    2016          13 :     gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &margin);
    2017             : 
    2018          13 :     *left += margin.left;
    2019          13 :     *right += margin.right;
    2020          13 :     *top += margin.top;
    2021          13 :     *bottom += margin.bottom;
    2022          13 : }
    2023             : 
    2024             : static void
    2025          13 : moz_gtk_add_style_border(GtkStyleContext* style,
    2026             :                          gint* left, gint* top, gint* right, gint* bottom)
    2027             : {
    2028             :     GtkBorder border;
    2029             : 
    2030          13 :     gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
    2031             : 
    2032          13 :     *left += border.left;
    2033          13 :     *right += border.right;
    2034          13 :     *top += border.top;
    2035          13 :     *bottom += border.bottom;
    2036          13 : }
    2037             : 
    2038             : static void
    2039          13 : moz_gtk_add_style_padding(GtkStyleContext* style,
    2040             :                           gint* left, gint* top, gint* right, gint* bottom)
    2041             : {
    2042             :     GtkBorder padding;
    2043             : 
    2044          13 :     gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
    2045             : 
    2046          13 :     *left += padding.left;
    2047          13 :     *right += padding.right;
    2048          13 :     *top += padding.top;
    2049          13 :     *bottom += padding.bottom;
    2050          13 : }
    2051             : 
    2052          13 : static void moz_gtk_add_margin_border_padding(GtkStyleContext *style,
    2053             :                                               gint* left, gint* top,
    2054             :                                               gint* right, gint* bottom)
    2055             : {
    2056          13 :     moz_gtk_add_style_margin(style, left, top, right, bottom);
    2057          13 :     moz_gtk_add_style_border(style, left, top, right, bottom);
    2058          13 :     moz_gtk_add_style_padding(style, left, top, right, bottom);
    2059          13 : }
    2060             : 
    2061             : static GtkBorder
    2062          12 : GetMarginBorderPadding(GtkStyleContext* aStyle)
    2063             : {
    2064          12 :     gint left = 0, top = 0, right = 0, bottom = 0;
    2065          12 :     moz_gtk_add_margin_border_padding(aStyle, &left, &top, &right, &bottom);
    2066             :     // narrowing conversions to gint16:
    2067             :     GtkBorder result;
    2068          12 :     result.left = left;
    2069          12 :     result.right = right;
    2070          12 :     result.top = top;
    2071          12 :     result.bottom = bottom;
    2072          12 :     return result;
    2073             : }
    2074             : 
    2075             : gint
    2076           8 : moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top,
    2077             :                           gint* right, gint* bottom,
    2078             :                           // NOTE: callers depend on direction being used
    2079             :                           // only for MOZ_GTK_DROPDOWN widgets.
    2080             :                           GtkTextDirection direction)
    2081             : {
    2082             :     GtkWidget* w;
    2083             :     GtkStyleContext* style;
    2084           8 :     *left = *top = *right = *bottom = 0;
    2085             : 
    2086           8 :     switch (widget) {
    2087             :     case MOZ_GTK_BUTTON:
    2088             :     case MOZ_GTK_TOOLBAR_BUTTON:
    2089             :         {
    2090           0 :             style = ClaimStyleContext(MOZ_GTK_BUTTON);
    2091             : 
    2092           0 :             *left = *top = *right = *bottom =
    2093           0 :                 gtk_container_get_border_width(GTK_CONTAINER(GetWidget(MOZ_GTK_BUTTON)));
    2094             : 
    2095           0 :             if (widget == MOZ_GTK_TOOLBAR_BUTTON) {
    2096           0 :                 gtk_style_context_save(style);
    2097           0 :                 gtk_style_context_add_class(style, "image-button");
    2098             :             }
    2099             : 
    2100           0 :             moz_gtk_add_style_padding(style, left, top, right, bottom);
    2101             : 
    2102           0 :             if (widget == MOZ_GTK_TOOLBAR_BUTTON)
    2103           0 :                 gtk_style_context_restore(style);
    2104             : 
    2105           0 :             moz_gtk_add_style_border(style, left, top, right, bottom);
    2106             : 
    2107           0 :             ReleaseStyleContext(style);
    2108           0 :             return MOZ_GTK_SUCCESS;
    2109             :         }
    2110             :     case MOZ_GTK_ENTRY:
    2111             :         {
    2112           0 :             style = ClaimStyleContext(MOZ_GTK_ENTRY);
    2113             : 
    2114             :             // XXX: Subtract 1 pixel from the padding to account for the default
    2115             :             // padding in forms.css. See bug 1187385.
    2116           0 :             *left = *top = *right = *bottom = -1;
    2117           0 :             moz_gtk_add_style_padding(style, left, top, right, bottom);
    2118           0 :             moz_gtk_add_style_border(style, left, top, right, bottom);
    2119             : 
    2120           0 :             ReleaseStyleContext(style);
    2121           0 :             return MOZ_GTK_SUCCESS;
    2122             :         }
    2123             :     case MOZ_GTK_TEXT_VIEW:
    2124             :     case MOZ_GTK_TREEVIEW:
    2125             :         {
    2126           0 :             style = ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW);
    2127           0 :             moz_gtk_add_style_border(style, left, top, right, bottom);
    2128           0 :             ReleaseStyleContext(style);
    2129           0 :             return MOZ_GTK_SUCCESS;
    2130             :         }
    2131             :     case MOZ_GTK_TREE_HEADER_CELL:
    2132             :         {
    2133             :             /* A Tree Header in GTK is just a different styled button
    2134             :              * It must be placed in a TreeView for getting the correct style
    2135             :              * assigned.
    2136             :              * That is why the following code is the same as for MOZ_GTK_BUTTON.
    2137             :              * */
    2138           0 :             *left = *top = *right = *bottom =
    2139           0 :                 gtk_container_get_border_width(GTK_CONTAINER(
    2140             :                                                GetWidget(MOZ_GTK_TREE_HEADER_CELL)));
    2141             : 
    2142           0 :             style = ClaimStyleContext(MOZ_GTK_TREE_HEADER_CELL);
    2143           0 :             moz_gtk_add_style_border(style, left, top, right, bottom);
    2144           0 :             moz_gtk_add_style_padding(style, left, top, right, bottom);
    2145           0 :             ReleaseStyleContext(style);
    2146           0 :             return MOZ_GTK_SUCCESS;
    2147             :         }
    2148             :     case MOZ_GTK_TREE_HEADER_SORTARROW:
    2149           0 :         w = GetWidget(MOZ_GTK_TREE_HEADER_SORTARROW);
    2150           0 :         break;
    2151             :     case MOZ_GTK_DROPDOWN_ENTRY:
    2152           0 :         w = GetWidget(MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA);
    2153           0 :         break;
    2154             :     case MOZ_GTK_DROPDOWN_ARROW:
    2155           0 :         w = GetWidget(MOZ_GTK_COMBOBOX_ENTRY_BUTTON);
    2156           0 :         break;
    2157             :     case MOZ_GTK_DROPDOWN:
    2158             :         {
    2159             :             /* We need to account for the arrow on the dropdown, so text
    2160             :              * doesn't come too close to the arrow, or in some cases spill
    2161             :              * into the arrow. */
    2162             :             gboolean wide_separators;
    2163             :             gint separator_width;
    2164             :             GtkRequisition arrow_req;
    2165             :             GtkBorder border;
    2166             : 
    2167           0 :             *left = *top = *right = *bottom =
    2168           0 :                 gtk_container_get_border_width(GTK_CONTAINER(
    2169             :                                                GetWidget(MOZ_GTK_COMBOBOX_BUTTON)));
    2170           0 :             style = ClaimStyleContext(MOZ_GTK_COMBOBOX_BUTTON);
    2171           0 :             moz_gtk_add_style_padding(style, left, top, right, bottom);
    2172           0 :             moz_gtk_add_style_border(style, left, top, right, bottom);
    2173           0 :             ReleaseStyleContext(style);
    2174             : 
    2175             :             /* If there is no separator, don't try to count its width. */
    2176           0 :             separator_width = 0;
    2177           0 :             GtkWidget* comboBoxSeparator = GetWidget(MOZ_GTK_COMBOBOX_SEPARATOR);
    2178           0 :             if (comboBoxSeparator) {
    2179           0 :                 style = gtk_widget_get_style_context(comboBoxSeparator);
    2180             :                 gtk_style_context_get_style(style,
    2181             :                                             "wide-separators", &wide_separators,
    2182             :                                             "separator-width", &separator_width,
    2183           0 :                                             NULL);
    2184             : 
    2185           0 :                 if (!wide_separators) {
    2186             :                     gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL,
    2187           0 :                                                  &border);
    2188           0 :                     separator_width = border.left;
    2189             :                 }
    2190             :             }
    2191             : 
    2192           0 :             gtk_widget_get_preferred_size(GetWidget(MOZ_GTK_COMBOBOX_ARROW),
    2193           0 :                                           NULL, &arrow_req);
    2194             : 
    2195           0 :             if (direction == GTK_TEXT_DIR_RTL)
    2196           0 :                 *left += separator_width + arrow_req.width;
    2197             :             else
    2198           0 :                 *right += separator_width + arrow_req.width;
    2199             : 
    2200           0 :             return MOZ_GTK_SUCCESS;
    2201             :         }
    2202             :     case MOZ_GTK_TABPANELS:
    2203           0 :         w = GetWidget(MOZ_GTK_TABPANELS);
    2204           0 :         break;
    2205             :     case MOZ_GTK_PROGRESSBAR:
    2206           0 :         w = GetWidget(MOZ_GTK_PROGRESSBAR);
    2207           0 :         break;
    2208             :     case MOZ_GTK_SPINBUTTON_ENTRY:
    2209             :     case MOZ_GTK_SPINBUTTON_UP:
    2210             :     case MOZ_GTK_SPINBUTTON_DOWN:
    2211           0 :         w = GetWidget(MOZ_GTK_SPINBUTTON);
    2212           0 :         break;
    2213             :     case MOZ_GTK_SCALE_HORIZONTAL:
    2214             :     case MOZ_GTK_SCALE_VERTICAL:
    2215           0 :         w = GetWidget(widget);
    2216           0 :         break;
    2217             :     case MOZ_GTK_FRAME:
    2218           0 :         w = GetWidget(MOZ_GTK_FRAME);
    2219           0 :         break;
    2220             :     case MOZ_GTK_CHECKBUTTON_CONTAINER:
    2221             :     case MOZ_GTK_RADIOBUTTON_CONTAINER:
    2222             :         {
    2223           0 :             w = GetWidget(widget);
    2224           0 :             style = gtk_widget_get_style_context(w);
    2225             : 
    2226           0 :             *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(w));
    2227             :             moz_gtk_add_style_border(style,
    2228           0 :                                      left, top, right, bottom);
    2229             :             moz_gtk_add_style_padding(style,
    2230           0 :                                       left, top, right, bottom);
    2231           0 :             return MOZ_GTK_SUCCESS;
    2232             :         }
    2233             :     case MOZ_GTK_MENUPOPUP:
    2234           0 :         w = GetWidget(MOZ_GTK_MENUPOPUP);
    2235           0 :         break;
    2236             :     case MOZ_GTK_MENUBARITEM:
    2237             :     case MOZ_GTK_MENUITEM:
    2238             :     case MOZ_GTK_CHECKMENUITEM:
    2239             :     case MOZ_GTK_RADIOMENUITEM:
    2240             :         {
    2241             :             // Bug 1274143 for MOZ_GTK_MENUBARITEM
    2242             :             WidgetNodeType type =
    2243           1 :                 widget == MOZ_GTK_MENUBARITEM ? MOZ_GTK_MENUITEM : widget;
    2244           1 :             style = ClaimStyleContext(type);
    2245             : 
    2246           1 :             if (gtk_get_minor_version() < 20) {
    2247           0 :                 moz_gtk_add_style_padding(style, left, top, right, bottom);
    2248             :             } else {
    2249             :                 moz_gtk_add_margin_border_padding(style,
    2250           1 :                                                   left, top, right, bottom);
    2251             :             }
    2252           1 :             ReleaseStyleContext(style);
    2253           1 :             return MOZ_GTK_SUCCESS;
    2254             :         }
    2255             :     case MOZ_GTK_INFO_BAR:
    2256           0 :         w = GetWidget(MOZ_GTK_INFO_BAR);
    2257           0 :         break;
    2258             :     case MOZ_GTK_TOOLTIP:
    2259             :         {
    2260             :             // In GTK 3 there are 6 pixels of additional margin around the box.
    2261             :             // See details there:
    2262             :             // https://github.com/GNOME/gtk/blob/5ea69a136bd7e4970b3a800390e20314665aaed2/gtk/ui/gtktooltipwindow.ui#L11
    2263           0 :             *left = *right = *top = *bottom = 6;
    2264             : 
    2265             :             // We also need to add margin/padding/borders from Tooltip content.
    2266             :             // Tooltip contains horizontal box, where icon and label is put.
    2267             :             // We ignore icon as long as we don't have support for it.
    2268           0 :             GtkStyleContext* boxStyle = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX);
    2269             :             moz_gtk_add_margin_border_padding(boxStyle,
    2270           0 :                                               left, top, right, bottom);
    2271           0 :             ReleaseStyleContext(boxStyle);
    2272             : 
    2273           0 :             GtkStyleContext* labelStyle = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL);
    2274             :             moz_gtk_add_margin_border_padding(labelStyle,
    2275           0 :                                               left, top, right, bottom);
    2276           0 :             ReleaseStyleContext(labelStyle);
    2277             : 
    2278           0 :             return MOZ_GTK_SUCCESS;
    2279             :         }
    2280             : 
    2281             :     /* These widgets have no borders, since they are not containers. */
    2282             :     case MOZ_GTK_CHECKBUTTON_LABEL:
    2283             :     case MOZ_GTK_RADIOBUTTON_LABEL:
    2284             :     case MOZ_GTK_SPLITTER_HORIZONTAL:
    2285             :     case MOZ_GTK_SPLITTER_VERTICAL:
    2286             :     case MOZ_GTK_CHECKBUTTON:
    2287             :     case MOZ_GTK_RADIOBUTTON:
    2288             :     case MOZ_GTK_SCROLLBAR_BUTTON:
    2289             :     case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
    2290             :     case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
    2291             :     case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
    2292             :     case MOZ_GTK_SCALE_THUMB_VERTICAL:
    2293             :     case MOZ_GTK_GRIPPER:
    2294             :     case MOZ_GTK_PROGRESS_CHUNK:
    2295             :     case MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE:
    2296             :     case MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE:
    2297             :     case MOZ_GTK_TREEVIEW_EXPANDER:
    2298             :     case MOZ_GTK_TOOLBAR_SEPARATOR:
    2299             :     case MOZ_GTK_MENUSEPARATOR:
    2300             :     /* These widgets have no borders.*/
    2301             :     case MOZ_GTK_SPINBUTTON:
    2302             :     case MOZ_GTK_WINDOW:
    2303             :     case MOZ_GTK_RESIZER:
    2304             :     case MOZ_GTK_MENUARROW:
    2305             :     case MOZ_GTK_TOOLBARBUTTON_ARROW:
    2306             :     case MOZ_GTK_TOOLBAR:
    2307             :     case MOZ_GTK_MENUBAR:
    2308             :     case MOZ_GTK_TAB_SCROLLARROW:
    2309           7 :         return MOZ_GTK_SUCCESS;
    2310             :     default:
    2311           0 :         g_warning("Unsupported widget type: %d", widget);
    2312           0 :         return MOZ_GTK_UNKNOWN_WIDGET;
    2313             :     }
    2314             :     /* TODO - we're still missing some widget implementations */
    2315           0 :     if (w) {
    2316           0 :       moz_gtk_add_style_border(gtk_widget_get_style_context(w), 
    2317           0 :                                left, top, right, bottom);
    2318             :     }
    2319           0 :     return MOZ_GTK_SUCCESS;
    2320             : }
    2321             : 
    2322             : gint
    2323           0 : moz_gtk_get_tab_border(gint* left, gint* top, gint* right, gint* bottom, 
    2324             :                        GtkTextDirection direction, GtkTabFlags flags, 
    2325             :                        WidgetNodeType widget)
    2326             : {
    2327           0 :     GtkStyleContext* style = ClaimStyleContext(widget, direction,
    2328           0 :                               GetStateFlagsFromGtkTabFlags(flags));
    2329             : 
    2330           0 :     *left = *top = *right = *bottom = 0;
    2331           0 :     moz_gtk_add_style_padding(style, left, top, right, bottom);
    2332             : 
    2333             :     // Gtk >= 3.20 does not use those styles
    2334           0 :     if (gtk_check_version(3, 20, 0) != nullptr) {
    2335             :         int tab_curvature;
    2336             : 
    2337           0 :         gtk_style_context_get_style(style, "tab-curvature", &tab_curvature, NULL);
    2338           0 :         *left += tab_curvature;
    2339           0 :         *right += tab_curvature;
    2340             : 
    2341           0 :         if (flags & MOZ_GTK_TAB_FIRST) {
    2342           0 :             int initial_gap = 0;
    2343           0 :             gtk_style_context_get_style(style, "initial-gap", &initial_gap, NULL);
    2344           0 :             if (direction == GTK_TEXT_DIR_RTL)
    2345           0 :                 *right += initial_gap;
    2346             :             else
    2347           0 :                 *left += initial_gap;
    2348             :         }
    2349             :     } else {
    2350             :         GtkBorder margin;
    2351             : 
    2352           0 :         gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &margin);
    2353           0 :         *left += margin.left;
    2354           0 :         *right += margin.right;
    2355             : 
    2356           0 :         if (flags & MOZ_GTK_TAB_FIRST) {
    2357           0 :             ReleaseStyleContext(style);
    2358           0 :             style = ClaimStyleContext(MOZ_GTK_NOTEBOOK_HEADER, direction);
    2359           0 :             gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &margin);
    2360           0 :             *left += margin.left;
    2361           0 :             *right += margin.right;
    2362             :         }
    2363             :     }
    2364             : 
    2365           0 :     ReleaseStyleContext(style);
    2366           0 :     return MOZ_GTK_SUCCESS;
    2367             : }
    2368             : 
    2369             : gint
    2370           0 : moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height)
    2371             : {
    2372             :     /*
    2373             :      * We get the requisition of the drop down button, which includes
    2374             :      * all padding, border and focus line widths the button uses,
    2375             :      * as well as the minimum arrow size and its padding
    2376             :      * */
    2377             :     GtkRequisition requisition;
    2378             : 
    2379           0 :     gtk_widget_get_preferred_size(GetWidget(MOZ_GTK_COMBOBOX_ENTRY_BUTTON),
    2380           0 :                                   NULL, &requisition);
    2381           0 :     *width = requisition.width;
    2382           0 :     *height = requisition.height;
    2383             : 
    2384           0 :     return MOZ_GTK_SUCCESS;
    2385             : }
    2386             : 
    2387             : gint
    2388           0 : moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height)
    2389             : {
    2390             :     gint arrow_size;
    2391             : 
    2392           0 :     GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_TABPANELS);
    2393             :     gtk_style_context_get_style(style,
    2394             :                                 "scroll-arrow-hlength", &arrow_size,
    2395           0 :                                 NULL);
    2396           0 :     ReleaseStyleContext(style);
    2397             : 
    2398           0 :     *height = *width = arrow_size;
    2399             : 
    2400           0 :     return MOZ_GTK_SUCCESS;
    2401             : }
    2402             : 
    2403             : void
    2404           2 : moz_gtk_get_arrow_size(WidgetNodeType widgetType, gint* width, gint* height)
    2405             : {
    2406             :     GtkWidget* widget;
    2407           2 :     switch (widgetType) {
    2408             :         case MOZ_GTK_DROPDOWN:
    2409           0 :             widget = GetWidget(MOZ_GTK_COMBOBOX_ARROW);
    2410           0 :             break;
    2411             :         default:
    2412           2 :             widget = GetWidget(MOZ_GTK_BUTTON_ARROW);
    2413           2 :             break;
    2414             :     }
    2415             : 
    2416             :     GtkRequisition requisition;
    2417           2 :     gtk_widget_get_preferred_size(widget, NULL, &requisition);
    2418           2 :     *width = requisition.width;
    2419           2 :     *height = requisition.height;
    2420           2 : }
    2421             : 
    2422             : gint
    2423           0 : moz_gtk_get_toolbar_separator_width(gint* size)
    2424             : {
    2425             :     gboolean wide_separators;
    2426             :     gint separator_width;
    2427             :     GtkBorder border;
    2428             : 
    2429           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLBAR);
    2430             :     gtk_style_context_get_style(style,
    2431             :                                 "space-size", size,
    2432             :                                 "wide-separators",  &wide_separators,
    2433             :                                 "separator-width", &separator_width,
    2434           0 :                                 NULL);
    2435             :     /* Just in case... */
    2436           0 :     gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
    2437           0 :     *size = MAX(*size, (wide_separators ? separator_width : border.left));
    2438           0 :     ReleaseStyleContext(style);
    2439           0 :     return MOZ_GTK_SUCCESS;
    2440             : }
    2441             : 
    2442             : gint
    2443           0 : moz_gtk_get_expander_size(gint* size)
    2444             : {
    2445           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_EXPANDER);
    2446             :     gtk_style_context_get_style(style,
    2447             :                                 "expander-size", size,
    2448           0 :                                 NULL);
    2449           0 :     ReleaseStyleContext(style);
    2450           0 :     return MOZ_GTK_SUCCESS;
    2451             : }
    2452             : 
    2453             : gint
    2454           0 : moz_gtk_get_treeview_expander_size(gint* size)
    2455             : {
    2456           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TREEVIEW);
    2457           0 :     gtk_style_context_get_style(style, "expander-size", size, NULL);
    2458           0 :     ReleaseStyleContext(style);
    2459           0 :     return MOZ_GTK_SUCCESS;
    2460             : }
    2461             : 
    2462             : // See gtk_menu_item_draw() for reference.
    2463             : gint
    2464           0 : moz_gtk_get_menu_separator_height(gint *size)
    2465             : {
    2466             :     gboolean  wide_separators;
    2467             :     gint      separator_height;
    2468             :     GtkBorder padding;
    2469           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_MENUSEPARATOR);
    2470           0 :     gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
    2471             : 
    2472           0 :     gtk_style_context_save(style);
    2473           0 :     gtk_style_context_add_class(style, GTK_STYLE_CLASS_SEPARATOR);
    2474             : 
    2475             :     gtk_style_context_get_style(style,
    2476             :                                 "wide-separators",  &wide_separators,
    2477             :                                 "separator-height", &separator_height,
    2478           0 :                                 NULL);
    2479             : 
    2480           0 :     gtk_style_context_restore(style);
    2481           0 :     ReleaseStyleContext(style);
    2482             : 
    2483           0 :     *size = padding.top + padding.bottom;
    2484           0 :     *size += (wide_separators) ? separator_height : 1;
    2485             : 
    2486           0 :     return MOZ_GTK_SUCCESS;
    2487             : }
    2488             : 
    2489             : void
    2490           0 : moz_gtk_get_entry_min_height(gint* height)
    2491             : {
    2492           0 :     GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_ENTRY);
    2493           0 :     if (!gtk_check_version(3, 20, 0)) {
    2494           0 :         gtk_style_context_get(style, gtk_style_context_get_state(style),
    2495             :                               "min-height", height,
    2496           0 :                               nullptr);
    2497             :     } else {
    2498           0 :         *height = 0;
    2499             :     }
    2500             : 
    2501             :     GtkBorder border;
    2502             :     GtkBorder padding;
    2503           0 :     gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
    2504           0 :     gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
    2505             : 
    2506           0 :     *height += (border.top + border.bottom + padding.top + padding.bottom);
    2507           0 :     ReleaseStyleContext(style);
    2508           0 : }
    2509             : 
    2510             : void
    2511           0 : moz_gtk_get_scale_metrics(GtkOrientation orient, gint* scale_width,
    2512             :                           gint* scale_height)
    2513             : {
    2514           0 :   if (gtk_check_version(3, 20, 0) != nullptr) {
    2515           0 :       WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ?
    2516             :                                MOZ_GTK_SCALE_HORIZONTAL :
    2517           0 :                                MOZ_GTK_SCALE_VERTICAL;
    2518             : 
    2519             :       gint thumb_length, thumb_height, trough_border;
    2520           0 :       moz_gtk_get_scalethumb_metrics(orient, &thumb_length, &thumb_height);
    2521             : 
    2522           0 :       GtkStyleContext* style = ClaimStyleContext(widget);
    2523           0 :       gtk_style_context_get_style(style, "trough-border", &trough_border, NULL);
    2524             : 
    2525           0 :       if (orient == GTK_ORIENTATION_HORIZONTAL) {
    2526           0 :           *scale_width = thumb_length + trough_border * 2;
    2527           0 :           *scale_height = thumb_height + trough_border * 2;
    2528             :       } else {
    2529           0 :           *scale_width = thumb_height + trough_border * 2;
    2530           0 :           *scale_height = thumb_length + trough_border * 2;
    2531             :       }
    2532           0 :       ReleaseStyleContext(style);
    2533             :   } else {
    2534           0 :       WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ?
    2535             :                                MOZ_GTK_SCALE_TROUGH_HORIZONTAL :
    2536           0 :                                MOZ_GTK_SCALE_TROUGH_VERTICAL;
    2537           0 :       moz_gtk_get_widget_min_size(widget, scale_width, scale_height);
    2538             :   }
    2539           0 : }
    2540             : 
    2541             : gint
    2542           0 : moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height)
    2543             : {
    2544             : 
    2545           0 :   if (gtk_check_version(3, 20, 0) != nullptr) {
    2546           0 :       WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ?
    2547             :                                MOZ_GTK_SCALE_HORIZONTAL:
    2548           0 :                                MOZ_GTK_SCALE_VERTICAL;
    2549           0 :       GtkStyleContext* style = ClaimStyleContext(widget);
    2550             :       gtk_style_context_get_style(style,
    2551             :                                   "slider_length", thumb_length,
    2552             :                                   "slider_width", thumb_height,
    2553           0 :                                   NULL);
    2554           0 :       ReleaseStyleContext(style);
    2555             :   } else {
    2556           0 :       WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ?
    2557             :                                MOZ_GTK_SCALE_THUMB_HORIZONTAL:
    2558           0 :                                MOZ_GTK_SCALE_THUMB_VERTICAL;
    2559           0 :       GtkStyleContext* style = ClaimStyleContext(widget);
    2560             : 
    2561             :       gint min_width, min_height;
    2562           0 :       GtkStateFlags state = gtk_style_context_get_state(style);
    2563             :       gtk_style_context_get(style, state,
    2564             :                             "min-width", &min_width,
    2565             :                             "min-height", &min_height,
    2566           0 :                              nullptr);
    2567             :       GtkBorder margin;
    2568           0 :       gtk_style_context_get_margin(style, state, &margin);
    2569           0 :       gint margin_width = margin.left + margin.right;
    2570           0 :       gint margin_height = margin.top + margin.bottom;
    2571             : 
    2572             :       // Negative margin of slider element also determines its minimal size
    2573             :       // so use bigger of those two values.
    2574           0 :       if (min_width < -margin_width)
    2575           0 :           min_width = -margin_width;
    2576           0 :       if (min_height < -margin_height)
    2577           0 :           min_height = -margin_height;
    2578             : 
    2579           0 :       *thumb_length = min_width;
    2580           0 :       *thumb_height = min_height;
    2581             : 
    2582           0 :       ReleaseStyleContext(style);
    2583             :   }
    2584             : 
    2585           0 :   return MOZ_GTK_SUCCESS;
    2586             : }
    2587             : 
    2588             : static MozGtkSize
    2589           0 : SizeFromLengthAndBreadth(GtkOrientation aOrientation,
    2590             :                          gint aLength, gint aBreadth)
    2591             : {
    2592             :     return aOrientation == GTK_ORIENTATION_HORIZONTAL ?
    2593           0 :         MozGtkSize({aLength, aBreadth}) : MozGtkSize({aBreadth, aLength});
    2594             : }
    2595             : 
    2596             : const ScrollbarGTKMetrics*
    2597         102 : GetScrollbarMetrics(GtkOrientation aOrientation)
    2598             : {
    2599         102 :     auto metrics = &sScrollbarMetrics[aOrientation];
    2600         102 :     if (metrics->initialized)
    2601          98 :         return metrics;
    2602             : 
    2603           4 :     metrics->initialized = true;
    2604             : 
    2605           4 :     WidgetNodeType scrollbar = aOrientation == GTK_ORIENTATION_HORIZONTAL ?
    2606           4 :         MOZ_GTK_SCROLLBAR_HORIZONTAL : MOZ_GTK_SCROLLBAR_VERTICAL;
    2607             : 
    2608             :     gboolean backward, forward, secondary_backward, secondary_forward;
    2609           4 :     GtkStyleContext* style = ClaimStyleContext(scrollbar);
    2610             :     gtk_style_context_get_style(style,
    2611             :                                 "has-backward-stepper", &backward,
    2612             :                                 "has-forward-stepper", &forward,
    2613             :                                 "has-secondary-backward-stepper",
    2614             :                                 &secondary_backward,
    2615             :                                 "has-secondary-forward-stepper",
    2616           4 :                                 &secondary_forward, nullptr);
    2617             :     bool hasButtons =
    2618           4 :         backward || forward || secondary_backward || secondary_forward;
    2619             : 
    2620           4 :     if (gtk_get_minor_version() < 20) {
    2621             :         gint slider_width, trough_border, stepper_size, min_slider_size;
    2622             : 
    2623             :         gtk_style_context_get_style(style,
    2624             :                                     "slider-width", &slider_width,
    2625             :                                     "trough-border", &trough_border,
    2626             :                                     "stepper-size", &stepper_size,
    2627             :                                     "min-slider-length", &min_slider_size,
    2628           0 :                                     nullptr);
    2629           0 :         ReleaseStyleContext(style);
    2630             : 
    2631             :         metrics->size.thumb =
    2632           0 :             SizeFromLengthAndBreadth(aOrientation, min_slider_size, slider_width);
    2633             :         metrics->size.button =
    2634           0 :             SizeFromLengthAndBreadth(aOrientation, stepper_size, slider_width);
    2635             :         // overall scrollbar
    2636           0 :         gint breadth = slider_width + 2 * trough_border;
    2637             :         // Require room for the slider in the track if we don't have buttons.
    2638           0 :         gint length = hasButtons ? 0 : min_slider_size + 2 * trough_border;
    2639             :         metrics->size.scrollbar =
    2640           0 :             SizeFromLengthAndBreadth(aOrientation, length, breadth);
    2641             : 
    2642             :         // Borders on the major axis are set on the outermost scrollbar
    2643             :         // element to correctly position the buttons when
    2644             :         // trough-under-steppers is true.
    2645             :         // Borders on the minor axis are set on the track element so that it
    2646             :         // receives mouse events, as in GTK.
    2647             :         // Other borders have been zero-initialized.
    2648           0 :         if (aOrientation == GTK_ORIENTATION_HORIZONTAL) {
    2649           0 :             metrics->border.scrollbar.left =
    2650           0 :                 metrics->border.scrollbar.right =
    2651           0 :                 metrics->border.track.top =
    2652           0 :                 metrics->border.track.bottom = trough_border;
    2653             :         } else {
    2654           0 :             metrics->border.scrollbar.top =
    2655           0 :                 metrics->border.scrollbar.bottom =
    2656           0 :                 metrics->border.track.left =
    2657           0 :                 metrics->border.track.right = trough_border;
    2658             :         }
    2659             : 
    2660           0 :         return metrics;
    2661             :     }
    2662             : 
    2663             :     // GTK version > 3.20
    2664             :     // scrollbar
    2665           4 :     metrics->border.scrollbar = GetMarginBorderPadding(style);
    2666           4 :     ReleaseStyleContext(style);
    2667             : 
    2668             :     WidgetNodeType contents, track, thumb;
    2669           4 :     if (aOrientation == GTK_ORIENTATION_HORIZONTAL) {
    2670           2 :         contents = MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL;
    2671           2 :         track = MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL;
    2672           2 :         thumb = MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
    2673             :     } else {
    2674           2 :         contents = MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL;
    2675           2 :         track = MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL;
    2676           2 :         thumb = MOZ_GTK_SCROLLBAR_THUMB_VERTICAL;
    2677             :     }
    2678             :     // thumb
    2679           4 :     metrics->size.thumb = GetMinMarginBox(thumb);
    2680             :     // track
    2681           4 :     style = ClaimStyleContext(track);
    2682           4 :     metrics->border.track = GetMarginBorderPadding(style);
    2683           4 :     MozGtkSize trackMinSize = GetMinContentBox(style) + metrics->border.track;
    2684           4 :     ReleaseStyleContext(style);
    2685           4 :     MozGtkSize trackSizeForThumb = metrics->size.thumb + metrics->border.track;
    2686             :     // button
    2687           4 :     if (hasButtons) {
    2688           0 :         metrics->size.button = GetMinMarginBox(MOZ_GTK_SCROLLBAR_BUTTON);
    2689             :     } else {
    2690           4 :         metrics->size.button = {0, 0};
    2691             :     }
    2692           4 :     if (aOrientation == GTK_ORIENTATION_HORIZONTAL) {
    2693           2 :         metrics->size.button.Rotate();
    2694             :         // If the track is wider than necessary for the thumb, including when
    2695             :         // the buttons will cause Gecko to expand the track to fill
    2696             :         // available breadth, then add to the track border to prevent Gecko
    2697             :         // from expanding the thumb to fill available breadth.
    2698             :         gint extra =
    2699           2 :             std::max(trackMinSize.height,
    2700           4 :                      metrics->size.button.height) - trackSizeForThumb.height;
    2701           2 :         if (extra > 0) {
    2702             :             // If extra is odd, then the thumb is 0.5 pixels above
    2703             :             // center as in gtk_range_compute_slider_position().
    2704           0 :             metrics->border.track.top += extra / 2;
    2705           0 :             metrics->border.track.bottom += extra - extra / 2;
    2706             :             // Update size for change in border.
    2707           0 :             trackSizeForThumb.height += extra;
    2708             :         }
    2709             :     } else {
    2710             :         gint extra =
    2711           2 :             std::max(trackMinSize.width,
    2712           4 :                      metrics->size.button.width) - trackSizeForThumb.width;
    2713           2 :         if (extra > 0) {
    2714             :             // If extra is odd, then the thumb is 0.5 pixels to the left
    2715             :             // of center as in gtk_range_compute_slider_position().
    2716           0 :             metrics->border.track.left += extra / 2;
    2717           0 :             metrics->border.track.right += extra - extra / 2;
    2718           0 :             trackSizeForThumb.width += extra;
    2719             :         }
    2720             :     }
    2721             : 
    2722           4 :     style = ClaimStyleContext(contents);
    2723           4 :     GtkBorder contentsBorder = GetMarginBorderPadding(style);
    2724           4 :     ReleaseStyleContext(style);
    2725             : 
    2726             :     metrics->size.scrollbar =
    2727           4 :         trackSizeForThumb + contentsBorder + metrics->border.scrollbar;
    2728             : 
    2729           4 :     return metrics;
    2730             : }
    2731             : 
    2732             : /* cairo_t *cr argument has to be a system-cairo. */
    2733             : gint
    2734          18 : moz_gtk_widget_paint(WidgetNodeType widget, cairo_t *cr,
    2735             :                      GdkRectangle* rect,
    2736             :                      GtkWidgetState* state, gint flags,
    2737             :                      GtkTextDirection direction)
    2738             : {
    2739             :     /* A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=694086
    2740             :      */
    2741          18 :     cairo_new_path(cr);
    2742             : 
    2743          18 :     switch (widget) {
    2744             :     case MOZ_GTK_BUTTON:
    2745             :     case MOZ_GTK_TOOLBAR_BUTTON:
    2746           0 :         if (state->depressed) {
    2747           0 :             return moz_gtk_button_paint(cr, rect, state,
    2748             :                                         (GtkReliefStyle) flags,
    2749             :                                         GetWidget(MOZ_GTK_TOGGLE_BUTTON),
    2750           0 :                                         direction);
    2751             :         }
    2752           0 :         return moz_gtk_button_paint(cr, rect, state,
    2753             :                                     (GtkReliefStyle) flags,
    2754             :                                     GetWidget(MOZ_GTK_BUTTON),
    2755           0 :                                     direction);
    2756             :         break;
    2757             :     case MOZ_GTK_CHECKBUTTON:
    2758             :     case MOZ_GTK_RADIOBUTTON:
    2759           0 :         return moz_gtk_toggle_paint(cr, rect, state,
    2760           0 :                                     !!(flags & MOZ_GTK_WIDGET_CHECKED),
    2761           0 :                                     !!(flags & MOZ_GTK_WIDGET_INCONSISTENT),
    2762             :                                     (widget == MOZ_GTK_RADIOBUTTON),
    2763           0 :                                     direction);
    2764             :         break;
    2765             :     case MOZ_GTK_SCROLLBAR_BUTTON:
    2766           0 :         return moz_gtk_scrollbar_button_paint(cr, rect, state,
    2767             :                                               (GtkScrollbarButtonFlags) flags,
    2768           0 :                                               direction);
    2769             :         break;
    2770             :     case MOZ_GTK_SCROLLBAR_HORIZONTAL:
    2771             :     case MOZ_GTK_SCROLLBAR_VERTICAL:
    2772           0 :         if (flags & MOZ_GTK_TRACK_OPAQUE) {
    2773             :             GtkStyleContext* style =
    2774           0 :                 ClaimStyleContext(MOZ_GTK_WINDOW, direction);
    2775           0 :             gtk_render_background(style, cr,
    2776           0 :                                   rect->x, rect->y, rect->width, rect->height);
    2777           0 :             ReleaseStyleContext(style);
    2778             :         }
    2779           0 :         if (gtk_check_version(3,20,0) == nullptr) {
    2780           0 :           return moz_gtk_scrollbar_paint(widget, cr, rect, state, direction);
    2781             :         } else {
    2782           0 :           WidgetNodeType trough_widget = (widget == MOZ_GTK_SCROLLBAR_HORIZONTAL) ?
    2783           0 :               MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL : MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL;
    2784             :           return moz_gtk_scrollbar_trough_paint(trough_widget, cr, rect,
    2785           0 :                                                 state, direction);
    2786             :         }
    2787             :         break;
    2788             :     case MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL:
    2789             :     case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL:
    2790           0 :         if (gtk_check_version(3,20,0) == nullptr) {
    2791             :           return moz_gtk_scrollbar_trough_paint(widget, cr, rect,
    2792           0 :                                                 state, direction);
    2793             :         }
    2794           0 :         break;
    2795             :     case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
    2796             :     case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
    2797             :         return moz_gtk_scrollbar_thumb_paint(widget, cr, rect,
    2798           0 :                                              state, direction);
    2799             :         break;
    2800             :     case MOZ_GTK_SCALE_HORIZONTAL:
    2801             :     case MOZ_GTK_SCALE_VERTICAL:
    2802           0 :         return moz_gtk_scale_paint(cr, rect, state,
    2803           0 :                                    (GtkOrientation) flags, direction);
    2804             :         break;
    2805             :     case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
    2806             :     case MOZ_GTK_SCALE_THUMB_VERTICAL:
    2807           0 :         return moz_gtk_scale_thumb_paint(cr, rect, state,
    2808           0 :                                          (GtkOrientation) flags, direction);
    2809             :         break;
    2810             :     case MOZ_GTK_SPINBUTTON:
    2811           0 :         return moz_gtk_spin_paint(cr, rect, direction);
    2812             :         break;
    2813             :     case MOZ_GTK_SPINBUTTON_UP:
    2814             :     case MOZ_GTK_SPINBUTTON_DOWN:
    2815           0 :         return moz_gtk_spin_updown_paint(cr, rect,
    2816             :                                          (widget == MOZ_GTK_SPINBUTTON_DOWN),
    2817           0 :                                          state, direction);
    2818             :         break;
    2819             :     case MOZ_GTK_SPINBUTTON_ENTRY:
    2820             :         {
    2821           0 :             GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SPINBUTTON_ENTRY,
    2822           0 :                                      direction, GetStateFlagsFromGtkWidgetState(state));
    2823           0 :             gint ret = moz_gtk_entry_paint(cr, rect, state, style);
    2824           0 :             ReleaseStyleContext(style);
    2825           0 :             return ret;
    2826             :         }
    2827             :         break;
    2828             :     case MOZ_GTK_GRIPPER:
    2829             :         return moz_gtk_gripper_paint(cr, rect, state,
    2830           0 :                                      direction);
    2831             :         break;
    2832             :     case MOZ_GTK_TREEVIEW:
    2833             :         return moz_gtk_treeview_paint(cr, rect, state,
    2834           0 :                                       direction);
    2835             :         break;
    2836             :     case MOZ_GTK_TREE_HEADER_CELL:
    2837             :         return moz_gtk_tree_header_cell_paint(cr, rect, state,
    2838           0 :                                               flags, direction);
    2839             :         break;
    2840             :     case MOZ_GTK_TREE_HEADER_SORTARROW:
    2841           0 :         return moz_gtk_tree_header_sort_arrow_paint(cr, rect, 
    2842             :                                                     state,
    2843             :                                                     (GtkArrowType) flags,
    2844           0 :                                                     direction);
    2845             :         break;
    2846             :     case MOZ_GTK_TREEVIEW_EXPANDER:
    2847           0 :         return moz_gtk_treeview_expander_paint(cr, rect, state,
    2848           0 :                                                (GtkExpanderStyle) flags, direction);
    2849             :         break;
    2850             :     case MOZ_GTK_ENTRY:
    2851             :         {
    2852           0 :             GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_ENTRY,
    2853           0 :                                      direction, GetStateFlagsFromGtkWidgetState(state));
    2854           0 :             gint ret = moz_gtk_entry_paint(cr, rect, state, style);
    2855           0 :             ReleaseStyleContext(style);
    2856           0 :             return ret;
    2857             :         }
    2858             :     case MOZ_GTK_TEXT_VIEW:
    2859           0 :         return moz_gtk_text_view_paint(cr, rect, state, direction);
    2860             :         break;
    2861             :     case MOZ_GTK_DROPDOWN:
    2862           0 :         return moz_gtk_combo_box_paint(cr, rect, state, direction);
    2863             :         break;
    2864             :     case MOZ_GTK_DROPDOWN_ARROW:
    2865             :         return moz_gtk_combo_box_entry_button_paint(cr, rect,
    2866           0 :                                                     state, flags, direction);
    2867             :         break;
    2868             :     case MOZ_GTK_DROPDOWN_ENTRY:
    2869             :         {
    2870           0 :             GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA,
    2871           0 :                                      direction, GetStateFlagsFromGtkWidgetState(state));
    2872           0 :             gint ret = moz_gtk_entry_paint(cr, rect, state, style);
    2873           0 :             ReleaseStyleContext(style);
    2874           0 :             return ret;
    2875             :         }
    2876             :         break;
    2877             :     case MOZ_GTK_CHECKBUTTON_CONTAINER:
    2878             :     case MOZ_GTK_RADIOBUTTON_CONTAINER:
    2879           0 :         return moz_gtk_container_paint(cr, rect, state, widget, direction);
    2880             :         break;
    2881             :     case MOZ_GTK_CHECKBUTTON_LABEL:
    2882             :     case MOZ_GTK_RADIOBUTTON_LABEL:
    2883           0 :         return moz_gtk_toggle_label_paint(cr, rect, state,
    2884             :                                           (widget == MOZ_GTK_RADIOBUTTON_LABEL),
    2885           0 :                                           direction);
    2886             :         break;
    2887             :     case MOZ_GTK_TOOLBAR:
    2888           0 :         return moz_gtk_toolbar_paint(cr, rect, direction);
    2889             :         break;
    2890             :     case MOZ_GTK_TOOLBAR_SEPARATOR:
    2891             :         return moz_gtk_toolbar_separator_paint(cr, rect,
    2892           0 :                                                direction);
    2893             :         break;
    2894             :     case MOZ_GTK_TOOLTIP:
    2895           0 :         return moz_gtk_tooltip_paint(cr, rect, direction);
    2896             :         break;
    2897             :     case MOZ_GTK_FRAME:
    2898           0 :         return moz_gtk_frame_paint(cr, rect, direction);
    2899             :         break;
    2900             :     case MOZ_GTK_RESIZER:
    2901             :         return moz_gtk_resizer_paint(cr, rect, state,
    2902           0 :                                      direction);
    2903             :         break;
    2904             :     case MOZ_GTK_PROGRESSBAR:
    2905           0 :         return moz_gtk_progressbar_paint(cr, rect, direction);
    2906             :         break;
    2907             :     case MOZ_GTK_PROGRESS_CHUNK:
    2908             :     case MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE:
    2909             :     case MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE:
    2910             :         return moz_gtk_progress_chunk_paint(cr, rect,
    2911           0 :                                             direction, widget);
    2912             :         break;
    2913             :     case MOZ_GTK_TAB_TOP:
    2914             :     case MOZ_GTK_TAB_BOTTOM:
    2915           0 :         return moz_gtk_tab_paint(cr, rect, state,
    2916           0 :                                  (GtkTabFlags) flags, direction, widget);
    2917             :         break;
    2918             :     case MOZ_GTK_TABPANELS:
    2919           0 :         return moz_gtk_tabpanels_paint(cr, rect, direction);
    2920             :         break;
    2921             :     case MOZ_GTK_TAB_SCROLLARROW:
    2922           0 :         return moz_gtk_tab_scroll_arrow_paint(cr, rect, state,
    2923           0 :                                               (GtkArrowType) flags, direction);
    2924             :         break;
    2925             :     case MOZ_GTK_MENUBAR:
    2926           9 :         return moz_gtk_menu_bar_paint(cr, rect, direction);
    2927             :         break;
    2928             :     case MOZ_GTK_MENUPOPUP:
    2929           0 :         return moz_gtk_menu_popup_paint(cr, rect, direction);
    2930             :         break;
    2931             :     case MOZ_GTK_MENUSEPARATOR:
    2932             :         return moz_gtk_menu_separator_paint(cr, rect,
    2933           0 :                                             direction);
    2934             :         break;
    2935             :     case MOZ_GTK_MENUBARITEM:
    2936             :     case MOZ_GTK_MENUITEM:
    2937           0 :         return moz_gtk_menu_item_paint(widget, cr, rect, state, direction);
    2938             :         break;
    2939             :     case MOZ_GTK_MENUARROW:
    2940             :         return moz_gtk_menu_arrow_paint(cr, rect, state,
    2941           0 :                                         direction);
    2942             :         break;
    2943             :     case MOZ_GTK_TOOLBARBUTTON_ARROW:
    2944           0 :         return moz_gtk_arrow_paint(cr, rect, state,
    2945           0 :                                    (GtkArrowType) flags, direction);
    2946             :         break;
    2947             :     case MOZ_GTK_CHECKMENUITEM:
    2948             :     case MOZ_GTK_RADIOMENUITEM:
    2949             :         return moz_gtk_check_menu_item_paint(widget, cr, rect, state,
    2950           0 :                                              (gboolean) flags, direction);
    2951             :         break;
    2952             :     case MOZ_GTK_SPLITTER_HORIZONTAL:
    2953           0 :         return moz_gtk_vpaned_paint(cr, rect, state);
    2954             :         break;
    2955             :     case MOZ_GTK_SPLITTER_VERTICAL:
    2956           0 :         return moz_gtk_hpaned_paint(cr, rect, state);
    2957             :         break;
    2958             :     case MOZ_GTK_WINDOW:
    2959           9 :         return moz_gtk_window_paint(cr, rect, direction);
    2960             :         break;
    2961             :     case MOZ_GTK_INFO_BAR:
    2962           0 :         return moz_gtk_info_bar_paint(cr, rect, state);
    2963             :         break;
    2964             :     default:
    2965           0 :         g_warning("Unknown widget type: %d", widget);
    2966             :     }
    2967             : 
    2968           0 :     return MOZ_GTK_UNKNOWN_WIDGET;
    2969             : }
    2970             : 
    2971             : gint
    2972           0 : moz_gtk_shutdown()
    2973             : {
    2974             :     /* This will destroy all of our widgets */
    2975           0 :     ResetWidgetCache();
    2976             : 
    2977           0 :     return MOZ_GTK_SUCCESS;
    2978           9 : }

Generated by: LCOV version 1.13