LCOV - code coverage report
Current view: top level - widget/gtk - nsNativeThemeGTK.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 356 889 40.0 %
Date: 2017-07-14 16:53:18 Functions: 32 46 69.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       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             : #include "nsNativeThemeGTK.h"
       7             : #include "nsThemeConstants.h"
       8             : #include "gtkdrawing.h"
       9             : #include "ScreenHelperGTK.h"
      10             : 
      11             : #include "gfx2DGlue.h"
      12             : #include "nsIObserverService.h"
      13             : #include "nsIServiceManager.h"
      14             : #include "nsIFrame.h"
      15             : #include "nsIPresShell.h"
      16             : #include "nsIContent.h"
      17             : #include "nsViewManager.h"
      18             : #include "nsNameSpaceManager.h"
      19             : #include "nsGfxCIID.h"
      20             : #include "nsTransform2D.h"
      21             : #include "nsMenuFrame.h"
      22             : #include "prlink.h"
      23             : #include "nsIDOMHTMLInputElement.h"
      24             : #include "nsGkAtoms.h"
      25             : #include "nsAttrValueInlines.h"
      26             : 
      27             : #include "mozilla/EventStates.h"
      28             : #include "mozilla/Services.h"
      29             : 
      30             : #include <gdk/gdkprivate.h>
      31             : #include <gtk/gtk.h>
      32             : 
      33             : #include "gfxContext.h"
      34             : #include "gfxPlatformGtk.h"
      35             : #include "gfxGdkNativeRenderer.h"
      36             : #include "mozilla/gfx/BorrowedContext.h"
      37             : #include "mozilla/gfx/HelpersCairo.h"
      38             : #include "mozilla/gfx/PathHelpers.h"
      39             : 
      40             : #ifdef MOZ_X11
      41             : #  ifdef CAIRO_HAS_XLIB_SURFACE
      42             : #    include "cairo-xlib.h"
      43             : #  endif
      44             : #  ifdef CAIRO_HAS_XLIB_XRENDER_SURFACE
      45             : #    include "cairo-xlib-xrender.h"
      46             : #  endif
      47             : #endif
      48             : 
      49             : #include <algorithm>
      50             : #include <dlfcn.h>
      51             : 
      52             : using namespace mozilla;
      53             : using namespace mozilla::gfx;
      54             : 
      55          21 : NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeGTK, nsNativeTheme, nsITheme,
      56             :                                                              nsIObserver)
      57             : 
      58             : static int gLastGdkError;
      59             : 
      60           2 : nsNativeThemeGTK::nsNativeThemeGTK()
      61             : {
      62           2 :   if (moz_gtk_init() != MOZ_GTK_SUCCESS) {
      63           0 :     memset(mDisabledWidgetTypes, 0xff, sizeof(mDisabledWidgetTypes));
      64           0 :     return;
      65             :   }
      66             : 
      67             :   // We have to call moz_gtk_shutdown before the event loop stops running.
      68             :   nsCOMPtr<nsIObserverService> obsServ =
      69           4 :     mozilla::services::GetObserverService();
      70           2 :   obsServ->AddObserver(this, "xpcom-shutdown", false);
      71             : 
      72           2 :   ThemeChanged();
      73             : }
      74             : 
      75           0 : nsNativeThemeGTK::~nsNativeThemeGTK() {
      76           0 : }
      77             : 
      78             : NS_IMETHODIMP
      79           0 : nsNativeThemeGTK::Observe(nsISupports *aSubject, const char *aTopic,
      80             :                           const char16_t *aData)
      81             : {
      82           0 :   if (!nsCRT::strcmp(aTopic, "xpcom-shutdown")) {
      83           0 :     moz_gtk_shutdown();
      84             :   } else {
      85           0 :     NS_NOTREACHED("unexpected topic");
      86           0 :     return NS_ERROR_UNEXPECTED;
      87             :   }
      88             : 
      89           0 :   return NS_OK;
      90             : }
      91             : 
      92             : void
      93           0 : nsNativeThemeGTK::RefreshWidgetWindow(nsIFrame* aFrame)
      94             : {
      95           0 :   nsIPresShell *shell = GetPresShell(aFrame);
      96           0 :   if (!shell)
      97           0 :     return;
      98             : 
      99           0 :   nsViewManager* vm = shell->GetViewManager();
     100           0 :   if (!vm)
     101           0 :     return;
     102             :  
     103           0 :   vm->InvalidateAllViews();
     104             : }
     105             : 
     106             : 
     107          18 : static bool IsFrameContentNodeInNamespace(nsIFrame *aFrame, uint32_t aNamespace)
     108             : {
     109          18 :   nsIContent *content = aFrame ? aFrame->GetContent() : nullptr;
     110          18 :   if (!content)
     111           0 :     return false;
     112          18 :   return content->IsInNamespace(aNamespace);
     113             : }
     114             : 
     115        1286 : static bool IsWidgetTypeDisabled(uint8_t* aDisabledVector, uint8_t aWidgetType) {
     116        1286 :   MOZ_ASSERT(aWidgetType < ThemeWidgetType_COUNT);
     117        1286 :   return (aDisabledVector[aWidgetType >> 3] & (1 << (aWidgetType & 7))) != 0;
     118             : }
     119             : 
     120           0 : static void SetWidgetTypeDisabled(uint8_t* aDisabledVector, uint8_t aWidgetType) {
     121           0 :   MOZ_ASSERT(aWidgetType < ThemeWidgetType_COUNT);
     122           0 :   aDisabledVector[aWidgetType >> 3] |= (1 << (aWidgetType & 7));
     123           0 : }
     124             : 
     125             : static inline uint16_t
     126          21 : GetWidgetStateKey(uint8_t aWidgetType, GtkWidgetState *aWidgetState)
     127             : {
     128          42 :   return (aWidgetState->active |
     129          42 :           aWidgetState->focused << 1 |
     130          42 :           aWidgetState->inHover << 2 |
     131          42 :           aWidgetState->disabled << 3 |
     132          42 :           aWidgetState->isDefault << 4 |
     133          42 :           aWidgetType << 5);
     134             : }
     135             : 
     136          18 : static bool IsWidgetStateSafe(uint8_t* aSafeVector,
     137             :                                 uint8_t aWidgetType,
     138             :                                 GtkWidgetState *aWidgetState)
     139             : {
     140          18 :   MOZ_ASSERT(aWidgetType < ThemeWidgetType_COUNT);
     141          18 :   uint16_t key = GetWidgetStateKey(aWidgetType, aWidgetState);
     142          18 :   return (aSafeVector[key >> 3] & (1 << (key & 7))) != 0;
     143             : }
     144             : 
     145           3 : static void SetWidgetStateSafe(uint8_t *aSafeVector,
     146             :                                uint8_t aWidgetType,
     147             :                                GtkWidgetState *aWidgetState)
     148             : {
     149           3 :   MOZ_ASSERT(aWidgetType < ThemeWidgetType_COUNT);
     150           3 :   uint16_t key = GetWidgetStateKey(aWidgetType, aWidgetState);
     151           3 :   aSafeVector[key >> 3] |= (1 << (key & 7));
     152           3 : }
     153             : 
     154             : /* static */ GtkTextDirection
     155         404 : nsNativeThemeGTK::GetTextDirection(nsIFrame* aFrame)
     156             : {
     157             :   // IsFrameRTL() treats vertical-rl modes as right-to-left (in addition to
     158             :   // horizontal text with direction=RTL), rather than just considering the
     159             :   // text direction.  GtkTextDirection does not have distinct values for
     160             :   // vertical writing modes, but considering the block flow direction is
     161             :   // important for resizers and scrollbar elements, at least.
     162         404 :   return IsFrameRTL(aFrame) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
     163             : }
     164             : 
     165             : // Returns positive for negative margins (otherwise 0).
     166             : gint
     167           0 : nsNativeThemeGTK::GetTabMarginPixels(nsIFrame* aFrame)
     168             : {
     169             :   nscoord margin =
     170           0 :     IsBottomTab(aFrame) ? aFrame->GetUsedMargin().top
     171           0 :     : aFrame->GetUsedMargin().bottom;
     172             : 
     173             :   return std::min<gint>(MOZ_GTK_TAB_MARGIN_MASK,
     174             :                 std::max(0,
     175           0 :                        aFrame->PresContext()->AppUnitsToDevPixels(-margin)));
     176             : }
     177             : 
     178           0 : static bool ShouldScrollbarButtonBeDisabled(int32_t aCurpos, int32_t aMaxpos,
     179             :                                             uint8_t aWidgetType)
     180             : {
     181           0 :   return ((aCurpos == 0 && (aWidgetType == NS_THEME_SCROLLBARBUTTON_UP ||
     182             :                             aWidgetType == NS_THEME_SCROLLBARBUTTON_LEFT))
     183           0 :       || (aCurpos == aMaxpos && (aWidgetType == NS_THEME_SCROLLBARBUTTON_DOWN ||
     184           0 :                                  aWidgetType == NS_THEME_SCROLLBARBUTTON_RIGHT)));
     185             : }
     186             : 
     187             : bool
     188         312 : nsNativeThemeGTK::GetGtkWidgetAndState(uint8_t aWidgetType, nsIFrame* aFrame,
     189             :                                        WidgetNodeType& aGtkWidgetType,
     190             :                                        GtkWidgetState* aState,
     191             :                                        gint* aWidgetFlags)
     192             : {
     193         312 :   if (aState) {
     194             :     // For XUL checkboxes and radio buttons, the state of the parent
     195             :     // determines our state.
     196          18 :     nsIFrame *stateFrame = aFrame;
     197          18 :     if (aFrame && ((aWidgetFlags && (aWidgetType == NS_THEME_CHECKBOX ||
     198          18 :                                      aWidgetType == NS_THEME_RADIO)) ||
     199          18 :                    aWidgetType == NS_THEME_CHECKBOX_LABEL ||
     200             :                    aWidgetType == NS_THEME_RADIO_LABEL)) {
     201             : 
     202           0 :       nsIAtom* atom = nullptr;
     203           0 :       if (IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) {
     204           0 :         if (aWidgetType == NS_THEME_CHECKBOX_LABEL ||
     205             :             aWidgetType == NS_THEME_RADIO_LABEL) {
     206             :           // Adjust stateFrame so GetContentState finds the correct state.
     207           0 :           stateFrame = aFrame = aFrame->GetParent()->GetParent();
     208             :         } else {
     209             :           // GetContentState knows to look one frame up for radio/checkbox
     210             :           // widgets, so don't adjust stateFrame here.
     211           0 :           aFrame = aFrame->GetParent();
     212             :         }
     213           0 :         if (aWidgetFlags) {
     214           0 :           if (!atom) {
     215           0 :             atom = (aWidgetType == NS_THEME_CHECKBOX ||
     216           0 :                     aWidgetType == NS_THEME_CHECKBOX_LABEL) ? nsGkAtoms::checked
     217             :                                                             : nsGkAtoms::selected;
     218             :           }
     219           0 :           *aWidgetFlags = CheckBooleanAttr(aFrame, atom);
     220             :         }
     221             :       } else {
     222           0 :         if (aWidgetFlags) {
     223           0 :           nsCOMPtr<nsIDOMHTMLInputElement> inputElt(do_QueryInterface(aFrame->GetContent()));
     224           0 :           *aWidgetFlags = 0;
     225           0 :           if (inputElt) {
     226             :             bool isHTMLChecked;
     227           0 :             inputElt->GetChecked(&isHTMLChecked);
     228           0 :             if (isHTMLChecked)
     229           0 :               *aWidgetFlags |= MOZ_GTK_WIDGET_CHECKED;
     230             :           }
     231             : 
     232           0 :           if (GetIndeterminate(aFrame))
     233           0 :             *aWidgetFlags |= MOZ_GTK_WIDGET_INCONSISTENT;
     234             :         }
     235           0 :       }
     236          18 :     } else if (aWidgetType == NS_THEME_TOOLBARBUTTON_DROPDOWN ||
     237          18 :                aWidgetType == NS_THEME_TREEHEADERSORTARROW ||
     238          18 :                aWidgetType == NS_THEME_BUTTON_ARROW_PREVIOUS ||
     239          18 :                aWidgetType == NS_THEME_BUTTON_ARROW_NEXT ||
     240          18 :                aWidgetType == NS_THEME_BUTTON_ARROW_UP ||
     241             :                aWidgetType == NS_THEME_BUTTON_ARROW_DOWN) {
     242             :       // The state of an arrow comes from its parent.
     243           0 :       stateFrame = aFrame = aFrame->GetParent();
     244             :     }
     245             : 
     246          18 :     EventStates eventState = GetContentState(stateFrame, aWidgetType);
     247             : 
     248          18 :     aState->disabled = IsDisabled(aFrame, eventState) || IsReadOnly(aFrame);
     249          18 :     aState->active  = eventState.HasState(NS_EVENT_STATE_ACTIVE);
     250          18 :     aState->focused = eventState.HasState(NS_EVENT_STATE_FOCUS);
     251          18 :     aState->inHover = eventState.HasState(NS_EVENT_STATE_HOVER);
     252          18 :     aState->isDefault = IsDefaultButton(aFrame);
     253          18 :     aState->canDefault = FALSE; // XXX fix me
     254          18 :     aState->depressed = FALSE;
     255             : 
     256          18 :     if (aWidgetType == NS_THEME_FOCUS_OUTLINE) {
     257           0 :       aState->disabled = FALSE;
     258           0 :       aState->active  = FALSE;
     259           0 :       aState->inHover = FALSE;
     260           0 :       aState->isDefault = FALSE;
     261           0 :       aState->canDefault = FALSE;
     262             : 
     263           0 :       aState->focused = TRUE;
     264           0 :       aState->depressed = TRUE; // see moz_gtk_entry_paint()
     265          18 :     } else if (aWidgetType == NS_THEME_BUTTON ||
     266          18 :                aWidgetType == NS_THEME_TOOLBARBUTTON ||
     267          18 :                aWidgetType == NS_THEME_DUALBUTTON ||
     268          18 :                aWidgetType == NS_THEME_TOOLBARBUTTON_DROPDOWN ||
     269          18 :                aWidgetType == NS_THEME_MENULIST ||
     270             :                aWidgetType == NS_THEME_MENULIST_BUTTON) {
     271           0 :       aState->active &= aState->inHover;
     272             :     }
     273             : 
     274          18 :     if (IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) {
     275             :       // For these widget types, some element (either a child or parent)
     276             :       // actually has element focus, so we check the focused attribute
     277             :       // to see whether to draw in the focused state.
     278          18 :       if (aWidgetType == NS_THEME_NUMBER_INPUT ||
     279          18 :           aWidgetType == NS_THEME_TEXTFIELD ||
     280          18 :           aWidgetType == NS_THEME_TEXTFIELD_MULTILINE ||
     281          18 :           aWidgetType == NS_THEME_MENULIST_TEXTFIELD ||
     282          18 :           aWidgetType == NS_THEME_SPINNER_TEXTFIELD ||
     283          18 :           aWidgetType == NS_THEME_RADIO_CONTAINER ||
     284             :           aWidgetType == NS_THEME_RADIO_LABEL) {
     285           0 :         aState->focused = IsFocused(aFrame);
     286          18 :       } else if (aWidgetType == NS_THEME_RADIO ||
     287             :                  aWidgetType == NS_THEME_CHECKBOX) {
     288             :         // In XUL, checkboxes and radios shouldn't have focus rings, their labels do
     289           0 :         aState->focused = FALSE;
     290             :       }
     291             : 
     292          18 :       if (aWidgetType == NS_THEME_SCROLLBARTHUMB_VERTICAL ||
     293             :           aWidgetType == NS_THEME_SCROLLBARTHUMB_HORIZONTAL) {
     294             :         // for scrollbars we need to go up two to go from the thumb to
     295             :         // the slider to the actual scrollbar object
     296           0 :         nsIFrame *tmpFrame = aFrame->GetParent()->GetParent();
     297             : 
     298           0 :         aState->curpos = CheckIntAttr(tmpFrame, nsGkAtoms::curpos, 0);
     299           0 :         aState->maxpos = CheckIntAttr(tmpFrame, nsGkAtoms::maxpos, 100);
     300             : 
     301           0 :         if (CheckBooleanAttr(aFrame, nsGkAtoms::active)) {
     302           0 :           aState->active = TRUE;
     303             :           // Set hover state to emulate Gtk style of active scrollbar thumb
     304           0 :           aState->inHover = TRUE;
     305             :         }
     306             :       }
     307             : 
     308          18 :       if (aWidgetType == NS_THEME_SCROLLBARBUTTON_UP ||
     309          18 :           aWidgetType == NS_THEME_SCROLLBARBUTTON_DOWN ||
     310          18 :           aWidgetType == NS_THEME_SCROLLBARBUTTON_LEFT ||
     311             :           aWidgetType == NS_THEME_SCROLLBARBUTTON_RIGHT) {
     312             :         // set the state to disabled when the scrollbar is scrolled to
     313             :         // the beginning or the end, depending on the button type.
     314           0 :         int32_t curpos = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0);
     315           0 :         int32_t maxpos = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 100);
     316           0 :         if (ShouldScrollbarButtonBeDisabled(curpos, maxpos, aWidgetType)) {
     317           0 :           aState->disabled = true;
     318             :         }
     319             : 
     320             :         // In order to simulate native GTK scrollbar click behavior,
     321             :         // we set the active attribute on the element to true if it's
     322             :         // pressed with any mouse button.
     323             :         // This allows us to show that it's active without setting :active
     324           0 :         else if (CheckBooleanAttr(aFrame, nsGkAtoms::active))
     325           0 :           aState->active = true;
     326             : 
     327           0 :         if (aWidgetFlags) {
     328           0 :           *aWidgetFlags = GetScrollbarButtonType(aFrame);
     329           0 :           if (aWidgetType - NS_THEME_SCROLLBARBUTTON_UP < 2)
     330           0 :             *aWidgetFlags |= MOZ_GTK_STEPPER_VERTICAL;
     331             :         }
     332             :       }
     333             : 
     334             :       // menu item state is determined by the attribute "_moz-menuactive",
     335             :       // and not by the mouse hovering (accessibility).  as a special case,
     336             :       // menus which are children of a menu bar are only marked as prelight
     337             :       // if they are open, not on normal hover.
     338             : 
     339          18 :       if (aWidgetType == NS_THEME_MENUITEM ||
     340          18 :           aWidgetType == NS_THEME_CHECKMENUITEM ||
     341          18 :           aWidgetType == NS_THEME_RADIOMENUITEM ||
     342          18 :           aWidgetType == NS_THEME_MENUSEPARATOR ||
     343             :           aWidgetType == NS_THEME_MENUARROW) {
     344           0 :         bool isTopLevel = false;
     345           0 :         nsMenuFrame *menuFrame = do_QueryFrame(aFrame);
     346           0 :         if (menuFrame) {
     347           0 :           isTopLevel = menuFrame->IsOnMenuBar();
     348             :         }
     349             : 
     350           0 :         if (isTopLevel) {
     351           0 :           aState->inHover = menuFrame->IsOpen();
     352             :         } else {
     353           0 :           aState->inHover = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive);
     354             :         }
     355             : 
     356           0 :         aState->active = FALSE;
     357             : 
     358           0 :         if (aWidgetType == NS_THEME_CHECKMENUITEM ||
     359             :             aWidgetType == NS_THEME_RADIOMENUITEM) {
     360           0 :           *aWidgetFlags = 0;
     361           0 :           if (aFrame && aFrame->GetContent()) {
     362           0 :             *aWidgetFlags = aFrame->GetContent()->
     363           0 :               AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
     364             :                           nsGkAtoms::_true, eIgnoreCase);
     365             :           }
     366             :         }
     367             :       }
     368             : 
     369             :       // A button with drop down menu open or an activated toggle button
     370             :       // should always appear depressed.
     371          18 :       if (aWidgetType == NS_THEME_BUTTON ||
     372          18 :           aWidgetType == NS_THEME_TOOLBARBUTTON ||
     373          18 :           aWidgetType == NS_THEME_DUALBUTTON ||
     374          18 :           aWidgetType == NS_THEME_TOOLBARBUTTON_DROPDOWN ||
     375          18 :           aWidgetType == NS_THEME_MENULIST ||
     376             :           aWidgetType == NS_THEME_MENULIST_BUTTON) {
     377           0 :         bool menuOpen = IsOpenButton(aFrame);
     378           0 :         aState->depressed = IsCheckedButton(aFrame) || menuOpen;
     379             :         // we must not highlight buttons with open drop down menus on hover.
     380           0 :         aState->inHover = aState->inHover && !menuOpen;
     381             :       }
     382             : 
     383             :       // When the input field of the drop down button has focus, some themes
     384             :       // should draw focus for the drop down button as well.
     385          18 :       if (aWidgetType == NS_THEME_MENULIST_BUTTON && aWidgetFlags) {
     386           0 :         *aWidgetFlags = CheckBooleanAttr(aFrame, nsGkAtoms::parentfocused);
     387             :       }
     388             :     }
     389             :   }
     390             : 
     391         312 :   switch (aWidgetType) {
     392             :   case NS_THEME_BUTTON:
     393           0 :     if (aWidgetFlags)
     394           0 :       *aWidgetFlags = GTK_RELIEF_NORMAL;
     395           0 :     aGtkWidgetType = MOZ_GTK_BUTTON;
     396           0 :     break;
     397             :   case NS_THEME_TOOLBARBUTTON:
     398             :   case NS_THEME_DUALBUTTON:
     399           0 :     if (aWidgetFlags)
     400           0 :       *aWidgetFlags = GTK_RELIEF_NONE;
     401           0 :     aGtkWidgetType = MOZ_GTK_TOOLBAR_BUTTON;
     402           0 :     break;
     403             :   case NS_THEME_FOCUS_OUTLINE:
     404           0 :     aGtkWidgetType = MOZ_GTK_ENTRY;
     405           0 :     break;
     406             :   case NS_THEME_CHECKBOX:
     407             :   case NS_THEME_RADIO:
     408           0 :     aGtkWidgetType = (aWidgetType == NS_THEME_RADIO) ? MOZ_GTK_RADIOBUTTON : MOZ_GTK_CHECKBUTTON;
     409           0 :     break;
     410             :   case NS_THEME_SCROLLBARBUTTON_UP:
     411             :   case NS_THEME_SCROLLBARBUTTON_DOWN:
     412             :   case NS_THEME_SCROLLBARBUTTON_LEFT:
     413             :   case NS_THEME_SCROLLBARBUTTON_RIGHT:
     414           0 :     aGtkWidgetType = MOZ_GTK_SCROLLBAR_BUTTON;
     415           0 :     break;
     416             :   case NS_THEME_SCROLLBAR_VERTICAL:
     417           0 :     aGtkWidgetType = MOZ_GTK_SCROLLBAR_VERTICAL;
     418           0 :     if (GetWidgetTransparency(aFrame, aWidgetType) == eOpaque)
     419           0 :         *aWidgetFlags = MOZ_GTK_TRACK_OPAQUE;
     420             :     else
     421           0 :         *aWidgetFlags = 0;
     422           0 :     break;
     423             :   case NS_THEME_SCROLLBAR_HORIZONTAL:
     424           0 :     aGtkWidgetType = MOZ_GTK_SCROLLBAR_HORIZONTAL;
     425           0 :     if (GetWidgetTransparency(aFrame, aWidgetType) == eOpaque)
     426           0 :         *aWidgetFlags = MOZ_GTK_TRACK_OPAQUE;
     427             :     else
     428           0 :         *aWidgetFlags = 0;
     429           0 :     break;
     430             :   case NS_THEME_SCROLLBARTRACK_HORIZONTAL:
     431           0 :     aGtkWidgetType = MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL;
     432           0 :     break;
     433             :   case NS_THEME_SCROLLBARTRACK_VERTICAL:
     434           0 :     aGtkWidgetType = MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL;
     435           0 :     break;
     436             :   case NS_THEME_SCROLLBARTHUMB_VERTICAL:
     437          10 :     aGtkWidgetType = MOZ_GTK_SCROLLBAR_THUMB_VERTICAL;
     438          10 :     break;
     439             :   case NS_THEME_SCROLLBARTHUMB_HORIZONTAL:
     440          10 :     aGtkWidgetType = MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
     441          10 :     break;
     442             :   case NS_THEME_SPINNER:
     443           0 :     aGtkWidgetType = MOZ_GTK_SPINBUTTON;
     444           0 :     break;
     445             :   case NS_THEME_SPINNER_UPBUTTON:
     446           0 :     aGtkWidgetType = MOZ_GTK_SPINBUTTON_UP;
     447           0 :     break;
     448             :   case NS_THEME_SPINNER_DOWNBUTTON:
     449           0 :     aGtkWidgetType = MOZ_GTK_SPINBUTTON_DOWN;
     450           0 :     break;
     451             :   case NS_THEME_SPINNER_TEXTFIELD:
     452           0 :     aGtkWidgetType = MOZ_GTK_SPINBUTTON_ENTRY;
     453           0 :     break;
     454             :   case NS_THEME_RANGE:
     455             :     {
     456           0 :       if (IsRangeHorizontal(aFrame)) {
     457           0 :         if (aWidgetFlags)
     458           0 :           *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL;
     459           0 :         aGtkWidgetType = MOZ_GTK_SCALE_HORIZONTAL;
     460             :       } else {
     461           0 :         if (aWidgetFlags)
     462           0 :           *aWidgetFlags = GTK_ORIENTATION_VERTICAL;
     463           0 :         aGtkWidgetType = MOZ_GTK_SCALE_VERTICAL;
     464             :       }
     465           0 :       break;
     466             :     }
     467             :   case NS_THEME_RANGE_THUMB:
     468             :     {
     469           0 :       if (IsRangeHorizontal(aFrame)) {
     470           0 :         if (aWidgetFlags)
     471           0 :           *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL;
     472           0 :         aGtkWidgetType = MOZ_GTK_SCALE_THUMB_HORIZONTAL;
     473             :       } else {
     474           0 :         if (aWidgetFlags)
     475           0 :           *aWidgetFlags = GTK_ORIENTATION_VERTICAL;
     476           0 :         aGtkWidgetType = MOZ_GTK_SCALE_THUMB_VERTICAL;
     477             :       }
     478           0 :       break;
     479             :     }
     480             :   case NS_THEME_SCALE_HORIZONTAL:
     481           0 :     if (aWidgetFlags)
     482           0 :       *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL;
     483           0 :     aGtkWidgetType = MOZ_GTK_SCALE_HORIZONTAL;
     484           0 :     break;
     485             :   case NS_THEME_SCALETHUMB_HORIZONTAL:
     486           0 :     if (aWidgetFlags)
     487           0 :       *aWidgetFlags = GTK_ORIENTATION_HORIZONTAL;
     488           0 :     aGtkWidgetType = MOZ_GTK_SCALE_THUMB_HORIZONTAL;
     489           0 :     break;
     490             :   case NS_THEME_SCALE_VERTICAL:
     491           0 :     if (aWidgetFlags)
     492           0 :       *aWidgetFlags = GTK_ORIENTATION_VERTICAL;
     493           0 :     aGtkWidgetType = MOZ_GTK_SCALE_VERTICAL;
     494           0 :     break;
     495             :   case NS_THEME_SEPARATOR:
     496           0 :     aGtkWidgetType = MOZ_GTK_TOOLBAR_SEPARATOR;
     497           0 :     break;
     498             :   case NS_THEME_SCALETHUMB_VERTICAL:
     499           0 :     if (aWidgetFlags)
     500           0 :       *aWidgetFlags = GTK_ORIENTATION_VERTICAL;
     501           0 :     aGtkWidgetType = MOZ_GTK_SCALE_THUMB_VERTICAL;
     502           0 :     break;
     503             :   case NS_THEME_TOOLBARGRIPPER:
     504           0 :     aGtkWidgetType = MOZ_GTK_GRIPPER;
     505           0 :     break;
     506             :   case NS_THEME_RESIZER:
     507           0 :     aGtkWidgetType = MOZ_GTK_RESIZER;
     508           0 :     break;
     509             :   case NS_THEME_NUMBER_INPUT:
     510             :   case NS_THEME_TEXTFIELD:
     511           0 :     aGtkWidgetType = MOZ_GTK_ENTRY;
     512           0 :     break;
     513             :   case NS_THEME_TEXTFIELD_MULTILINE:
     514             : #if (MOZ_WIDGET_GTK == 3)
     515           0 :     aGtkWidgetType = MOZ_GTK_TEXT_VIEW;
     516             : #else
     517             :     aGtkWidgetType = MOZ_GTK_ENTRY;
     518             : #endif
     519           0 :     break;
     520             :   case NS_THEME_LISTBOX:
     521             :   case NS_THEME_TREEVIEW:
     522           0 :     aGtkWidgetType = MOZ_GTK_TREEVIEW;
     523           0 :     break;
     524             :   case NS_THEME_TREEHEADERCELL:
     525           0 :     if (aWidgetFlags) {
     526             :       // In this case, the flag denotes whether the header is the sorted one or not
     527           0 :       if (GetTreeSortDirection(aFrame) == eTreeSortDirection_Natural)
     528           0 :         *aWidgetFlags = false;
     529             :       else
     530           0 :         *aWidgetFlags = true;
     531             :     }
     532           0 :     aGtkWidgetType = MOZ_GTK_TREE_HEADER_CELL;
     533           0 :     break;
     534             :   case NS_THEME_TREEHEADERSORTARROW:
     535           0 :     if (aWidgetFlags) {
     536           0 :       switch (GetTreeSortDirection(aFrame)) {
     537             :         case eTreeSortDirection_Ascending:
     538           0 :           *aWidgetFlags = GTK_ARROW_DOWN;
     539           0 :           break;
     540             :         case eTreeSortDirection_Descending:
     541           0 :           *aWidgetFlags = GTK_ARROW_UP;
     542           0 :           break;
     543             :         case eTreeSortDirection_Natural:
     544             :         default:
     545             :           /* This prevents the treecolums from getting smaller
     546             :            * and wider when switching sort direction off and on
     547             :            * */
     548           0 :           *aWidgetFlags = GTK_ARROW_NONE;
     549           0 :           break;
     550             :       }
     551             :     }
     552           0 :     aGtkWidgetType = MOZ_GTK_TREE_HEADER_SORTARROW;
     553           0 :     break;
     554             :   case NS_THEME_TREETWISTY:
     555           0 :     aGtkWidgetType = MOZ_GTK_TREEVIEW_EXPANDER;
     556           0 :     if (aWidgetFlags)
     557           0 :       *aWidgetFlags = GTK_EXPANDER_COLLAPSED;
     558           0 :     break;
     559             :   case NS_THEME_TREETWISTYOPEN:
     560           0 :     aGtkWidgetType = MOZ_GTK_TREEVIEW_EXPANDER;
     561           0 :     if (aWidgetFlags)
     562           0 :       *aWidgetFlags = GTK_EXPANDER_EXPANDED;
     563           0 :     break;
     564             :   case NS_THEME_MENULIST:
     565           0 :     aGtkWidgetType = MOZ_GTK_DROPDOWN;
     566           0 :     if (aWidgetFlags)
     567           0 :         *aWidgetFlags = IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XHTML);
     568           0 :     break;
     569             :   case NS_THEME_MENULIST_TEXT:
     570           0 :     return false; // nothing to do, but prevents the bg from being drawn
     571             :   case NS_THEME_MENULIST_TEXTFIELD:
     572           0 :     aGtkWidgetType = MOZ_GTK_DROPDOWN_ENTRY;
     573           0 :     break;
     574             :   case NS_THEME_MENULIST_BUTTON:
     575           0 :     aGtkWidgetType = MOZ_GTK_DROPDOWN_ARROW;
     576           0 :     break;
     577             :   case NS_THEME_TOOLBARBUTTON_DROPDOWN:
     578             :   case NS_THEME_BUTTON_ARROW_DOWN:
     579             :   case NS_THEME_BUTTON_ARROW_UP:
     580             :   case NS_THEME_BUTTON_ARROW_NEXT:
     581             :   case NS_THEME_BUTTON_ARROW_PREVIOUS:
     582          10 :     aGtkWidgetType = MOZ_GTK_TOOLBARBUTTON_ARROW;
     583          10 :     if (aWidgetFlags) {
     584          10 :       *aWidgetFlags = GTK_ARROW_DOWN;
     585             : 
     586          10 :       if (aWidgetType == NS_THEME_BUTTON_ARROW_UP)
     587           0 :         *aWidgetFlags = GTK_ARROW_UP;
     588          10 :       else if (aWidgetType == NS_THEME_BUTTON_ARROW_NEXT)
     589           0 :         *aWidgetFlags = GTK_ARROW_RIGHT;
     590          10 :       else if (aWidgetType == NS_THEME_BUTTON_ARROW_PREVIOUS)
     591           0 :         *aWidgetFlags = GTK_ARROW_LEFT;
     592             :     }
     593          10 :     break;
     594             :   case NS_THEME_CHECKBOX_CONTAINER:
     595           0 :     aGtkWidgetType = MOZ_GTK_CHECKBUTTON_CONTAINER;
     596           0 :     break;
     597             :   case NS_THEME_RADIO_CONTAINER:
     598           0 :     aGtkWidgetType = MOZ_GTK_RADIOBUTTON_CONTAINER;
     599           0 :     break;
     600             :   case NS_THEME_CHECKBOX_LABEL:
     601           0 :     aGtkWidgetType = MOZ_GTK_CHECKBUTTON_LABEL;
     602           0 :     break;
     603             :   case NS_THEME_RADIO_LABEL:
     604           0 :     aGtkWidgetType = MOZ_GTK_RADIOBUTTON_LABEL;
     605           0 :     break;
     606             :   case NS_THEME_TOOLBAR:
     607           0 :     aGtkWidgetType = MOZ_GTK_TOOLBAR;
     608           0 :     break;
     609             :   case NS_THEME_TOOLTIP:
     610           0 :     aGtkWidgetType = MOZ_GTK_TOOLTIP;
     611           0 :     break;
     612             :   case NS_THEME_STATUSBARPANEL:
     613             :   case NS_THEME_RESIZERPANEL:
     614           0 :     aGtkWidgetType = MOZ_GTK_FRAME;
     615           0 :     break;
     616             :   case NS_THEME_PROGRESSBAR:
     617             :   case NS_THEME_PROGRESSBAR_VERTICAL:
     618           0 :     aGtkWidgetType = MOZ_GTK_PROGRESSBAR;
     619           0 :     break;
     620             :   case NS_THEME_PROGRESSCHUNK:
     621             :   case NS_THEME_PROGRESSCHUNK_VERTICAL:
     622             :     {
     623           0 :       nsIFrame* stateFrame = aFrame->GetParent();
     624           0 :       EventStates eventStates = GetContentState(stateFrame, aWidgetType);
     625             : 
     626           0 :       aGtkWidgetType = IsIndeterminateProgress(stateFrame, eventStates)
     627           0 :                          ? IsVerticalProgress(stateFrame)
     628           0 :                            ? MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE
     629             :                            : MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE
     630             :                          : MOZ_GTK_PROGRESS_CHUNK;
     631             :     }
     632           0 :     break;
     633             :   case NS_THEME_TAB_SCROLL_ARROW_BACK:
     634             :   case NS_THEME_TAB_SCROLL_ARROW_FORWARD:
     635           0 :     if (aWidgetFlags)
     636           0 :       *aWidgetFlags = aWidgetType == NS_THEME_TAB_SCROLL_ARROW_BACK ?
     637             :                         GTK_ARROW_LEFT : GTK_ARROW_RIGHT;
     638           0 :     aGtkWidgetType = MOZ_GTK_TAB_SCROLLARROW;
     639           0 :     break;
     640             :   case NS_THEME_TABPANELS:
     641           0 :     aGtkWidgetType = MOZ_GTK_TABPANELS;
     642           0 :     break;
     643             :   case NS_THEME_TAB:
     644             :     {
     645           0 :       if (IsBottomTab(aFrame)) {
     646           0 :         aGtkWidgetType = MOZ_GTK_TAB_BOTTOM;
     647             :       } else {
     648           0 :         aGtkWidgetType = MOZ_GTK_TAB_TOP;
     649             :       }
     650             : 
     651           0 :       if (aWidgetFlags) {
     652             :         /* First bits will be used to store max(0,-bmargin) where bmargin
     653             :          * is the bottom margin of the tab in pixels  (resp. top margin,
     654             :          * for bottom tabs). */
     655           0 :         *aWidgetFlags = GetTabMarginPixels(aFrame);
     656             : 
     657           0 :         if (IsSelectedTab(aFrame))
     658           0 :           *aWidgetFlags |= MOZ_GTK_TAB_SELECTED;
     659             : 
     660           0 :         if (IsFirstTab(aFrame))
     661           0 :           *aWidgetFlags |= MOZ_GTK_TAB_FIRST;
     662             :       }
     663             :     }
     664           0 :     break;
     665             :   case NS_THEME_SPLITTER:
     666           0 :     if (IsHorizontal(aFrame))
     667           0 :       aGtkWidgetType = MOZ_GTK_SPLITTER_VERTICAL;
     668             :     else 
     669           0 :       aGtkWidgetType = MOZ_GTK_SPLITTER_HORIZONTAL;
     670           0 :     break;
     671             :   case NS_THEME_MENUBAR:
     672          65 :     aGtkWidgetType = MOZ_GTK_MENUBAR;
     673          65 :     break;
     674             :   case NS_THEME_MENUPOPUP:
     675           0 :     aGtkWidgetType = MOZ_GTK_MENUPOPUP;
     676           0 :     break;
     677             :   case NS_THEME_MENUITEM:
     678             :     {
     679          77 :       nsMenuFrame *menuFrame = do_QueryFrame(aFrame);
     680          77 :       if (menuFrame && menuFrame->IsOnMenuBar()) {
     681          77 :         aGtkWidgetType = MOZ_GTK_MENUBARITEM;
     682          77 :         break;
     683             :       }
     684             :     }
     685           0 :     aGtkWidgetType = MOZ_GTK_MENUITEM;
     686           0 :     break;
     687             :   case NS_THEME_MENUSEPARATOR:
     688           0 :     aGtkWidgetType = MOZ_GTK_MENUSEPARATOR;
     689           0 :     break;
     690             :   case NS_THEME_MENUARROW:
     691           0 :     aGtkWidgetType = MOZ_GTK_MENUARROW;
     692           0 :     break;
     693             :   case NS_THEME_CHECKMENUITEM:
     694           0 :     aGtkWidgetType = MOZ_GTK_CHECKMENUITEM;
     695           0 :     break;
     696             :   case NS_THEME_RADIOMENUITEM:
     697           0 :     aGtkWidgetType = MOZ_GTK_RADIOMENUITEM;
     698           0 :     break;
     699             :   case NS_THEME_WINDOW:
     700             :   case NS_THEME_DIALOG:
     701         134 :     aGtkWidgetType = MOZ_GTK_WINDOW;
     702         134 :     break;
     703             :   case NS_THEME_GTK_INFO_BAR:
     704           0 :     aGtkWidgetType = MOZ_GTK_INFO_BAR;
     705           0 :     break;
     706             :   default:
     707           6 :     return false;
     708             :   }
     709             : 
     710         306 :   return true;
     711             : }
     712             : 
     713             : #if (MOZ_WIDGET_GTK == 2)
     714             : class ThemeRenderer : public gfxGdkNativeRenderer {
     715             : public:
     716             :   ThemeRenderer(GtkWidgetState aState, WidgetNodeType aGTKWidgetType,
     717             :                 gint aFlags, GtkTextDirection aDirection,
     718             :                 const GdkRectangle& aGDKRect, const GdkRectangle& aGDKClip)
     719             :     : mState(aState), mGTKWidgetType(aGTKWidgetType), mFlags(aFlags),
     720             :       mDirection(aDirection), mGDKRect(aGDKRect), mGDKClip(aGDKClip) {}
     721             :   nsresult DrawWithGDK(GdkDrawable * drawable, gint offsetX, gint offsetY,
     722             :                        GdkRectangle * clipRects, uint32_t numClipRects);
     723             : private:
     724             :   GtkWidgetState mState;
     725             :   WidgetNodeType mGTKWidgetType;
     726             :   gint mFlags;
     727             :   GtkTextDirection mDirection;
     728             :   const GdkRectangle& mGDKRect;
     729             :   const GdkRectangle& mGDKClip;
     730             : };
     731             : 
     732             : nsresult
     733             : ThemeRenderer::DrawWithGDK(GdkDrawable * drawable, gint offsetX, 
     734             :         gint offsetY, GdkRectangle * clipRects, uint32_t numClipRects)
     735             : {
     736             :   GdkRectangle gdk_rect = mGDKRect;
     737             :   gdk_rect.x += offsetX;
     738             :   gdk_rect.y += offsetY;
     739             : 
     740             :   GdkRectangle gdk_clip = mGDKClip;
     741             :   gdk_clip.x += offsetX;
     742             :   gdk_clip.y += offsetY;
     743             : 
     744             :   GdkRectangle surfaceRect;
     745             :   surfaceRect.x = 0;
     746             :   surfaceRect.y = 0;
     747             :   gdk_drawable_get_size(drawable, &surfaceRect.width, &surfaceRect.height);
     748             :   gdk_rectangle_intersect(&gdk_clip, &surfaceRect, &gdk_clip);
     749             :   
     750             :   NS_ASSERTION(numClipRects == 0, "We don't support clipping!!!");
     751             :   moz_gtk_widget_paint(mGTKWidgetType, drawable, &gdk_rect, &gdk_clip,
     752             :                        &mState, mFlags, mDirection);
     753             : 
     754             :   return NS_OK;
     755             : }
     756             : #else
     757          54 : class SystemCairoClipper : public ClipExporter {
     758             : public:
     759          18 :   explicit SystemCairoClipper(cairo_t* aContext) : mContext(aContext)
     760             :   {
     761          18 :   }
     762             : 
     763             :   void
     764          27 :   BeginClip(const Matrix& aTransform) override
     765             :   {
     766             :     cairo_matrix_t mat;
     767          27 :     GfxMatrixToCairoMatrix(aTransform, mat);
     768          27 :     cairo_set_matrix(mContext, &mat);
     769             : 
     770          27 :     cairo_new_path(mContext);
     771          27 :   }
     772             : 
     773             :   void
     774          49 :   MoveTo(const Point &aPoint) override
     775             :   {
     776          49 :     cairo_move_to(mContext, aPoint.x, aPoint.y);
     777          49 :     mCurrentPoint = aPoint;
     778          49 :   }
     779             : 
     780             :   void
     781         147 :   LineTo(const Point &aPoint) override
     782             :   {
     783         147 :     cairo_line_to(mContext, aPoint.x, aPoint.y);
     784         147 :     mCurrentPoint = aPoint;
     785         147 :   }
     786             : 
     787             :   void
     788           0 :   BezierTo(const Point &aCP1, const Point &aCP2, const Point &aCP3) override
     789             :   {
     790           0 :     cairo_curve_to(mContext, aCP1.x, aCP1.y, aCP2.x, aCP2.y, aCP3.x, aCP3.y);
     791           0 :     mCurrentPoint = aCP3;
     792           0 :   }
     793             : 
     794             :   void
     795           0 :   QuadraticBezierTo(const Point &aCP1, const Point &aCP2) override
     796             :   {
     797           0 :     Point CP0 = CurrentPoint();
     798           0 :     Point CP1 = (CP0 + aCP1 * 2.0) / 3.0;
     799           0 :     Point CP2 = (aCP2 + aCP1 * 2.0) / 3.0;
     800           0 :     Point CP3 = aCP2;
     801           0 :     cairo_curve_to(mContext, CP1.x, CP1.y, CP2.x, CP2.y, CP3.x, CP3.y);
     802           0 :     mCurrentPoint = aCP2;
     803           0 :   }
     804             : 
     805             :   void
     806           0 :   Arc(const Point &aOrigin, float aRadius, float aStartAngle, float aEndAngle,
     807             :       bool aAntiClockwise) override
     808             :   {
     809           0 :     ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle,
     810           0 :                 aAntiClockwise);
     811           0 :   }
     812             : 
     813             :   void
     814          49 :   Close() override
     815             :   {
     816          49 :     cairo_close_path(mContext);
     817          49 :   }
     818             : 
     819             :   void
     820          27 :   EndClip() override
     821             :   {
     822          27 :     cairo_clip(mContext);
     823          27 :   }
     824             : 
     825             :   Point
     826           0 :   CurrentPoint() const override
     827             :   {
     828           0 :     return mCurrentPoint;
     829             :   }
     830             : 
     831             : private:
     832             :   cairo_t* mContext;
     833             :   Point mCurrentPoint;
     834             : };
     835             : 
     836             : static void
     837          18 : DrawThemeWithCairo(gfxContext* aContext, DrawTarget* aDrawTarget,
     838             :                    GtkWidgetState aState, WidgetNodeType aGTKWidgetType,
     839             :                    gint aFlags, GtkTextDirection aDirection, gint aScaleFactor,
     840             :                    bool aSnapped, const Point& aDrawOrigin, const nsIntSize& aDrawSize,
     841             :                    GdkRectangle& aGDKRect, nsITheme::Transparency aTransparency)
     842             : {
     843          18 :   Point drawOffset;
     844          18 :   Matrix transform;
     845          18 :   if (!aSnapped) {
     846             :     // If we are not snapped, we depend on the DT for translation.
     847           0 :     drawOffset = aDrawOrigin;
     848           0 :     transform = aDrawTarget->GetTransform().PreTranslate(aDrawOrigin);
     849             :   } else {
     850             :     // Otherwise, we only need to take the device offset into account.
     851          18 :     drawOffset = aDrawOrigin - aContext->GetDeviceOffset();
     852          18 :     transform = Matrix::Translation(drawOffset);
     853             :   }
     854             : 
     855          18 :   if (aScaleFactor != 1)
     856          18 :     transform.PreScale(aScaleFactor, aScaleFactor);
     857             : 
     858             :   cairo_matrix_t mat;
     859          18 :   GfxMatrixToCairoMatrix(transform, mat);
     860             : 
     861          18 :   nsIntSize clipSize((aDrawSize.width + aScaleFactor - 1) / aScaleFactor,
     862          36 :                      (aDrawSize.height + aScaleFactor - 1) / aScaleFactor);
     863             : 
     864             : #ifndef MOZ_TREE_CAIRO
     865             :   // Directly use the Cairo draw target to render the widget if using system Cairo everywhere.
     866             :   BorrowedCairoContext borrowCairo(aDrawTarget);
     867             :   if (borrowCairo.mCairo) {
     868             :     cairo_set_matrix(borrowCairo.mCairo, &mat);
     869             : 
     870             :     cairo_new_path(borrowCairo.mCairo);
     871             :     cairo_rectangle(borrowCairo.mCairo, 0, 0, clipSize.width, clipSize.height);
     872             :     cairo_clip(borrowCairo.mCairo);
     873             : 
     874             :     moz_gtk_widget_paint(aGTKWidgetType, borrowCairo.mCairo, &aGDKRect, &aState, aFlags, aDirection);
     875             : 
     876             :     borrowCairo.Finish();
     877             :     return;
     878             :   }
     879             : #endif
     880             : 
     881             :   // A direct Cairo draw target is not available, so we need to create a temporary one.
     882             : #if defined(MOZ_X11) && defined(CAIRO_HAS_XLIB_SURFACE)
     883             :   // If using a Cairo xlib surface, then try to reuse it.
     884          36 :   BorrowedXlibDrawable borrow(aDrawTarget);
     885          18 :   if (borrow.GetDrawable()) {
     886           0 :     nsIntSize size = borrow.GetSize();
     887           0 :     cairo_surface_t* surf = nullptr;
     888             :     // Check if the surface is using XRender.
     889             : #ifdef CAIRO_HAS_XLIB_XRENDER_SURFACE
     890           0 :     if (borrow.GetXRenderFormat()) {
     891           0 :       surf = cairo_xlib_surface_create_with_xrender_format(
     892             :           borrow.GetDisplay(), borrow.GetDrawable(), borrow.GetScreen(),
     893           0 :           borrow.GetXRenderFormat(), size.width, size.height);
     894             :     } else {
     895             : #else
     896             :       if (! borrow.GetXRenderFormat()) {
     897             : #endif
     898           0 :         surf = cairo_xlib_surface_create(
     899             :             borrow.GetDisplay(), borrow.GetDrawable(), borrow.GetVisual(),
     900           0 :             size.width, size.height);
     901             :       }
     902           0 :       if (!NS_WARN_IF(!surf)) {
     903           0 :         Point offset = borrow.GetOffset();
     904           0 :         if (offset != Point()) {
     905           0 :           cairo_surface_set_device_offset(surf, offset.x, offset.y);
     906             :         }
     907           0 :         cairo_t* cr = cairo_create(surf);
     908           0 :         if (!NS_WARN_IF(!cr)) {
     909           0 :           RefPtr<SystemCairoClipper> clipper = new SystemCairoClipper(cr);
     910           0 :           aContext->ExportClip(*clipper);
     911             : 
     912           0 :           cairo_set_matrix(cr, &mat);
     913             : 
     914           0 :           cairo_new_path(cr);
     915           0 :           cairo_rectangle(cr, 0, 0, clipSize.width, clipSize.height);
     916           0 :           cairo_clip(cr);
     917             : 
     918           0 :           moz_gtk_widget_paint(aGTKWidgetType, cr, &aGDKRect, &aState, aFlags, aDirection);
     919             : 
     920           0 :           cairo_destroy(cr);
     921             :         }
     922           0 :         cairo_surface_destroy(surf);
     923             :       }
     924           0 :       borrow.Finish();
     925           0 :       return;
     926             :     }
     927             : #endif
     928             : 
     929             :   // Check if the widget requires complex masking that must be composited.
     930             :   // Try to directly write to the draw target's pixels if possible.
     931             :   uint8_t* data;
     932          18 :   nsIntSize size;
     933             :   int32_t stride;
     934             :   SurfaceFormat format;
     935          18 :   IntPoint origin;
     936          18 :   if (aDrawTarget->LockBits(&data, &size, &stride, &format, &origin)) {
     937             :     // Create a Cairo image surface context the device rectangle.
     938             :     cairo_surface_t* surf =
     939          18 :       cairo_image_surface_create_for_data(
     940          18 :         data, GfxFormatToCairoFormat(format), size.width, size.height, stride);
     941          18 :     if (!NS_WARN_IF(!surf)) {
     942          18 :       if (origin != IntPoint()) {
     943           0 :         cairo_surface_set_device_offset(surf, -origin.x, -origin.y);
     944             :       }
     945          18 :       cairo_t* cr = cairo_create(surf);
     946          18 :       if (!NS_WARN_IF(!cr)) {
     947          36 :         RefPtr<SystemCairoClipper> clipper = new SystemCairoClipper(cr);
     948          18 :         aContext->ExportClip(*clipper);
     949             : 
     950          18 :         cairo_set_matrix(cr, &mat);
     951             : 
     952          18 :         cairo_new_path(cr);
     953          18 :         cairo_rectangle(cr, 0, 0, clipSize.width, clipSize.height);
     954          18 :         cairo_clip(cr);
     955             : 
     956          18 :         moz_gtk_widget_paint(aGTKWidgetType, cr, &aGDKRect, &aState, aFlags, aDirection);
     957             : 
     958          18 :         cairo_destroy(cr);
     959             :       }
     960          18 :       cairo_surface_destroy(surf);
     961             :     }
     962          18 :     aDrawTarget->ReleaseBits(data);
     963             :   } else {
     964             :     // If the widget has any transparency, make sure to choose an alpha format.
     965           0 :     format = aTransparency != nsITheme::eOpaque ? SurfaceFormat::B8G8R8A8 : aDrawTarget->GetFormat();
     966             :     // Create a temporary data surface to render the widget into.
     967             :     RefPtr<DataSourceSurface> dataSurface =
     968           0 :       Factory::CreateDataSourceSurface(aDrawSize, format, aTransparency != nsITheme::eOpaque);
     969             :     DataSourceSurface::MappedSurface map;
     970           0 :     if (!NS_WARN_IF(!(dataSurface && dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)))) {
     971             :       // Create a Cairo image surface wrapping the data surface.
     972             :       cairo_surface_t* surf =
     973           0 :         cairo_image_surface_create_for_data(map.mData, GfxFormatToCairoFormat(format),
     974           0 :                                             aDrawSize.width, aDrawSize.height, map.mStride);
     975           0 :       cairo_t* cr = nullptr;
     976           0 :       if (!NS_WARN_IF(!surf)) {
     977           0 :         cr = cairo_create(surf);
     978           0 :         if (!NS_WARN_IF(!cr)) {
     979           0 :           if (aScaleFactor != 1) {
     980           0 :             cairo_scale(cr, aScaleFactor, aScaleFactor);
     981             :           }
     982             : 
     983           0 :           moz_gtk_widget_paint(aGTKWidgetType, cr, &aGDKRect, &aState, aFlags, aDirection);
     984             :         }
     985             :       }
     986             : 
     987             :       // Unmap the surface before using it as a source
     988           0 :       dataSurface->Unmap();
     989             : 
     990           0 :       if (cr) {
     991           0 :         if (!aSnapped || aTransparency != nsITheme::eOpaque) {
     992             :           // The widget either needs to be masked or has transparency, so use the slower drawing path.
     993           0 :           aDrawTarget->DrawSurface(dataSurface,
     994           0 :                                    Rect(aSnapped ? drawOffset - aDrawTarget->GetTransform().GetTranslation() : drawOffset,
     995           0 :                                         Size(aDrawSize)),
     996           0 :                                    Rect(0, 0, aDrawSize.width, aDrawSize.height));
     997             :         } else {
     998             :           // The widget is a simple opaque rectangle, so just copy it out.
     999             :           aDrawTarget->CopySurface(dataSurface,
    1000           0 :                                    IntRect(0, 0, aDrawSize.width, aDrawSize.height),
    1001           0 :                                    TruncatedToInt(drawOffset));
    1002             :         }
    1003             : 
    1004           0 :         cairo_destroy(cr);
    1005             :       }
    1006             : 
    1007           0 :       if (surf) {
    1008           0 :         cairo_surface_destroy(surf);
    1009             :       }
    1010             :     }
    1011             :   }
    1012             : }
    1013             : #endif
    1014             : 
    1015             : bool
    1016         212 : nsNativeThemeGTK::GetExtraSizeForWidget(nsIFrame* aFrame, uint8_t aWidgetType,
    1017             :                                         nsIntMargin* aExtra)
    1018             : {
    1019         212 :   *aExtra = nsIntMargin(0,0,0,0);
    1020             :   // Allow an extra one pixel above and below the thumb for certain
    1021             :   // GTK2 themes (Ximian Industrial, Bluecurve, Misty, at least);
    1022             :   // We modify the frame's overflow area.  See bug 297508.
    1023         212 :   switch (aWidgetType) {
    1024             :   case NS_THEME_SCROLLBARTHUMB_VERTICAL:
    1025           5 :     aExtra->top = aExtra->bottom = 1;
    1026           5 :     break;
    1027             :   case NS_THEME_SCROLLBARTHUMB_HORIZONTAL:
    1028           5 :     aExtra->left = aExtra->right = 1;
    1029           5 :     break;
    1030             : 
    1031             :   // Include the indicator spacing (the padding around the control).
    1032             :   case NS_THEME_CHECKBOX:
    1033             :   case NS_THEME_RADIO:
    1034             :     {
    1035             :       gint indicator_size, indicator_spacing;
    1036             : 
    1037           0 :       if (aWidgetType == NS_THEME_CHECKBOX) {
    1038           0 :         moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
    1039             :       } else {
    1040           0 :         moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
    1041             :       }
    1042             : 
    1043           0 :       aExtra->top = indicator_spacing;
    1044           0 :       aExtra->right = indicator_spacing;
    1045           0 :       aExtra->bottom = indicator_spacing;
    1046           0 :       aExtra->left = indicator_spacing;
    1047           0 :       break;
    1048             :     }
    1049             :   case NS_THEME_BUTTON :
    1050             :     {
    1051           0 :       if (IsDefaultButton(aFrame)) {
    1052             :         // Some themes draw a default indicator outside the widget,
    1053             :         // include that in overflow
    1054             :         gint top, left, bottom, right;
    1055           0 :         moz_gtk_button_get_default_overflow(&top, &left, &bottom, &right);
    1056           0 :         aExtra->top = top;
    1057           0 :         aExtra->right = right;
    1058           0 :         aExtra->bottom = bottom;
    1059           0 :         aExtra->left = left;
    1060           0 :         break;
    1061             :       }
    1062           0 :       return false;
    1063             :     }
    1064             :   case NS_THEME_FOCUS_OUTLINE:
    1065             :     {
    1066           0 :       moz_gtk_get_focus_outline_size(&aExtra->left, &aExtra->top);
    1067           0 :       aExtra->right = aExtra->left;
    1068           0 :       aExtra->bottom = aExtra->top;
    1069           0 :       break;
    1070             :     }
    1071             :   case NS_THEME_TAB :
    1072             :     {
    1073           0 :       if (!IsSelectedTab(aFrame))
    1074           0 :         return false;
    1075             : 
    1076           0 :       gint gap_height = moz_gtk_get_tab_thickness(IsBottomTab(aFrame) ?
    1077           0 :                             MOZ_GTK_TAB_BOTTOM : MOZ_GTK_TAB_TOP);
    1078           0 :       if (!gap_height)
    1079           0 :         return false;
    1080             : 
    1081           0 :       int32_t extra = gap_height - GetTabMarginPixels(aFrame);
    1082           0 :       if (extra <= 0)
    1083           0 :         return false;
    1084             : 
    1085           0 :       if (IsBottomTab(aFrame)) {
    1086           0 :         aExtra->top = extra;
    1087             :       } else {
    1088           0 :         aExtra->bottom = extra;
    1089             :       }
    1090           0 :       return false;
    1091             :     }
    1092             :   default:
    1093         202 :     return false;
    1094             :   }
    1095          10 :   gint scale = ScreenHelperGTK::GetGTKMonitorScaleFactor();
    1096          10 :   aExtra->top *= scale;
    1097          10 :   aExtra->right *= scale;
    1098          10 :   aExtra->bottom *= scale;
    1099          10 :   aExtra->left *= scale;
    1100          10 :   return true;
    1101             : }
    1102             : 
    1103             : NS_IMETHODIMP
    1104          18 : nsNativeThemeGTK::DrawWidgetBackground(gfxContext* aContext,
    1105             :                                        nsIFrame* aFrame,
    1106             :                                        uint8_t aWidgetType,
    1107             :                                        const nsRect& aRect,
    1108             :                                        const nsRect& aDirtyRect)
    1109             : {
    1110             :   GtkWidgetState state;
    1111             :   WidgetNodeType gtkWidgetType;
    1112          18 :   GtkTextDirection direction = GetTextDirection(aFrame);
    1113             :   gint flags;
    1114          18 :   if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, &state,
    1115             :                             &flags))
    1116           0 :     return NS_OK;
    1117             : 
    1118          18 :   gfxContext* ctx = aContext;
    1119          18 :   nsPresContext *presContext = aFrame->PresContext();
    1120             : 
    1121          18 :   gfxRect rect = presContext->AppUnitsToGfxUnits(aRect);
    1122          18 :   gfxRect dirtyRect = presContext->AppUnitsToGfxUnits(aDirtyRect);
    1123          18 :   gint scaleFactor = ScreenHelperGTK::GetGTKMonitorScaleFactor();
    1124             : 
    1125             :   // Align to device pixels where sensible
    1126             :   // to provide crisper and faster drawing.
    1127             :   // Don't snap if it's a non-unit scale factor. We're going to have to take
    1128             :   // slow paths then in any case.
    1129          18 :   bool snapped = ctx->UserToDevicePixelSnapped(rect);
    1130          18 :   if (snapped) {
    1131             :     // Leave rect in device coords but make dirtyRect consistent.
    1132          18 :     dirtyRect = ctx->UserToDevice(dirtyRect);
    1133             :   }
    1134             : 
    1135             :   // Translate the dirty rect so that it is wrt the widget top-left.
    1136          18 :   dirtyRect.MoveBy(-rect.TopLeft());
    1137             :   // Round out the dirty rect to gdk pixels to ensure that gtk draws
    1138             :   // enough pixels for interpolation to device pixels.
    1139          18 :   dirtyRect.RoundOut();
    1140             : 
    1141             :   // GTK themes can only draw an integer number of pixels
    1142             :   // (even when not snapped).
    1143          18 :   nsIntRect widgetRect(0, 0, NS_lround(rect.Width()), NS_lround(rect.Height()));
    1144          18 :   nsIntRect overflowRect(widgetRect);
    1145          18 :   nsIntMargin extraSize;
    1146          18 :   if (GetExtraSizeForWidget(aFrame, aWidgetType, &extraSize)) {
    1147           0 :     overflowRect.Inflate(extraSize);
    1148             :   }
    1149             : 
    1150             :   // This is the rectangle that will actually be drawn, in gdk pixels
    1151          18 :   nsIntRect drawingRect(int32_t(dirtyRect.X()),
    1152          18 :                         int32_t(dirtyRect.Y()),
    1153          18 :                         int32_t(dirtyRect.Width()),
    1154          72 :                         int32_t(dirtyRect.Height()));
    1155          36 :   if (widgetRect.IsEmpty()
    1156          18 :       || !drawingRect.IntersectRect(overflowRect, drawingRect))
    1157           0 :     return NS_OK;
    1158             : 
    1159          18 :   NS_ASSERTION(!IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType),
    1160             :                "Trying to render an unsafe widget!");
    1161             : 
    1162          18 :   bool safeState = IsWidgetStateSafe(mSafeWidgetStates, aWidgetType, &state);
    1163          18 :   if (!safeState) {
    1164           3 :     gLastGdkError = 0;
    1165           3 :     gdk_error_trap_push ();
    1166             :   }
    1167             : 
    1168          18 :   Transparency transparency = GetWidgetTransparency(aFrame, aWidgetType);
    1169             : 
    1170             :   // gdk rectangles are wrt the drawing rect.
    1171          18 :   GdkRectangle gdk_rect = {-drawingRect.x/scaleFactor,
    1172          18 :                            -drawingRect.y/scaleFactor,
    1173          18 :                            widgetRect.width/scaleFactor,
    1174          54 :                            widgetRect.height/scaleFactor};
    1175             : 
    1176             :   // translate everything so (0,0) is the top left of the drawingRect
    1177          18 :   gfxPoint origin = rect.TopLeft() + drawingRect.TopLeft();
    1178             : 
    1179             : #if (MOZ_WIDGET_GTK == 2)
    1180             :   gfxContextAutoSaveRestore autoSR(ctx);
    1181             :   gfxMatrix matrix;
    1182             :   if (!snapped) { // else rects are in device coords
    1183             :     matrix = ctx->CurrentMatrix();
    1184             :   }
    1185             :   matrix.Translate(origin);
    1186             :   matrix.Scale(scaleFactor, scaleFactor); // Draw in GDK coords
    1187             :   ctx->SetMatrix(matrix);
    1188             : 
    1189             :   // The gdk_clip is just advisory here, meaning "you don't
    1190             :   // need to draw outside this rect if you don't feel like it!"
    1191             :   GdkRectangle gdk_clip = {0, 0, drawingRect.width, drawingRect.height};
    1192             : 
    1193             :   ThemeRenderer renderer(state, gtkWidgetType, flags, direction,
    1194             :                          gdk_rect, gdk_clip);
    1195             : 
    1196             :   // Some themes (e.g. Clearlooks) just don't clip properly to any
    1197             :   // clip rect we provide, so we cannot advertise support for clipping within
    1198             :   // the widget bounds.
    1199             :   uint32_t rendererFlags = 0;
    1200             :   if (transparency == eOpaque) {
    1201             :     rendererFlags |= gfxGdkNativeRenderer::DRAW_IS_OPAQUE;
    1202             :   }
    1203             : 
    1204             :   // GtkStyles (used by the widget drawing backend) are created for a
    1205             :   // particular colormap/visual.
    1206             :   GdkColormap* colormap = moz_gtk_widget_get_colormap();
    1207             : 
    1208             :   renderer.Draw(ctx, drawingRect.Size(), rendererFlags, colormap);
    1209             : #else 
    1210          36 :   DrawThemeWithCairo(ctx, aContext->GetDrawTarget(),
    1211             :                      state, gtkWidgetType, flags, direction, scaleFactor,
    1212          36 :                      snapped, ToPoint(origin), drawingRect.Size(),
    1213          36 :                      gdk_rect, transparency);
    1214             : #endif
    1215             : 
    1216          18 :   if (!safeState) {
    1217           3 :     gdk_flush();
    1218           3 :     gLastGdkError = gdk_error_trap_pop ();
    1219             : 
    1220           3 :     if (gLastGdkError) {
    1221             : #ifdef DEBUG
    1222           0 :       printf("GTK theme failed for widget type %d, error was %d, state was "
    1223             :              "[active=%d,focused=%d,inHover=%d,disabled=%d]\n",
    1224           0 :              aWidgetType, gLastGdkError, state.active, state.focused,
    1225           0 :              state.inHover, state.disabled);
    1226             : #endif
    1227           0 :       NS_WARNING("GTK theme failed; disabling unsafe widget");
    1228           0 :       SetWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType);
    1229             :       // force refresh of the window, because the widget was not
    1230             :       // successfully drawn it must be redrawn using the default look
    1231           0 :       RefreshWidgetWindow(aFrame);
    1232             :     } else {
    1233           3 :       SetWidgetStateSafe(mSafeWidgetStates, aWidgetType, &state);
    1234             :     }
    1235             :   }
    1236             : 
    1237             :   // Indeterminate progress bar are animated.
    1238          36 :   if (gtkWidgetType == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE ||
    1239          18 :       gtkWidgetType == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) {
    1240           0 :     if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) {
    1241           0 :       NS_WARNING("unable to animate widget!");
    1242             :     }
    1243             :   }
    1244             : 
    1245          18 :   return NS_OK;
    1246             : }
    1247             : 
    1248             : WidgetNodeType
    1249           0 : nsNativeThemeGTK::NativeThemeToGtkTheme(uint8_t aWidgetType, nsIFrame* aFrame)
    1250             : {
    1251             :   WidgetNodeType gtkWidgetType;
    1252             :   gint unusedFlags;
    1253             : 
    1254           0 :   if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nullptr,
    1255             :                             &unusedFlags))
    1256             :   {
    1257           0 :     MOZ_ASSERT_UNREACHABLE("Unknown native widget to gtk widget mapping");
    1258             :     return MOZ_GTK_WINDOW;
    1259             :   }
    1260           0 :   return gtkWidgetType;
    1261             : }
    1262             : 
    1263             : void
    1264         294 : nsNativeThemeGTK::GetCachedWidgetBorder(nsIFrame* aFrame, uint8_t aWidgetType,
    1265             :                                         GtkTextDirection aDirection,
    1266             :                                         nsIntMargin* aResult)
    1267             : {
    1268         294 :   aResult->SizeTo(0, 0, 0, 0);
    1269             : 
    1270             :   WidgetNodeType gtkWidgetType;
    1271             :   gint unusedFlags;
    1272         294 :   if (GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nullptr,
    1273             :                            &unusedFlags)) {
    1274         288 :     MOZ_ASSERT(0 <= gtkWidgetType && gtkWidgetType < MOZ_GTK_WIDGET_NODE_COUNT);
    1275         288 :     uint8_t cacheIndex = gtkWidgetType / 8;
    1276         288 :     uint8_t cacheBit = 1u << (gtkWidgetType % 8);
    1277             : 
    1278         288 :     if (mBorderCacheValid[cacheIndex] & cacheBit) {
    1279         280 :       *aResult = mBorderCache[gtkWidgetType];
    1280             :     } else {
    1281           8 :       moz_gtk_get_widget_border(gtkWidgetType, &aResult->left, &aResult->top,
    1282           8 :                                 &aResult->right, &aResult->bottom, aDirection);
    1283           8 :       if (aWidgetType != MOZ_GTK_DROPDOWN) { // depends on aDirection
    1284           8 :         mBorderCacheValid[cacheIndex] |= cacheBit;
    1285           8 :         mBorderCache[gtkWidgetType] = *aResult;
    1286             :       }
    1287             :     }
    1288             :   }
    1289         294 : }
    1290             : 
    1291             : NS_IMETHODIMP
    1292         386 : nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame,
    1293             :                                   uint8_t aWidgetType, nsIntMargin* aResult)
    1294             : {
    1295         386 :   GtkTextDirection direction = GetTextDirection(aFrame);
    1296         386 :   aResult->top = aResult->left = aResult->right = aResult->bottom = 0;
    1297         386 :   switch (aWidgetType) {
    1298             :   case NS_THEME_SCROLLBAR_HORIZONTAL:
    1299             :   case NS_THEME_SCROLLBAR_VERTICAL:
    1300             :     {
    1301             :       GtkOrientation orientation =
    1302          26 :         aWidgetType == NS_THEME_SCROLLBAR_HORIZONTAL ?
    1303          26 :         GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
    1304          26 :       const ScrollbarGTKMetrics* metrics = GetScrollbarMetrics(orientation);
    1305             : 
    1306          26 :       const GtkBorder& border = metrics->border.scrollbar;
    1307          26 :       aResult->top = border.top;
    1308          26 :       aResult->right = border.right;
    1309          26 :       aResult->bottom = border.bottom;
    1310          26 :       aResult->left = border.left;
    1311             :     }
    1312          26 :     break;
    1313             :   case NS_THEME_SCROLLBARTRACK_HORIZONTAL:
    1314             :   case NS_THEME_SCROLLBARTRACK_VERTICAL:
    1315             :     {
    1316             :       GtkOrientation orientation =
    1317          66 :         aWidgetType == NS_THEME_SCROLLBARTRACK_HORIZONTAL ?
    1318          66 :         GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
    1319          66 :       const ScrollbarGTKMetrics* metrics = GetScrollbarMetrics(orientation);
    1320             : 
    1321          66 :       const GtkBorder& border = metrics->border.track;
    1322          66 :       aResult->top = border.top;
    1323          66 :       aResult->right = border.right;
    1324          66 :       aResult->bottom = border.bottom;
    1325          66 :       aResult->left = border.left;
    1326             :     }
    1327          66 :     break;
    1328             :   case NS_THEME_TOOLBOX:
    1329             :     // gtk has no toolbox equivalent.  So, although we map toolbox to
    1330             :     // gtk's 'toolbar' for purposes of painting the widget background,
    1331             :     // we don't use the toolbar border for toolbox.
    1332           0 :     break;
    1333             :   case NS_THEME_DUALBUTTON:
    1334             :     // TOOLBAR_DUAL_BUTTON is an interesting case.  We want a border to draw
    1335             :     // around the entire button + dropdown, and also an inner border if you're
    1336             :     // over the button part.  But, we want the inner button to be right up
    1337             :     // against the edge of the outer button so that the borders overlap.
    1338             :     // To make this happen, we draw a button border for the outer button,
    1339             :     // but don't reserve any space for it.
    1340           0 :     break;
    1341             :   case NS_THEME_TAB:
    1342             :     {
    1343             :       WidgetNodeType gtkWidgetType;
    1344             :       gint flags;
    1345             : 
    1346           0 :       if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nullptr,
    1347             :                                 &flags))
    1348           0 :         return NS_OK;
    1349             : 
    1350           0 :       moz_gtk_get_tab_border(&aResult->left, &aResult->top,
    1351             :                              &aResult->right, &aResult->bottom, direction,
    1352           0 :                              (GtkTabFlags)flags, gtkWidgetType);
    1353             :     }
    1354           0 :     break;
    1355             :   case NS_THEME_MENUITEM:
    1356             :   case NS_THEME_CHECKMENUITEM:
    1357             :   case NS_THEME_RADIOMENUITEM:
    1358             :     // For regular menuitems, we will be using GetWidgetPadding instead of
    1359             :     // GetWidgetBorder to pad up the widget's internals; other menuitems
    1360             :     // will need to fall through and use the default case as before.
    1361          77 :     if (IsRegularMenuItem(aFrame))
    1362           0 :       break;
    1363             :     MOZ_FALLTHROUGH;
    1364             :   default:
    1365             :     {
    1366         294 :       GetCachedWidgetBorder(aFrame, aWidgetType, direction, aResult);
    1367             :     }
    1368             :   }
    1369             : 
    1370         386 :   gint scale = ScreenHelperGTK::GetGTKMonitorScaleFactor();
    1371         386 :   aResult->top *= scale;
    1372         386 :   aResult->right *= scale;
    1373         386 :   aResult->bottom *= scale;
    1374         386 :   aResult->left *= scale;
    1375         386 :   return NS_OK;
    1376             : }
    1377             : 
    1378             : bool
    1379         329 : nsNativeThemeGTK::GetWidgetPadding(nsDeviceContext* aContext,
    1380             :                                    nsIFrame* aFrame, uint8_t aWidgetType,
    1381             :                                    nsIntMargin* aResult)
    1382             : {
    1383         329 :   switch (aWidgetType) {
    1384             :     case NS_THEME_BUTTON_FOCUS:
    1385             :     case NS_THEME_TOOLBARBUTTON:
    1386             :     case NS_THEME_DUALBUTTON:
    1387             :     case NS_THEME_TAB_SCROLL_ARROW_BACK:
    1388             :     case NS_THEME_TAB_SCROLL_ARROW_FORWARD:
    1389             :     case NS_THEME_MENULIST_BUTTON:
    1390             :     case NS_THEME_TOOLBARBUTTON_DROPDOWN:
    1391             :     case NS_THEME_BUTTON_ARROW_UP:
    1392             :     case NS_THEME_BUTTON_ARROW_DOWN:
    1393             :     case NS_THEME_BUTTON_ARROW_NEXT:
    1394             :     case NS_THEME_BUTTON_ARROW_PREVIOUS:
    1395             :     case NS_THEME_RANGE_THUMB:
    1396             :     // Radios and checkboxes return a fixed size in GetMinimumWidgetSize
    1397             :     // and have a meaningful baseline, so they can't have
    1398             :     // author-specified padding.
    1399             :     case NS_THEME_CHECKBOX:
    1400             :     case NS_THEME_RADIO:
    1401          10 :       aResult->SizeTo(0, 0, 0, 0);
    1402          10 :       return true;
    1403             :     case NS_THEME_MENUITEM:
    1404             :     case NS_THEME_CHECKMENUITEM:
    1405             :     case NS_THEME_RADIOMENUITEM:
    1406             :       {
    1407             :         // Menubar and menulist have their padding specified in CSS.
    1408          77 :         if (!IsRegularMenuItem(aFrame))
    1409          77 :           return false;
    1410             : 
    1411           0 :         GetCachedWidgetBorder(aFrame, aWidgetType, GetTextDirection(aFrame),
    1412           0 :                               aResult);
    1413             : 
    1414             :         gint horizontal_padding;
    1415             : 
    1416           0 :         if (aWidgetType == NS_THEME_MENUITEM)
    1417           0 :           moz_gtk_menuitem_get_horizontal_padding(&horizontal_padding);
    1418             :         else
    1419           0 :           moz_gtk_checkmenuitem_get_horizontal_padding(&horizontal_padding);
    1420             : 
    1421           0 :         aResult->left += horizontal_padding;
    1422           0 :         aResult->right += horizontal_padding;
    1423             : 
    1424           0 :         gint scale = ScreenHelperGTK::GetGTKMonitorScaleFactor();
    1425           0 :         aResult->top *= scale;
    1426           0 :         aResult->right *= scale;
    1427           0 :         aResult->bottom *= scale;
    1428           0 :         aResult->left *= scale;
    1429             : 
    1430           0 :         return true;
    1431             :       }
    1432             :   }
    1433             : 
    1434         242 :   return false;
    1435             : }
    1436             : 
    1437             : bool
    1438         194 : nsNativeThemeGTK::GetWidgetOverflow(nsDeviceContext* aContext,
    1439             :                                     nsIFrame* aFrame, uint8_t aWidgetType,
    1440             :                                     nsRect* aOverflowRect)
    1441             : {
    1442         194 :   nsIntMargin extraSize;
    1443         194 :   if (!GetExtraSizeForWidget(aFrame, aWidgetType, &extraSize))
    1444         184 :     return false;
    1445             : 
    1446          10 :   int32_t p2a = aContext->AppUnitsPerDevPixel();
    1447             :   nsMargin m(NSIntPixelsToAppUnits(extraSize.top, p2a),
    1448             :              NSIntPixelsToAppUnits(extraSize.right, p2a),
    1449             :              NSIntPixelsToAppUnits(extraSize.bottom, p2a),
    1450          10 :              NSIntPixelsToAppUnits(extraSize.left, p2a));
    1451             : 
    1452          10 :   aOverflowRect->Inflate(m);
    1453          10 :   return true;
    1454             : }
    1455             : 
    1456             : NS_IMETHODIMP
    1457          82 : nsNativeThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
    1458             :                                        nsIFrame* aFrame, uint8_t aWidgetType,
    1459             :                                        LayoutDeviceIntSize* aResult,
    1460             :                                        bool* aIsOverridable)
    1461             : {
    1462          82 :   aResult->width = aResult->height = 0;
    1463          82 :   *aIsOverridable = true;
    1464             : 
    1465          82 :   switch (aWidgetType) {
    1466             :     case NS_THEME_SCROLLBARBUTTON_UP:
    1467             :     case NS_THEME_SCROLLBARBUTTON_DOWN:
    1468             :       {
    1469             :         const ScrollbarGTKMetrics* metrics =
    1470           0 :           GetScrollbarMetrics(GTK_ORIENTATION_VERTICAL);
    1471             : 
    1472           0 :         aResult->width = metrics->size.button.width;
    1473           0 :         aResult->height = metrics->size.button.height;
    1474           0 :         *aIsOverridable = false;
    1475             :       }
    1476           0 :       break;
    1477             :     case NS_THEME_SCROLLBARBUTTON_LEFT:
    1478             :     case NS_THEME_SCROLLBARBUTTON_RIGHT:
    1479             :       {
    1480             :         const ScrollbarGTKMetrics* metrics =
    1481           0 :           GetScrollbarMetrics(GTK_ORIENTATION_HORIZONTAL);
    1482             : 
    1483           0 :         aResult->width = metrics->size.button.width;
    1484           0 :         aResult->height = metrics->size.button.height;
    1485           0 :         *aIsOverridable = false;
    1486             :       }
    1487           0 :       break;
    1488             :     case NS_THEME_SPLITTER:
    1489             :     {
    1490             :       gint metrics;
    1491           0 :       if (IsHorizontal(aFrame)) {
    1492           0 :         moz_gtk_splitter_get_metrics(GTK_ORIENTATION_HORIZONTAL, &metrics);
    1493           0 :         aResult->width = metrics;
    1494           0 :         aResult->height = 0;
    1495             :       } else {
    1496           0 :         moz_gtk_splitter_get_metrics(GTK_ORIENTATION_VERTICAL, &metrics);
    1497           0 :         aResult->width = 0;
    1498           0 :         aResult->height = metrics;
    1499             :       }
    1500           0 :       *aIsOverridable = false;
    1501             :     }
    1502           0 :     break;
    1503             :     case NS_THEME_SCROLLBAR_HORIZONTAL:
    1504             :     case NS_THEME_SCROLLBAR_VERTICAL:
    1505             :     {
    1506             :       /* While we enforce a minimum size for the thumb, this is ignored
    1507             :        * for the some scrollbars if buttons are hidden (bug 513006) because
    1508             :        * the thumb isn't a direct child of the scrollbar, unlike the buttons
    1509             :        * or track. So add a minimum size to the track as well to prevent a
    1510             :        * 0-width scrollbar. */
    1511             :       GtkOrientation orientation =
    1512           6 :         aWidgetType == NS_THEME_SCROLLBAR_HORIZONTAL ?
    1513           6 :         GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
    1514           6 :       const ScrollbarGTKMetrics* metrics = GetScrollbarMetrics(orientation);
    1515             : 
    1516           6 :       aResult->width = metrics->size.scrollbar.width;
    1517           6 :       aResult->height = metrics->size.scrollbar.height;
    1518             :     }
    1519           6 :     break;
    1520             :     case NS_THEME_SCROLLBARTHUMB_VERTICAL:
    1521             :     case NS_THEME_SCROLLBARTHUMB_HORIZONTAL:
    1522             :       {
    1523             :         GtkOrientation orientation =
    1524           4 :           aWidgetType == NS_THEME_SCROLLBARTHUMB_HORIZONTAL ?
    1525           4 :           GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
    1526           4 :         const ScrollbarGTKMetrics* metrics = GetScrollbarMetrics(orientation);
    1527             : 
    1528           4 :         aResult->width = metrics->size.thumb.width;
    1529           4 :         aResult->height = metrics->size.thumb.height;
    1530           4 :         *aIsOverridable = false;
    1531             :       }
    1532           4 :       break;
    1533             :     case NS_THEME_RANGE_THUMB:
    1534             :       {
    1535             :         gint thumb_length, thumb_height;
    1536             : 
    1537           0 :         if (IsRangeHorizontal(aFrame)) {
    1538           0 :           moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_length, &thumb_height);
    1539             :         } else {
    1540           0 :           moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_length);
    1541             :         }
    1542           0 :         aResult->width = thumb_length;
    1543           0 :         aResult->height = thumb_height;
    1544             : 
    1545           0 :         *aIsOverridable = false;
    1546             :       }
    1547           0 :       break;
    1548             :     case NS_THEME_RANGE:
    1549             :       {
    1550             :         gint scale_width, scale_height;
    1551             : 
    1552           0 :         moz_gtk_get_scale_metrics(IsRangeHorizontal(aFrame) ?
    1553             :             GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL,
    1554           0 :             &scale_width, &scale_height);
    1555           0 :         aResult->width = scale_width;
    1556           0 :         aResult->height = scale_height;
    1557             : 
    1558           0 :         *aIsOverridable = true;
    1559             :       }
    1560           0 :       break;
    1561             :     case NS_THEME_SCALETHUMB_HORIZONTAL:
    1562             :     case NS_THEME_SCALETHUMB_VERTICAL:
    1563             :       {
    1564             :         gint thumb_length, thumb_height;
    1565             : 
    1566           0 :         if (aWidgetType == NS_THEME_SCALETHUMB_VERTICAL) {
    1567           0 :           moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_length, &thumb_height);
    1568           0 :           aResult->width = thumb_height;
    1569           0 :           aResult->height = thumb_length;
    1570             :         } else {
    1571           0 :           moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_length, &thumb_height);
    1572           0 :           aResult->width = thumb_length;
    1573           0 :           aResult->height = thumb_height;
    1574             :         }
    1575             : 
    1576           0 :         *aIsOverridable = false;
    1577             :       }
    1578           0 :       break;
    1579             :     case NS_THEME_TAB_SCROLL_ARROW_BACK:
    1580             :     case NS_THEME_TAB_SCROLL_ARROW_FORWARD:
    1581             :       {
    1582           0 :         moz_gtk_get_tab_scroll_arrow_size(&aResult->width, &aResult->height);
    1583           0 :         *aIsOverridable = false;
    1584             :       }
    1585           0 :       break;
    1586             :   case NS_THEME_MENULIST_BUTTON:
    1587             :     {
    1588           0 :       moz_gtk_get_combo_box_entry_button_size(&aResult->width,
    1589           0 :                                               &aResult->height);
    1590           0 :       *aIsOverridable = false;
    1591             :     }
    1592           0 :     break;
    1593             :   case NS_THEME_MENUSEPARATOR:
    1594             :     {
    1595             :       gint separator_height;
    1596             : 
    1597           0 :       moz_gtk_get_menu_separator_height(&separator_height);
    1598           0 :       aResult->height = separator_height;
    1599             :     
    1600           0 :       *aIsOverridable = false;
    1601             :     }
    1602           0 :     break;
    1603             :   case NS_THEME_CHECKBOX:
    1604             :   case NS_THEME_RADIO:
    1605             :     {
    1606             :       gint indicator_size, indicator_spacing;
    1607             : 
    1608           0 :       if (aWidgetType == NS_THEME_CHECKBOX) {
    1609           0 :         moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
    1610             :       } else {
    1611           0 :         moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
    1612             :       }
    1613             : 
    1614             :       // Include space for the indicator and the padding around it.
    1615           0 :       aResult->width = indicator_size;
    1616           0 :       aResult->height = indicator_size;
    1617             :     }
    1618           0 :     break;
    1619             :   case NS_THEME_TOOLBARBUTTON_DROPDOWN:
    1620             :   case NS_THEME_BUTTON_ARROW_UP:
    1621             :   case NS_THEME_BUTTON_ARROW_DOWN:
    1622             :   case NS_THEME_BUTTON_ARROW_NEXT:
    1623             :   case NS_THEME_BUTTON_ARROW_PREVIOUS:
    1624             :     {
    1625           2 :       moz_gtk_get_arrow_size(MOZ_GTK_TOOLBARBUTTON_ARROW,
    1626           2 :                              &aResult->width, &aResult->height);
    1627           2 :       *aIsOverridable = false;
    1628             :     }
    1629           2 :     break;
    1630             :   case NS_THEME_CHECKBOX_CONTAINER:
    1631             :   case NS_THEME_RADIO_CONTAINER:
    1632             :   case NS_THEME_CHECKBOX_LABEL:
    1633             :   case NS_THEME_RADIO_LABEL:
    1634             :   case NS_THEME_BUTTON:
    1635             :   case NS_THEME_MENULIST:
    1636             :   case NS_THEME_TOOLBARBUTTON:
    1637             :   case NS_THEME_TREEHEADERCELL:
    1638             :     {
    1639           0 :       if (aWidgetType == NS_THEME_MENULIST) {
    1640             :         // Include the arrow size.
    1641           0 :         moz_gtk_get_arrow_size(MOZ_GTK_DROPDOWN,
    1642           0 :                                &aResult->width, &aResult->height);
    1643             :       }
    1644             :       // else the minimum size is missing consideration of container
    1645             :       // descendants; the value returned here will not be helpful, but the
    1646             :       // box model may consider border and padding with child minimum sizes.
    1647             : 
    1648           0 :       nsIntMargin border;
    1649           0 :       nsNativeThemeGTK::GetWidgetBorder(aFrame->PresContext()->DeviceContext(),
    1650           0 :                                         aFrame, aWidgetType, &border);
    1651           0 :       aResult->width += border.left + border.right;
    1652           0 :       aResult->height += border.top + border.bottom;
    1653             :     }
    1654           0 :     break;
    1655             : #if (MOZ_WIDGET_GTK == 3)
    1656             :   case NS_THEME_NUMBER_INPUT:
    1657             :   case NS_THEME_TEXTFIELD:
    1658             :     {
    1659           0 :       moz_gtk_get_entry_min_height(&aResult->height);
    1660             :     }
    1661           0 :     break;
    1662             : #endif
    1663             :   case NS_THEME_SEPARATOR:
    1664             :     {
    1665             :       gint separator_width;
    1666             :     
    1667           0 :       moz_gtk_get_toolbar_separator_width(&separator_width);
    1668             :     
    1669           0 :       aResult->width = separator_width;
    1670             :     }
    1671           0 :     break;
    1672             :   case NS_THEME_SPINNER:
    1673             :     // hard code these sizes
    1674           0 :     aResult->width = 14;
    1675           0 :     aResult->height = 26;
    1676           0 :     break;
    1677             :   case NS_THEME_TREEHEADERSORTARROW:
    1678             :   case NS_THEME_SPINNER_UPBUTTON:
    1679             :   case NS_THEME_SPINNER_DOWNBUTTON:
    1680             :     // hard code these sizes
    1681           0 :     aResult->width = 14;
    1682           0 :     aResult->height = 13;
    1683           0 :     break;
    1684             :   case NS_THEME_RESIZER:
    1685             :     // same as Windows to make our lives easier
    1686           0 :     aResult->width = aResult->height = 15;
    1687           0 :     *aIsOverridable = false;
    1688           0 :     break;
    1689             :   case NS_THEME_TREETWISTY:
    1690             :   case NS_THEME_TREETWISTYOPEN:
    1691             :     {
    1692             :       gint expander_size;
    1693             : 
    1694           0 :       moz_gtk_get_treeview_expander_size(&expander_size);
    1695           0 :       aResult->width = aResult->height = expander_size;
    1696           0 :       *aIsOverridable = false;
    1697             :     }
    1698           0 :     break;
    1699             :   }
    1700             : 
    1701          82 :   *aResult = *aResult * ScreenHelperGTK::GetGTKMonitorScaleFactor();
    1702             : 
    1703          82 :   return NS_OK;
    1704             : }
    1705             : 
    1706             : NS_IMETHODIMP
    1707          55 : nsNativeThemeGTK::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType, 
    1708             :                                      nsIAtom* aAttribute, bool* aShouldRepaint,
    1709             :                                      const nsAttrValue* aOldValue)
    1710             : {
    1711             :   // Some widget types just never change state.
    1712          55 :   if (aWidgetType == NS_THEME_TOOLBOX ||
    1713          55 :       aWidgetType == NS_THEME_TOOLBAR ||
    1714          55 :       aWidgetType == NS_THEME_STATUSBAR ||
    1715          55 :       aWidgetType == NS_THEME_STATUSBARPANEL ||
    1716          55 :       aWidgetType == NS_THEME_RESIZERPANEL ||
    1717          55 :       aWidgetType == NS_THEME_PROGRESSCHUNK ||
    1718          55 :       aWidgetType == NS_THEME_PROGRESSCHUNK_VERTICAL ||
    1719          55 :       aWidgetType == NS_THEME_PROGRESSBAR ||
    1720          55 :       aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL ||
    1721          50 :       aWidgetType == NS_THEME_MENUBAR ||
    1722          50 :       aWidgetType == NS_THEME_MENUPOPUP ||
    1723          50 :       aWidgetType == NS_THEME_TOOLTIP ||
    1724          50 :       aWidgetType == NS_THEME_MENUSEPARATOR ||
    1725          44 :       aWidgetType == NS_THEME_WINDOW ||
    1726             :       aWidgetType == NS_THEME_DIALOG) {
    1727          11 :     *aShouldRepaint = false;
    1728          11 :     return NS_OK;
    1729             :   }
    1730             : 
    1731          44 :   if ((aWidgetType == NS_THEME_SCROLLBARTHUMB_VERTICAL ||
    1732           4 :        aWidgetType == NS_THEME_SCROLLBARTHUMB_HORIZONTAL) &&
    1733           4 :        aAttribute == nsGkAtoms::active) {
    1734           0 :     *aShouldRepaint = true;
    1735           0 :     return NS_OK;
    1736             :   }
    1737             : 
    1738          44 :   if ((aWidgetType == NS_THEME_SCROLLBARBUTTON_UP ||
    1739          44 :        aWidgetType == NS_THEME_SCROLLBARBUTTON_DOWN ||
    1740          44 :        aWidgetType == NS_THEME_SCROLLBARBUTTON_LEFT ||
    1741           0 :        aWidgetType == NS_THEME_SCROLLBARBUTTON_RIGHT) &&
    1742           0 :       (aAttribute == nsGkAtoms::curpos ||
    1743           0 :        aAttribute == nsGkAtoms::maxpos)) {
    1744             :     // If 'curpos' has changed and we are passed its old value, we can
    1745             :     // determine whether the button's enablement actually needs to change.
    1746           0 :     if (aAttribute == nsGkAtoms::curpos && aOldValue) {
    1747           0 :       int32_t curpos = CheckIntAttr(aFrame, nsGkAtoms::curpos, 0);
    1748           0 :       int32_t maxpos = CheckIntAttr(aFrame, nsGkAtoms::maxpos, 0);
    1749           0 :       nsAutoString str;
    1750           0 :       aOldValue->ToString(str);
    1751             :       nsresult err;
    1752           0 :       int32_t oldCurpos = str.ToInteger(&err);
    1753           0 :       if (str.IsEmpty() || NS_FAILED(err)) {
    1754           0 :         *aShouldRepaint = true;
    1755             :       } else {
    1756           0 :         bool disabledBefore = ShouldScrollbarButtonBeDisabled(oldCurpos, maxpos, aWidgetType);
    1757           0 :         bool disabledNow = ShouldScrollbarButtonBeDisabled(curpos, maxpos, aWidgetType);
    1758           0 :         *aShouldRepaint = (disabledBefore != disabledNow);
    1759           0 :       }
    1760             :     } else {
    1761           0 :       *aShouldRepaint = true;
    1762             :     }
    1763           0 :     return NS_OK;
    1764             :   }
    1765             : 
    1766             :   // XXXdwh Not sure what can really be done here.  Can at least guess for
    1767             :   // specific widgets that they're highly unlikely to have certain states.
    1768             :   // For example, a toolbar doesn't care about any states.
    1769          44 :   if (!aAttribute) {
    1770             :     // Hover/focus/active changed.  Always repaint.
    1771           0 :     *aShouldRepaint = true;
    1772             :   }
    1773             :   else {
    1774             :     // Check the attribute to see if it's relevant.  
    1775             :     // disabled, checked, dlgtype, default, etc.
    1776          44 :     *aShouldRepaint = false;
    1777          80 :     if (aAttribute == nsGkAtoms::disabled ||
    1778          72 :         aAttribute == nsGkAtoms::checked ||
    1779          72 :         aAttribute == nsGkAtoms::selected ||
    1780          72 :         aAttribute == nsGkAtoms::visuallyselected ||
    1781          72 :         aAttribute == nsGkAtoms::focused ||
    1782          72 :         aAttribute == nsGkAtoms::readonly ||
    1783          72 :         aAttribute == nsGkAtoms::_default ||
    1784          72 :         aAttribute == nsGkAtoms::menuactive ||
    1785          72 :         aAttribute == nsGkAtoms::open ||
    1786          36 :         aAttribute == nsGkAtoms::parentfocused)
    1787           8 :       *aShouldRepaint = true;
    1788             :   }
    1789             : 
    1790          44 :   return NS_OK;
    1791             : }
    1792             : 
    1793             : NS_IMETHODIMP
    1794           2 : nsNativeThemeGTK::ThemeChanged()
    1795             : {
    1796           2 :   memset(mDisabledWidgetTypes, 0, sizeof(mDisabledWidgetTypes));
    1797           2 :   memset(mSafeWidgetStates, 0, sizeof(mSafeWidgetStates));
    1798           2 :   memset(mBorderCacheValid, 0, sizeof(mBorderCacheValid));
    1799           2 :   return NS_OK;
    1800             : }
    1801             : 
    1802             : NS_IMETHODIMP_(bool)
    1803        1268 : nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
    1804             :                                       nsIFrame* aFrame,
    1805             :                                       uint8_t aWidgetType)
    1806             : {
    1807        1268 :   if (IsWidgetTypeDisabled(mDisabledWidgetTypes, aWidgetType))
    1808           0 :     return false;
    1809             : 
    1810        1268 :   switch (aWidgetType) {
    1811             :   // Combobox dropdowns don't support native theming in vertical mode.
    1812             :   case NS_THEME_MENULIST:
    1813             :   case NS_THEME_MENULIST_TEXT:
    1814             :   case NS_THEME_MENULIST_TEXTFIELD:
    1815           0 :     if (aFrame && aFrame->GetWritingMode().IsVertical()) {
    1816           0 :       return false;
    1817             :     }
    1818             :     MOZ_FALLTHROUGH;
    1819             : 
    1820             :   case NS_THEME_BUTTON:
    1821             :   case NS_THEME_BUTTON_FOCUS:
    1822             :   case NS_THEME_RADIO:
    1823             :   case NS_THEME_CHECKBOX:
    1824             :   case NS_THEME_TOOLBOX: // N/A
    1825             :   case NS_THEME_TOOLBAR:
    1826             :   case NS_THEME_TOOLBARBUTTON:
    1827             :   case NS_THEME_DUALBUTTON: // so we can override the border with 0
    1828             :   case NS_THEME_TOOLBARBUTTON_DROPDOWN:
    1829             :   case NS_THEME_BUTTON_ARROW_UP:
    1830             :   case NS_THEME_BUTTON_ARROW_DOWN:
    1831             :   case NS_THEME_BUTTON_ARROW_NEXT:
    1832             :   case NS_THEME_BUTTON_ARROW_PREVIOUS:
    1833             :   case NS_THEME_SEPARATOR:
    1834             :   case NS_THEME_TOOLBARGRIPPER:
    1835             :   case NS_THEME_STATUSBAR:
    1836             :   case NS_THEME_STATUSBARPANEL:
    1837             :   case NS_THEME_RESIZERPANEL:
    1838             :   case NS_THEME_RESIZER:
    1839             :   case NS_THEME_LISTBOX:
    1840             :     // case NS_THEME_LISTITEM:
    1841             :   case NS_THEME_TREEVIEW:
    1842             :     // case NS_THEME_TREEITEM:
    1843             :   case NS_THEME_TREETWISTY:
    1844             :     // case NS_THEME_TREELINE:
    1845             :     // case NS_THEME_TREEHEADER:
    1846             :   case NS_THEME_TREEHEADERCELL:
    1847             :   case NS_THEME_TREEHEADERSORTARROW:
    1848             :   case NS_THEME_TREETWISTYOPEN:
    1849             :     case NS_THEME_PROGRESSBAR:
    1850             :     case NS_THEME_PROGRESSCHUNK:
    1851             :     case NS_THEME_PROGRESSBAR_VERTICAL:
    1852             :     case NS_THEME_PROGRESSCHUNK_VERTICAL:
    1853             :     case NS_THEME_TAB:
    1854             :     // case NS_THEME_TABPANEL:
    1855             :     case NS_THEME_TABPANELS:
    1856             :     case NS_THEME_TAB_SCROLL_ARROW_BACK:
    1857             :     case NS_THEME_TAB_SCROLL_ARROW_FORWARD:
    1858             :   case NS_THEME_TOOLTIP:
    1859             :   case NS_THEME_SPINNER:
    1860             :   case NS_THEME_SPINNER_UPBUTTON:
    1861             :   case NS_THEME_SPINNER_DOWNBUTTON:
    1862             :   case NS_THEME_SPINNER_TEXTFIELD:
    1863             :     // case NS_THEME_SCROLLBAR:  (n/a for gtk)
    1864             :     // case NS_THEME_SCROLLBAR_SMALL: (n/a for gtk)
    1865             :   case NS_THEME_SCROLLBARBUTTON_UP:
    1866             :   case NS_THEME_SCROLLBARBUTTON_DOWN:
    1867             :   case NS_THEME_SCROLLBARBUTTON_LEFT:
    1868             :   case NS_THEME_SCROLLBARBUTTON_RIGHT:
    1869             :   case NS_THEME_SCROLLBAR_HORIZONTAL:
    1870             :   case NS_THEME_SCROLLBAR_VERTICAL:
    1871             :   case NS_THEME_SCROLLBARTRACK_HORIZONTAL:
    1872             :   case NS_THEME_SCROLLBARTRACK_VERTICAL:
    1873             :   case NS_THEME_SCROLLBARTHUMB_HORIZONTAL:
    1874             :   case NS_THEME_SCROLLBARTHUMB_VERTICAL:
    1875             :   case NS_THEME_NUMBER_INPUT:
    1876             :   case NS_THEME_TEXTFIELD:
    1877             :   case NS_THEME_TEXTFIELD_MULTILINE:
    1878             :   case NS_THEME_RANGE:
    1879             :   case NS_THEME_RANGE_THUMB:
    1880             :   case NS_THEME_SCALE_HORIZONTAL:
    1881             :   case NS_THEME_SCALETHUMB_HORIZONTAL:
    1882             :   case NS_THEME_SCALE_VERTICAL:
    1883             :   case NS_THEME_SCALETHUMB_VERTICAL:
    1884             :     // case NS_THEME_SCALETHUMBSTART:
    1885             :     // case NS_THEME_SCALETHUMBEND:
    1886             :     // case NS_THEME_SCALETHUMBTICK:
    1887             :   case NS_THEME_CHECKBOX_CONTAINER:
    1888             :   case NS_THEME_RADIO_CONTAINER:
    1889             :   case NS_THEME_CHECKBOX_LABEL:
    1890             :   case NS_THEME_RADIO_LABEL:
    1891             :   case NS_THEME_MENUBAR:
    1892             :   case NS_THEME_MENUPOPUP:
    1893             :   case NS_THEME_MENUITEM:
    1894             :   case NS_THEME_MENUARROW:
    1895             :   case NS_THEME_MENUSEPARATOR:
    1896             :   case NS_THEME_CHECKMENUITEM:
    1897             :   case NS_THEME_RADIOMENUITEM:
    1898             :   case NS_THEME_SPLITTER:
    1899             :   case NS_THEME_WINDOW:
    1900             :   case NS_THEME_DIALOG:
    1901             : #if (MOZ_WIDGET_GTK == 3)
    1902             :   case NS_THEME_GTK_INFO_BAR:
    1903             : #endif
    1904        1268 :     return !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
    1905             : 
    1906             :   case NS_THEME_MENULIST_BUTTON:
    1907           0 :     if (aFrame && aFrame->GetWritingMode().IsVertical()) {
    1908           0 :       return false;
    1909             :     }
    1910             :     // "Native" dropdown buttons cause padding and margin problems, but only
    1911             :     // in HTML so allow them in XUL.
    1912           0 :     return (!aFrame || IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) &&
    1913           0 :            !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
    1914             : 
    1915             :   case NS_THEME_FOCUS_OUTLINE:
    1916           0 :     return true;
    1917             :   }
    1918             : 
    1919           0 :   return false;
    1920             : }
    1921             : 
    1922             : NS_IMETHODIMP_(bool)
    1923          81 : nsNativeThemeGTK::WidgetIsContainer(uint8_t aWidgetType)
    1924             : {
    1925             :   // XXXdwh At some point flesh all of this out.
    1926          81 :   if (aWidgetType == NS_THEME_MENULIST_BUTTON ||
    1927          81 :       aWidgetType == NS_THEME_RADIO ||
    1928          81 :       aWidgetType == NS_THEME_RANGE_THUMB ||
    1929          81 :       aWidgetType == NS_THEME_CHECKBOX ||
    1930          81 :       aWidgetType == NS_THEME_TAB_SCROLL_ARROW_BACK ||
    1931          81 :       aWidgetType == NS_THEME_TAB_SCROLL_ARROW_FORWARD ||
    1932          81 :       aWidgetType == NS_THEME_BUTTON_ARROW_UP ||
    1933          81 :       aWidgetType == NS_THEME_BUTTON_ARROW_DOWN ||
    1934          81 :       aWidgetType == NS_THEME_BUTTON_ARROW_NEXT ||
    1935             :       aWidgetType == NS_THEME_BUTTON_ARROW_PREVIOUS)
    1936           0 :     return false;
    1937          81 :   return true;
    1938             : }
    1939             : 
    1940             : bool
    1941           0 : nsNativeThemeGTK::ThemeDrawsFocusForWidget(uint8_t aWidgetType)
    1942             : {
    1943           0 :    if (aWidgetType == NS_THEME_MENULIST ||
    1944           0 :       aWidgetType == NS_THEME_BUTTON || 
    1945             :       aWidgetType == NS_THEME_TREEHEADERCELL)
    1946           0 :     return true;
    1947             :   
    1948           0 :   return false;
    1949             : }
    1950             : 
    1951             : bool
    1952           0 : nsNativeThemeGTK::ThemeNeedsComboboxDropmarker()
    1953             : {
    1954           0 :   return false;
    1955             : }
    1956             : 
    1957             : nsITheme::Transparency
    1958         119 : nsNativeThemeGTK::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType)
    1959             : {
    1960         119 :   switch (aWidgetType) {
    1961             :   // These widgets always draw a default background.
    1962             : #if (MOZ_WIDGET_GTK == 2)
    1963             :   case NS_THEME_TOOLBAR:
    1964             :   case NS_THEME_MENUBAR:
    1965             : #endif
    1966             :   case NS_THEME_MENUPOPUP:
    1967             :   case NS_THEME_WINDOW:
    1968             :   case NS_THEME_DIALOG:
    1969          62 :     return eOpaque;
    1970             :   case NS_THEME_SCROLLBAR_VERTICAL:
    1971             :   case NS_THEME_SCROLLBAR_HORIZONTAL:
    1972             : #if (MOZ_WIDGET_GTK == 3)
    1973             :     // Make scrollbar tracks opaque on the window's scroll frame to prevent
    1974             :     // leaf layers from overlapping. See bug 1179780.
    1975           0 :     if (!(CheckBooleanAttr(aFrame, nsGkAtoms::root_) &&
    1976           0 :           aFrame->PresContext()->IsRootContentDocument() &&
    1977           0 :           IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)))
    1978           0 :       return eTransparent;
    1979             : #endif
    1980           0 :     return eOpaque;
    1981             :   // Tooltips use gtk_paint_flat_box() on Gtk2
    1982             :   // but are shaped on Gtk3
    1983             :   case NS_THEME_TOOLTIP:
    1984             : #if (MOZ_WIDGET_GTK == 2)
    1985             :     return eOpaque;
    1986             : #else
    1987           0 :     return eTransparent;
    1988             : #endif
    1989             :   }
    1990             : 
    1991          57 :   return eUnknownTransparency;
    1992             : }

Generated by: LCOV version 1.13