LCOV - code coverage report
Current view: top level - layout/style - nsLayoutStylesheetCache.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 169 485 34.8 %
Date: 2017-07-14 16:53:18 Functions: 28 46 60.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsLayoutStylesheetCache.h"
       8             : 
       9             : #include "nsAppDirectoryServiceDefs.h"
      10             : #include "mozilla/StyleSheetInlines.h"
      11             : #include "mozilla/MemoryReporting.h"
      12             : #include "mozilla/Preferences.h"
      13             : #include "mozilla/StyleSheet.h"
      14             : #include "mozilla/StyleSheetInlines.h"
      15             : #include "mozilla/css/Loader.h"
      16             : #include "mozilla/dom/SRIMetadata.h"
      17             : #include "MainThreadUtils.h"
      18             : #include "nsColor.h"
      19             : #include "nsIConsoleService.h"
      20             : #include "nsIFile.h"
      21             : #include "nsNetUtil.h"
      22             : #include "nsIObserverService.h"
      23             : #include "nsServiceManagerUtils.h"
      24             : #include "nsIXULRuntime.h"
      25             : #include "nsPresContext.h"
      26             : #include "nsPrintfCString.h"
      27             : #include "nsXULAppAPI.h"
      28             : 
      29             : // Includes for the crash report annotation in ErrorLoadingSheet.
      30             : #ifdef MOZ_CRASHREPORTER
      31             : #include "mozilla/Omnijar.h"
      32             : #include "nsDirectoryService.h"
      33             : #include "nsDirectoryServiceDefs.h"
      34             : #include "nsExceptionHandler.h"
      35             : #include "nsIChromeRegistry.h"
      36             : #include "nsISimpleEnumerator.h"
      37             : #include "nsISubstitutingProtocolHandler.h"
      38             : #include "zlib.h"
      39             : #include "nsZipArchive.h"
      40             : #endif
      41             : 
      42             : using namespace mozilla;
      43             : using namespace mozilla::css;
      44             : 
      45             : static bool sNumberControlEnabled;
      46             : 
      47             : #define NUMBER_CONTROL_PREF "dom.forms.number"
      48             : 
      49          16 : NS_IMPL_ISUPPORTS(
      50             :   nsLayoutStylesheetCache, nsIObserver, nsIMemoryReporter)
      51             : 
      52             : nsresult
      53           0 : nsLayoutStylesheetCache::Observe(nsISupports* aSubject,
      54             :                             const char* aTopic,
      55             :                             const char16_t* aData)
      56             : {
      57           0 :   if (!strcmp(aTopic, "profile-before-change")) {
      58           0 :     mUserContentSheet = nullptr;
      59           0 :     mUserChromeSheet  = nullptr;
      60             :   }
      61           0 :   else if (!strcmp(aTopic, "profile-do-change")) {
      62           0 :     InitFromProfile();
      63             :   }
      64           0 :   else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
      65           0 :            strcmp(aTopic, "chrome-flush-caches") == 0) {
      66           0 :     mScrollbarsSheet = nullptr;
      67           0 :     mFormsSheet = nullptr;
      68           0 :     mNumberControlSheet = nullptr;
      69             :   }
      70             :   else {
      71           0 :     NS_NOTREACHED("Unexpected observer topic.");
      72             :   }
      73           0 :   return NS_OK;
      74             : }
      75             : 
      76             : StyleSheet*
      77           7 : nsLayoutStylesheetCache::ScrollbarsSheet()
      78             : {
      79           7 :   if (!mScrollbarsSheet) {
      80             :     // Scrollbars don't need access to unsafe rules
      81           2 :     LoadSheetURL("chrome://global/skin/scrollbars.css",
      82           2 :                  &mScrollbarsSheet, eSafeAgentSheetFeatures, eCrash);
      83             :   }
      84             : 
      85           7 :   return mScrollbarsSheet;
      86             : }
      87             : 
      88             : StyleSheet*
      89           9 : nsLayoutStylesheetCache::FormsSheet()
      90             : {
      91           9 :   if (!mFormsSheet) {
      92             :     // forms.css needs access to unsafe rules
      93           2 :     LoadSheetURL("resource://gre-resources/forms.css",
      94           2 :                  &mFormsSheet, eAgentSheetFeatures, eCrash);
      95             :   }
      96             : 
      97           9 :   return mFormsSheet;
      98             : }
      99             : 
     100             : StyleSheet*
     101           9 : nsLayoutStylesheetCache::NumberControlSheet()
     102             : {
     103           9 :   if (!sNumberControlEnabled) {
     104           0 :     return nullptr;
     105             :   }
     106             : 
     107           9 :   if (!mNumberControlSheet) {
     108           2 :     LoadSheetURL("resource://gre-resources/number-control.css",
     109           2 :                  &mNumberControlSheet, eAgentSheetFeatures, eCrash);
     110             :   }
     111             : 
     112           9 :   return mNumberControlSheet;
     113             : }
     114             : 
     115             : StyleSheet*
     116           5 : nsLayoutStylesheetCache::UserContentSheet()
     117             : {
     118           5 :   return mUserContentSheet;
     119             : }
     120             : 
     121             : StyleSheet*
     122           4 : nsLayoutStylesheetCache::UserChromeSheet()
     123             : {
     124           4 :   return mUserChromeSheet;
     125             : }
     126             : 
     127             : StyleSheet*
     128           9 : nsLayoutStylesheetCache::UASheet()
     129             : {
     130           9 :   if (!mUASheet) {
     131           2 :     LoadSheetURL("resource://gre-resources/ua.css",
     132           2 :                  &mUASheet, eAgentSheetFeatures, eCrash);
     133             :   }
     134             : 
     135           9 :   return mUASheet;
     136             : }
     137             : 
     138             : StyleSheet*
     139           9 : nsLayoutStylesheetCache::HTMLSheet()
     140             : {
     141           9 :   return mHTMLSheet;
     142             : }
     143             : 
     144             : StyleSheet*
     145           7 : nsLayoutStylesheetCache::MinimalXULSheet()
     146             : {
     147           7 :   return mMinimalXULSheet;
     148             : }
     149             : 
     150             : StyleSheet*
     151           4 : nsLayoutStylesheetCache::XULSheet()
     152             : {
     153           4 :   if (!mXULSheet) {
     154           1 :     LoadSheetURL("chrome://global/content/xul.css",
     155           1 :                  &mXULSheet, eAgentSheetFeatures, eCrash);
     156             :   }
     157             : 
     158           4 :   return mXULSheet;
     159             : }
     160             : 
     161             : StyleSheet*
     162           6 : nsLayoutStylesheetCache::QuirkSheet()
     163             : {
     164           6 :   return mQuirkSheet;
     165             : }
     166             : 
     167             : StyleSheet*
     168          22 : nsLayoutStylesheetCache::SVGSheet()
     169             : {
     170          22 :   return mSVGSheet;
     171             : }
     172             : 
     173             : StyleSheet*
     174           0 : nsLayoutStylesheetCache::MathMLSheet()
     175             : {
     176           0 :   if (!mMathMLSheet) {
     177           0 :     LoadSheetURL("resource://gre-resources/mathml.css",
     178           0 :                  &mMathMLSheet, eAgentSheetFeatures, eCrash);
     179             :   }
     180             : 
     181           0 :   return mMathMLSheet;
     182             : }
     183             : 
     184             : StyleSheet*
     185           9 : nsLayoutStylesheetCache::CounterStylesSheet()
     186             : {
     187           9 :   return mCounterStylesSheet;
     188             : }
     189             : 
     190             : StyleSheet*
     191           7 : nsLayoutStylesheetCache::NoScriptSheet()
     192             : {
     193           7 :   if (!mNoScriptSheet) {
     194           2 :     LoadSheetURL("resource://gre-resources/noscript.css",
     195           2 :                  &mNoScriptSheet, eAgentSheetFeatures, eCrash);
     196             :   }
     197             : 
     198           7 :   return mNoScriptSheet;
     199             : }
     200             : 
     201             : StyleSheet*
     202           0 : nsLayoutStylesheetCache::NoFramesSheet()
     203             : {
     204           0 :   if (!mNoFramesSheet) {
     205           0 :     LoadSheetURL("resource://gre-resources/noframes.css",
     206           0 :                  &mNoFramesSheet, eAgentSheetFeatures, eCrash);
     207             :   }
     208             : 
     209           0 :   return mNoFramesSheet;
     210             : }
     211             : 
     212             : StyleSheet*
     213           0 : nsLayoutStylesheetCache::ChromePreferenceSheet(nsPresContext* aPresContext)
     214             : {
     215           0 :   if (!mChromePreferenceSheet) {
     216           0 :     BuildPreferenceSheet(&mChromePreferenceSheet, aPresContext);
     217             :   }
     218             : 
     219           0 :   return mChromePreferenceSheet;
     220             : }
     221             : 
     222             : StyleSheet*
     223           3 : nsLayoutStylesheetCache::ContentPreferenceSheet(nsPresContext* aPresContext)
     224             : {
     225           3 :   if (!mContentPreferenceSheet) {
     226           2 :     BuildPreferenceSheet(&mContentPreferenceSheet, aPresContext);
     227             :   }
     228             : 
     229           3 :   return mContentPreferenceSheet;
     230             : }
     231             : 
     232             : StyleSheet*
     233           0 : nsLayoutStylesheetCache::ContentEditableSheet()
     234             : {
     235           0 :   if (!mContentEditableSheet) {
     236           0 :     LoadSheetURL("resource://gre/res/contenteditable.css",
     237           0 :                  &mContentEditableSheet, eAgentSheetFeatures, eCrash);
     238             :   }
     239             : 
     240           0 :   return mContentEditableSheet;
     241             : }
     242             : 
     243             : StyleSheet*
     244           0 : nsLayoutStylesheetCache::DesignModeSheet()
     245             : {
     246           0 :   if (!mDesignModeSheet) {
     247           0 :     LoadSheetURL("resource://gre/res/designmode.css",
     248           0 :                  &mDesignModeSheet, eAgentSheetFeatures, eCrash);
     249             :   }
     250             : 
     251           0 :   return mDesignModeSheet;
     252             : }
     253             : 
     254             : void
     255           0 : nsLayoutStylesheetCache::Shutdown()
     256             : {
     257           0 :   gCSSLoader_Gecko = nullptr;
     258           0 :   gCSSLoader_Servo = nullptr;
     259           0 :   NS_WARNING_ASSERTION(!gStyleCache_Gecko || !gUserContentSheetURL_Gecko,
     260             :                        "Got the URL but never used by Gecko?");
     261           0 :   NS_WARNING_ASSERTION(!gStyleCache_Servo || !gUserContentSheetURL_Servo,
     262             :                        "Got the URL but never used by Servo?");
     263           0 :   gStyleCache_Gecko = nullptr;
     264           0 :   gStyleCache_Servo = nullptr;
     265           0 :   gUserContentSheetURL_Gecko = nullptr;
     266           0 :   gUserContentSheetURL_Servo = nullptr;
     267           0 : }
     268             : 
     269             : void
     270           2 : nsLayoutStylesheetCache::SetUserContentCSSURL(nsIURI* aURI)
     271             : {
     272           2 :   MOZ_ASSERT(XRE_IsContentProcess(), "Only used in content processes.");
     273           2 :   gUserContentSheetURL_Gecko = aURI;
     274           2 :   gUserContentSheetURL_Servo = aURI;
     275           2 : }
     276             : 
     277           0 : MOZ_DEFINE_MALLOC_SIZE_OF(LayoutStylesheetCacheMallocSizeOf)
     278             : 
     279             : NS_IMETHODIMP
     280           0 : nsLayoutStylesheetCache::CollectReports(nsIHandleReportCallback* aHandleReport,
     281             :                                         nsISupports* aData, bool aAnonymize)
     282             : {
     283           0 :   MOZ_COLLECT_REPORT(
     284             :     "explicit/layout/style-sheet-cache", KIND_HEAP, UNITS_BYTES,
     285             :     SizeOfIncludingThis(LayoutStylesheetCacheMallocSizeOf),
     286           0 :     "Memory used for some built-in style sheets.");
     287             : 
     288           0 :   return NS_OK;
     289             : }
     290             : 
     291             : 
     292             : size_t
     293           0 : nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     294             : {
     295           0 :   size_t n = aMallocSizeOf(this);
     296             : 
     297             :   #define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0;
     298             : 
     299           0 :   MEASURE(mChromePreferenceSheet);
     300           0 :   MEASURE(mContentEditableSheet);
     301           0 :   MEASURE(mContentPreferenceSheet);
     302           0 :   MEASURE(mCounterStylesSheet);
     303           0 :   MEASURE(mDesignModeSheet);
     304           0 :   MEASURE(mFormsSheet);
     305           0 :   MEASURE(mHTMLSheet);
     306           0 :   MEASURE(mMathMLSheet);
     307           0 :   MEASURE(mMinimalXULSheet);
     308           0 :   MEASURE(mNoFramesSheet);
     309           0 :   MEASURE(mNoScriptSheet);
     310           0 :   MEASURE(mNumberControlSheet);
     311           0 :   MEASURE(mQuirkSheet);
     312           0 :   MEASURE(mSVGSheet);
     313           0 :   MEASURE(mScrollbarsSheet);
     314           0 :   MEASURE(mUASheet);
     315           0 :   MEASURE(mUserChromeSheet);
     316           0 :   MEASURE(mUserContentSheet);
     317           0 :   MEASURE(mXULSheet);
     318             : 
     319             :   // Measurement of the following members may be added later if DMD finds it is
     320             :   // worthwhile:
     321             :   // - gCSSLoader_Gecko
     322             :   // - gCSSLoader_Servo
     323             : 
     324           0 :   return n;
     325             : }
     326             : 
     327           2 : nsLayoutStylesheetCache::nsLayoutStylesheetCache(StyleBackendType aType)
     328           2 :   : mBackendType(aType)
     329             : {
     330             :   nsCOMPtr<nsIObserverService> obsSvc =
     331           4 :     mozilla::services::GetObserverService();
     332           2 :   NS_ASSERTION(obsSvc, "No global observer service?");
     333             : 
     334           2 :   if (obsSvc) {
     335           2 :     obsSvc->AddObserver(this, "profile-before-change", false);
     336           2 :     obsSvc->AddObserver(this, "profile-do-change", false);
     337           2 :     obsSvc->AddObserver(this, "chrome-flush-skin-caches", false);
     338           2 :     obsSvc->AddObserver(this, "chrome-flush-caches", false);
     339             :   }
     340             : 
     341           2 :   InitFromProfile();
     342             : 
     343             :   // And make sure that we load our UA sheets.  No need to do this
     344             :   // per-profile, since they're profile-invariant.
     345           2 :   LoadSheetURL("resource://gre-resources/counterstyles.css",
     346           2 :                &mCounterStylesSheet, eAgentSheetFeatures, eCrash);
     347           2 :   LoadSheetURL("resource://gre-resources/html.css",
     348           2 :                &mHTMLSheet, eAgentSheetFeatures, eCrash);
     349           2 :   LoadSheetURL("chrome://global/content/minimal-xul.css",
     350           2 :                &mMinimalXULSheet, eAgentSheetFeatures, eCrash);
     351           2 :   LoadSheetURL("resource://gre-resources/quirk.css",
     352           2 :                &mQuirkSheet, eAgentSheetFeatures, eCrash);
     353           2 :   LoadSheetURL("resource://gre/res/svg.css",
     354           2 :                &mSVGSheet, eAgentSheetFeatures, eCrash);
     355           2 :   if (XRE_IsParentProcess()) {
     356             :     // We know we need xul.css for the UI, so load that now too:
     357           1 :     XULSheet();
     358             :   }
     359             : 
     360             :   auto& userContentSheetURL = aType == StyleBackendType::Gecko ?
     361             :                               gUserContentSheetURL_Gecko :
     362           2 :                               gUserContentSheetURL_Servo;
     363           2 :   if (userContentSheetURL) {
     364           0 :     MOZ_ASSERT(XRE_IsContentProcess(), "Only used in content processes.");
     365           0 :     LoadSheet(userContentSheetURL, &mUserContentSheet, eUserSheetFeatures, eLogToConsole);
     366           0 :     userContentSheetURL = nullptr;
     367             :   }
     368             : 
     369             :   // The remaining sheets are created on-demand do to their use being rarer
     370             :   // (which helps save memory for Firefox OS apps) or because they need to
     371             :   // be re-loadable in DependentPrefChanged.
     372           2 : }
     373             : 
     374           0 : nsLayoutStylesheetCache::~nsLayoutStylesheetCache()
     375             : {
     376           0 :   mozilla::UnregisterWeakMemoryReporter(this);
     377           0 : }
     378             : 
     379             : void
     380           2 : nsLayoutStylesheetCache::InitMemoryReporter()
     381             : {
     382           2 :   mozilla::RegisterWeakMemoryReporter(this);
     383           2 : }
     384             : 
     385             : /* static */ nsLayoutStylesheetCache*
     386          42 : nsLayoutStylesheetCache::For(StyleBackendType aType)
     387             : {
     388          42 :   MOZ_ASSERT(NS_IsMainThread());
     389             : 
     390          42 :   bool mustInit = !gStyleCache_Gecko && !gStyleCache_Servo;
     391             :   auto& cache = aType == StyleBackendType::Gecko ? gStyleCache_Gecko :
     392          42 :                                                    gStyleCache_Servo;
     393             : 
     394          42 :   if (!cache) {
     395           2 :     cache = new nsLayoutStylesheetCache(aType);
     396           2 :     cache->InitMemoryReporter();
     397             :   }
     398             : 
     399          42 :   if (mustInit) {
     400             :     // Initialization that only needs to be done once for both
     401             :     // nsLayoutStylesheetCaches.
     402             : 
     403             :     Preferences::AddBoolVarCache(&sNumberControlEnabled, NUMBER_CONTROL_PREF,
     404           2 :                                  true);
     405             : 
     406             :     // For each pref that controls a CSS feature that a UA style sheet depends
     407             :     // on (such as a pref that enables a property that a UA style sheet uses),
     408             :     // register DependentPrefChanged as a callback to ensure that the relevant
     409             :     // style sheets will be re-parsed.
     410             :     // Preferences::RegisterCallback(&DependentPrefChanged,
     411             :     //                               "layout.css.example-pref.enabled");
     412             :     Preferences::RegisterCallback(&DependentPrefChanged,
     413           2 :                                   "layout.css.grid.enabled");
     414             :   }
     415             : 
     416          42 :   return cache;
     417             : }
     418             : 
     419             : void
     420           2 : nsLayoutStylesheetCache::InitFromProfile()
     421             : {
     422           3 :   nsCOMPtr<nsIXULRuntime> appInfo = do_GetService("@mozilla.org/xre/app-info;1");
     423           2 :   if (appInfo) {
     424           2 :     bool inSafeMode = false;
     425           2 :     appInfo->GetInSafeMode(&inSafeMode);
     426           2 :     if (inSafeMode)
     427           0 :       return;
     428             :   }
     429           3 :   nsCOMPtr<nsIFile> contentFile;
     430           3 :   nsCOMPtr<nsIFile> chromeFile;
     431             : 
     432           2 :   NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR,
     433           4 :                          getter_AddRefs(contentFile));
     434           2 :   if (!contentFile) {
     435             :     // if we don't have a profile yet, that's OK!
     436           1 :     return;
     437             :   }
     438             : 
     439           1 :   contentFile->Clone(getter_AddRefs(chromeFile));
     440           1 :   if (!chromeFile) return;
     441             : 
     442           1 :   contentFile->Append(NS_LITERAL_STRING("userContent.css"));
     443           1 :   chromeFile->Append(NS_LITERAL_STRING("userChrome.css"));
     444             : 
     445           1 :   LoadSheetFile(contentFile, &mUserContentSheet, eUserSheetFeatures, eLogToConsole);
     446           1 :   LoadSheetFile(chromeFile, &mUserChromeSheet, eUserSheetFeatures, eLogToConsole);
     447             : }
     448             : 
     449             : void
     450          21 : nsLayoutStylesheetCache::LoadSheetURL(const char* aURL,
     451             :                                       RefPtr<StyleSheet>* aSheet,
     452             :                                       SheetParsingMode aParsingMode,
     453             :                                       FailureAction aFailureAction)
     454             : {
     455          42 :   nsCOMPtr<nsIURI> uri;
     456          21 :   NS_NewURI(getter_AddRefs(uri), aURL);
     457          21 :   LoadSheet(uri, aSheet, aParsingMode, aFailureAction);
     458          21 :   if (!aSheet) {
     459           0 :     NS_ERROR(nsPrintfCString("Could not load %s", aURL).get());
     460             :   }
     461          21 : }
     462             : 
     463             : void
     464           2 : nsLayoutStylesheetCache::LoadSheetFile(nsIFile* aFile,
     465             :                                        RefPtr<StyleSheet>* aSheet,
     466             :                                        SheetParsingMode aParsingMode,
     467             :                                        FailureAction aFailureAction)
     468             : {
     469           2 :   bool exists = false;
     470           2 :   aFile->Exists(&exists);
     471             : 
     472           2 :   if (!exists) return;
     473             : 
     474           0 :   nsCOMPtr<nsIURI> uri;
     475           0 :   NS_NewFileURI(getter_AddRefs(uri), aFile);
     476             : 
     477           0 :   LoadSheet(uri, aSheet, aParsingMode, aFailureAction);
     478             : }
     479             : 
     480             : #ifdef MOZ_CRASHREPORTER
     481             : static inline nsresult
     482           0 : ComputeCRC32(nsIFile* aFile, uint32_t* aResult)
     483             : {
     484             :   PRFileDesc* fd;
     485           0 :   nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
     486           0 :   NS_ENSURE_SUCCESS(rv, rv);
     487             : 
     488           0 :   uint32_t crc = crc32(0, nullptr, 0);
     489             : 
     490             :   unsigned char buf[512];
     491             :   int32_t n;
     492           0 :   while ((n = PR_Read(fd, buf, sizeof(buf))) > 0) {
     493           0 :     crc = crc32(crc, buf, n);
     494             :   }
     495           0 :   PR_Close(fd);
     496             : 
     497           0 :   if (n < 0) {
     498           0 :     return NS_ERROR_FAILURE;
     499             :   }
     500             : 
     501           0 :   *aResult = crc;
     502           0 :   return NS_OK;
     503             : }
     504             : 
     505             : static void
     506           0 : ListInterestingFiles(nsString& aAnnotation, nsIFile* aFile,
     507             :                      const nsTArray<nsString>& aInterestingFilenames)
     508             : {
     509           0 :   nsString filename;
     510           0 :   aFile->GetLeafName(filename);
     511           0 :   for (const nsString& interestingFilename : aInterestingFilenames) {
     512           0 :     if (interestingFilename == filename) {
     513           0 :       nsString path;
     514           0 :       aFile->GetPath(path);
     515           0 :       aAnnotation.AppendLiteral("  ");
     516           0 :       aAnnotation.Append(path);
     517           0 :       aAnnotation.AppendLiteral(" (");
     518             :       int64_t size;
     519           0 :       if (NS_SUCCEEDED(aFile->GetFileSize(&size))) {
     520           0 :         aAnnotation.AppendPrintf("%" PRId64, size);
     521             :       } else {
     522           0 :         aAnnotation.AppendLiteral("???");
     523             :       }
     524           0 :       aAnnotation.AppendLiteral(" bytes, crc32 = ");
     525             :       uint32_t crc;
     526           0 :       nsresult rv = ComputeCRC32(aFile, &crc);
     527           0 :       if (NS_SUCCEEDED(rv)) {
     528           0 :         aAnnotation.AppendPrintf("0x%08x)\n", crc);
     529             :       } else {
     530           0 :         aAnnotation.AppendPrintf("error 0x%08x)\n", uint32_t(rv));
     531             :       }
     532           0 :       return;
     533             :     }
     534             :   }
     535             : 
     536           0 :   bool isDir = false;
     537           0 :   aFile->IsDirectory(&isDir);
     538             : 
     539           0 :   if (!isDir) {
     540           0 :     return;
     541             :   }
     542             : 
     543           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
     544           0 :   if (NS_FAILED(aFile->GetDirectoryEntries(getter_AddRefs(entries)))) {
     545           0 :     aAnnotation.AppendLiteral("  (failed to enumerated directory)\n");
     546           0 :     return;
     547             :   }
     548             : 
     549             :   for (;;) {
     550           0 :     bool hasMore = false;
     551           0 :     if (NS_FAILED(entries->HasMoreElements(&hasMore))) {
     552           0 :       aAnnotation.AppendLiteral("  (failed during directory enumeration)\n");
     553           0 :       return;
     554             :     }
     555           0 :     if (!hasMore) {
     556           0 :       break;
     557             :     }
     558             : 
     559           0 :     nsCOMPtr<nsISupports> entry;
     560           0 :     if (NS_FAILED(entries->GetNext(getter_AddRefs(entry)))) {
     561           0 :       aAnnotation.AppendLiteral("  (failed during directory enumeration)\n");
     562           0 :       return;
     563             :     }
     564             : 
     565           0 :     nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
     566           0 :     if (file) {
     567           0 :       ListInterestingFiles(aAnnotation, file, aInterestingFilenames);
     568             :     }
     569           0 :   }
     570             : }
     571             : 
     572             : // Generate a crash report annotation to help debug issues with style
     573             : // sheets failing to load (bug 1194856).
     574             : static void
     575           0 : AnnotateCrashReport(nsIURI* aURI)
     576             : {
     577           0 :   nsAutoCString spec;
     578           0 :   nsAutoCString scheme;
     579           0 :   nsDependentCSubstring filename;
     580           0 :   if (aURI) {
     581           0 :     spec = aURI->GetSpecOrDefault();
     582           0 :     aURI->GetScheme(scheme);
     583           0 :     int32_t i = spec.RFindChar('/');
     584           0 :     if (i != -1) {
     585           0 :       filename.Rebind(spec, i + 1);
     586             :     }
     587             :   }
     588             : 
     589           0 :   nsString annotation;
     590             : 
     591             :   // The URL of the sheet that failed to load.
     592           0 :   annotation.AppendLiteral("Error loading sheet: ");
     593           0 :   annotation.Append(NS_ConvertUTF8toUTF16(spec).get());
     594           0 :   annotation.Append('\n');
     595             : 
     596           0 :   annotation.AppendLiteral("NS_ERROR_FILE_CORRUPTION reason: ");
     597           0 :   if (nsZipArchive::sFileCorruptedReason) {
     598           0 :     annotation.Append(NS_ConvertUTF8toUTF16(nsZipArchive::sFileCorruptedReason).get());
     599           0 :     annotation.Append('\n');
     600             :   } else {
     601           0 :     annotation.AppendLiteral("(none)\n");
     602             :   }
     603             : 
     604             :   // The jar: or file: URL that the sheet's resource: or chrome: URL
     605             :   // resolves to.
     606           0 :   if (scheme.EqualsLiteral("resource")) {
     607           0 :     annotation.AppendLiteral("Real location: ");
     608           0 :     nsCOMPtr<nsISubstitutingProtocolHandler> handler;
     609           0 :     nsCOMPtr<nsIIOService> io(do_GetIOService());
     610           0 :     if (io) {
     611           0 :       nsCOMPtr<nsIProtocolHandler> ph;
     612           0 :       io->GetProtocolHandler(scheme.get(), getter_AddRefs(ph));
     613           0 :       if (ph) {
     614           0 :         handler = do_QueryInterface(ph);
     615             :       }
     616             :     }
     617           0 :     if (!handler) {
     618           0 :       annotation.AppendLiteral("(ResolveURI failed)\n");
     619             :     } else {
     620           0 :       nsAutoCString resolvedSpec;
     621           0 :       nsresult rv = handler->ResolveURI(aURI, resolvedSpec);
     622           0 :       if (NS_FAILED(rv)) {
     623             :         annotation.AppendPrintf("(ResolveURI failed with 0x%08" PRIx32 ")\n",
     624           0 :                                 static_cast<uint32_t>(rv));
     625             :       }
     626           0 :       annotation.Append(NS_ConvertUTF8toUTF16(resolvedSpec));
     627           0 :       annotation.Append('\n');
     628             :     }
     629           0 :   } else if (scheme.EqualsLiteral("chrome")) {
     630           0 :     annotation.AppendLiteral("Real location: ");
     631             :     nsCOMPtr<nsIChromeRegistry> reg =
     632           0 :       mozilla::services::GetChromeRegistryService();
     633           0 :     if (!reg) {
     634           0 :       annotation.AppendLiteral("(no chrome registry)\n");
     635             :     } else {
     636           0 :       nsCOMPtr<nsIURI> resolvedURI;
     637           0 :       reg->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI));
     638           0 :       if (!resolvedURI) {
     639           0 :         annotation.AppendLiteral("(ConvertChromeURL failed)\n");
     640             :       } else {
     641             :         annotation.Append(
     642           0 :           NS_ConvertUTF8toUTF16(resolvedURI->GetSpecOrDefault()));
     643           0 :         annotation.Append('\n');
     644             :       }
     645             :     }
     646             :   }
     647             : 
     648           0 :   nsTArray<nsString> interestingFiles;
     649           0 :   interestingFiles.AppendElement(NS_LITERAL_STRING("chrome.manifest"));
     650           0 :   interestingFiles.AppendElement(NS_LITERAL_STRING("omni.ja"));
     651           0 :   interestingFiles.AppendElement(NS_ConvertUTF8toUTF16(filename));
     652             : 
     653           0 :   annotation.AppendLiteral("GRE directory: ");
     654           0 :   nsCOMPtr<nsIFile> file;
     655           0 :   nsDirectoryService::gService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile),
     656           0 :                                     getter_AddRefs(file));
     657           0 :   if (file) {
     658             :     // The Firefox installation directory.
     659           0 :     nsString path;
     660           0 :     file->GetPath(path);
     661           0 :     annotation.Append(path);
     662           0 :     annotation.Append('\n');
     663             : 
     664             :     // List interesting files -- any chrome.manifest or omni.ja file or any file
     665             :     // whose name is the sheet's filename -- under the Firefox installation
     666             :     // directory.
     667           0 :     annotation.AppendLiteral("Interesting files in the GRE directory:\n");
     668           0 :     ListInterestingFiles(annotation, file, interestingFiles);
     669             : 
     670             :     // If the Firefox installation directory has a chrome.manifest file, let's
     671             :     // see what's in it.
     672           0 :     file->Append(NS_LITERAL_STRING("chrome.manifest"));
     673           0 :     bool exists = false;
     674           0 :     file->Exists(&exists);
     675           0 :     if (exists) {
     676           0 :       annotation.AppendLiteral("Contents of chrome.manifest:\n[[[\n");
     677             :       PRFileDesc* fd;
     678           0 :       if (NS_SUCCEEDED(file->OpenNSPRFileDesc(PR_RDONLY, 0, &fd))) {
     679           0 :         nsCString contents;
     680             :         char buf[512];
     681             :         int32_t n;
     682           0 :         while ((n = PR_Read(fd, buf, sizeof(buf))) > 0) {
     683           0 :           contents.Append(buf, n);
     684             :         }
     685           0 :         if (n < 0) {
     686           0 :           annotation.AppendLiteral("  (error while reading)\n");
     687             :         } else {
     688           0 :           annotation.Append(NS_ConvertUTF8toUTF16(contents));
     689             :         }
     690           0 :         PR_Close(fd);
     691             :       }
     692           0 :       annotation.AppendLiteral("]]]\n");
     693             :     }
     694             :   } else {
     695           0 :     annotation.AppendLiteral("(none)\n");
     696             :   }
     697             : 
     698             :   // The jar: or file: URL prefix that chrome: and resource: URLs get translated
     699             :   // to.
     700           0 :   annotation.AppendLiteral("GRE omnijar URI string: ");
     701           0 :   nsCString uri;
     702           0 :   nsresult rv = Omnijar::GetURIString(Omnijar::GRE, uri);
     703           0 :   if (NS_FAILED(rv)) {
     704           0 :     annotation.AppendLiteral("(failed)\n");
     705             :   } else {
     706           0 :     annotation.Append(NS_ConvertUTF8toUTF16(uri));
     707           0 :     annotation.Append('\n');
     708             :   }
     709             : 
     710           0 :   RefPtr<nsZipArchive> zip = Omnijar::GetReader(Omnijar::GRE);
     711           0 :   if (zip) {
     712             :     // List interesting files in the GRE omnijar.
     713           0 :     annotation.AppendLiteral("Interesting files in the GRE omnijar:\n");
     714             :     nsZipFind* find;
     715           0 :     rv = zip->FindInit(nullptr, &find);
     716           0 :     if (NS_FAILED(rv)) {
     717             :       annotation.AppendPrintf("  (FindInit failed with 0x%08" PRIx32 ")\n",
     718           0 :                               static_cast<uint32_t>(rv));
     719           0 :     } else if (!find) {
     720           0 :       annotation.AppendLiteral("  (FindInit returned null)\n");
     721             :     } else {
     722             :       const char* result;
     723             :       uint16_t len;
     724           0 :       while (NS_SUCCEEDED(find->FindNext(&result, &len))) {
     725           0 :         nsCString itemPathname;
     726           0 :         nsString itemFilename;
     727           0 :         itemPathname.Append(result, len);
     728           0 :         int32_t i = itemPathname.RFindChar('/');
     729           0 :         if (i != -1) {
     730           0 :           itemFilename = NS_ConvertUTF8toUTF16(Substring(itemPathname, i + 1));
     731             :         }
     732           0 :         for (const nsString& interestingFile : interestingFiles) {
     733           0 :           if (interestingFile == itemFilename) {
     734           0 :             annotation.AppendLiteral("  ");
     735           0 :             annotation.Append(NS_ConvertUTF8toUTF16(itemPathname));
     736           0 :             nsZipItem* item = zip->GetItem(itemPathname.get());
     737           0 :             if (!item) {
     738           0 :               annotation.AppendLiteral(" (GetItem failed)\n");
     739             :             } else {
     740           0 :               annotation.AppendPrintf(" (%d bytes, crc32 = 0x%08x)\n",
     741             :                                       item->RealSize(),
     742           0 :                                       item->CRC32());
     743             :             }
     744           0 :             break;
     745             :           }
     746             :         }
     747             :       }
     748           0 :       delete find;
     749             :     }
     750             :   } else {
     751           0 :     annotation.AppendLiteral("No GRE omnijar\n");
     752             :   }
     753             : 
     754           0 :   CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("SheetLoadFailure"),
     755           0 :                                      NS_ConvertUTF16toUTF8(annotation));
     756           0 : }
     757             : #endif
     758             : 
     759             : static void
     760           0 : ErrorLoadingSheet(nsIURI* aURI, const char* aMsg, FailureAction aFailureAction)
     761             : {
     762             :   nsPrintfCString errorMessage("%s loading built-in stylesheet '%s'",
     763             :                                aMsg,
     764           0 :                                aURI ? aURI->GetSpecOrDefault().get() : "");
     765           0 :   if (aFailureAction == eLogToConsole) {
     766           0 :     nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
     767           0 :     if (cs) {
     768           0 :       cs->LogStringMessage(NS_ConvertUTF8toUTF16(errorMessage).get());
     769           0 :       return;
     770             :     }
     771             :   }
     772             : 
     773             : #ifdef MOZ_CRASHREPORTER
     774           0 :   AnnotateCrashReport(aURI);
     775             : #endif
     776           0 :   NS_RUNTIMEABORT(errorMessage.get());
     777             : }
     778             : 
     779             : void
     780          21 : nsLayoutStylesheetCache::LoadSheet(nsIURI* aURI,
     781             :                                    RefPtr<StyleSheet>* aSheet,
     782             :                                    SheetParsingMode aParsingMode,
     783             :                                    FailureAction aFailureAction)
     784             : {
     785          21 :   if (!aURI) {
     786           0 :     ErrorLoadingSheet(aURI, "null URI", eCrash);
     787           0 :     return;
     788             :   }
     789             : 
     790          21 :   auto& loader = mBackendType == StyleBackendType::Gecko ?
     791             :     gCSSLoader_Gecko :
     792          21 :     gCSSLoader_Servo;
     793             : 
     794          21 :   if (!loader) {
     795           2 :     loader = new Loader(mBackendType, nullptr);
     796           2 :     if (!loader) {
     797           0 :       ErrorLoadingSheet(aURI, "no Loader", eCrash);
     798           0 :       return;
     799             :     }
     800             :   }
     801             : 
     802             : #ifdef MOZ_CRASHREPORTER
     803          21 :   nsZipArchive::sFileCorruptedReason = nullptr;
     804             : #endif
     805          21 :   nsresult rv = loader->LoadSheetSync(aURI, aParsingMode, true, aSheet);
     806          21 :   if (NS_FAILED(rv)) {
     807           0 :     ErrorLoadingSheet(aURI,
     808           0 :       nsPrintfCString("LoadSheetSync failed with error %" PRIx32, static_cast<uint32_t>(rv)).get(),
     809           0 :       aFailureAction);
     810             :   }
     811             : }
     812             : 
     813             : /* static */ void
     814           0 : nsLayoutStylesheetCache::InvalidateSheet(RefPtr<StyleSheet>* aGeckoSheet,
     815             :                                          RefPtr<StyleSheet>* aServoSheet)
     816             : {
     817           0 :   MOZ_ASSERT(gCSSLoader_Gecko || gCSSLoader_Servo,
     818             :              "pref changed before we loaded a sheet?");
     819             : 
     820           0 :   const bool gotGeckoSheet = aGeckoSheet && *aGeckoSheet;
     821           0 :   const bool gotServoSheet = aServoSheet && *aServoSheet;
     822             : 
     823             :   // Make sure sheets have the expected types
     824           0 :   MOZ_ASSERT(!gotGeckoSheet || (*aGeckoSheet)->IsGecko());
     825           0 :   MOZ_ASSERT(!gotServoSheet || (*aServoSheet)->IsServo());
     826             :   // Make sure the URIs match
     827           0 :   MOZ_ASSERT(!gotServoSheet || !gotGeckoSheet ||
     828             :              (*aGeckoSheet)->GetSheetURI() == (*aServoSheet)->GetSheetURI(),
     829             :              "Sheets passed should have the same URI");
     830             : 
     831             :   nsIURI* uri;
     832           0 :   if (gotGeckoSheet) {
     833           0 :     uri = (*aGeckoSheet)->GetSheetURI();
     834           0 :   } else if (gotServoSheet) {
     835           0 :     uri = (*aServoSheet)->GetSheetURI();
     836             :   } else {
     837           0 :     return;
     838             :   }
     839             : 
     840           0 :   if (gCSSLoader_Gecko) {
     841           0 :     gCSSLoader_Gecko->ObsoleteSheet(uri);
     842             :   }
     843           0 :   if (gCSSLoader_Servo) {
     844           0 :     gCSSLoader_Servo->ObsoleteSheet(uri);
     845             :   }
     846           0 :   if (gotGeckoSheet) {
     847           0 :     *aGeckoSheet = nullptr;
     848             :   }
     849           0 :   if (gotServoSheet) {
     850           0 :     *aServoSheet = nullptr;
     851             :   }
     852             : }
     853             : 
     854             : /* static */ void
     855           0 : nsLayoutStylesheetCache::DependentPrefChanged(const char* aPref, void* aData)
     856             : {
     857           0 :   MOZ_ASSERT(gStyleCache_Gecko || gStyleCache_Servo,
     858             :              "pref changed after shutdown?");
     859             : 
     860             :   // Cause any UA style sheets whose parsing depends on the value of prefs
     861             :   // to be re-parsed by dropping the sheet from gCSSLoader_{Gecko,Servo}'s cache
     862             :   // then setting our cached sheet pointer to null.  This will only work for
     863             :   // sheets that are loaded lazily.
     864             : 
     865             : #define INVALIDATE(sheet_) \
     866             :   InvalidateSheet(gStyleCache_Gecko ? &gStyleCache_Gecko->sheet_ : nullptr, \
     867             :                   gStyleCache_Servo ? &gStyleCache_Servo->sheet_ : nullptr);
     868             : 
     869           0 :   INVALIDATE(mUASheet);  // for layout.css.grid.enabled
     870             : 
     871             : #undef INVALIDATE
     872           0 : }
     873             : 
     874             : /* static */ void
     875           0 : nsLayoutStylesheetCache::InvalidatePreferenceSheets()
     876             : {
     877           0 :   if (gStyleCache_Gecko) {
     878           0 :     gStyleCache_Gecko->mContentPreferenceSheet = nullptr;
     879           0 :     gStyleCache_Gecko->mChromePreferenceSheet = nullptr;
     880             :   }
     881           0 :   if (gStyleCache_Servo) {
     882           0 :     gStyleCache_Servo->mContentPreferenceSheet = nullptr;
     883           0 :     gStyleCache_Servo->mChromePreferenceSheet = nullptr;
     884             :   }
     885           0 : }
     886             : 
     887             : void
     888           2 : nsLayoutStylesheetCache::BuildPreferenceSheet(RefPtr<StyleSheet>* aSheet,
     889             :                                               nsPresContext* aPresContext)
     890             : {
     891           2 :   if (mBackendType == StyleBackendType::Gecko) {
     892             :     *aSheet = new CSSStyleSheet(eAgentSheetFeatures, CORS_NONE,
     893           2 :                                 mozilla::net::RP_Unset);
     894             :   } else {
     895             :     *aSheet = new ServoStyleSheet(eAgentSheetFeatures, CORS_NONE,
     896           0 :                                   mozilla::net::RP_Unset, dom::SRIMetadata());
     897             :   }
     898             : 
     899           2 :   StyleSheet* sheet = *aSheet;
     900             : 
     901           4 :   nsCOMPtr<nsIURI> uri;
     902           2 :   NS_NewURI(getter_AddRefs(uri), "about:PreferenceStyleSheet", nullptr);
     903           2 :   MOZ_ASSERT(uri, "URI creation shouldn't fail");
     904             : 
     905           2 :   sheet->SetURIs(uri, uri, uri);
     906           2 :   sheet->SetComplete();
     907             : 
     908             :   static const uint32_t kPreallocSize = 1024;
     909             : 
     910           4 :   nsString sheetText;
     911           2 :   sheetText.SetCapacity(kPreallocSize);
     912             : 
     913             : #define NS_GET_R_G_B(color_) \
     914             :   NS_GET_R(color_), NS_GET_G(color_), NS_GET_B(color_)
     915             : 
     916             :   sheetText.AppendLiteral(
     917             :       "@namespace url(http://www.w3.org/1999/xhtml);\n"
     918           2 :       "@namespace svg url(http://www.w3.org/2000/svg);\n");
     919             : 
     920             :   // Rules for link styling.
     921           2 :   nscolor linkColor = aPresContext->DefaultLinkColor();
     922           2 :   nscolor activeColor = aPresContext->DefaultActiveLinkColor();
     923           2 :   nscolor visitedColor = aPresContext->DefaultVisitedLinkColor();
     924             : 
     925          12 :   sheetText.AppendPrintf(
     926             :       "*|*:link { color: #%02x%02x%02x; }\n"
     927             :       "*|*:any-link:active { color: #%02x%02x%02x; }\n"
     928             :       "*|*:visited { color: #%02x%02x%02x; }\n",
     929           4 :       NS_GET_R_G_B(linkColor),
     930           4 :       NS_GET_R_G_B(activeColor),
     931           6 :       NS_GET_R_G_B(visitedColor));
     932             : 
     933             :   bool underlineLinks =
     934           2 :     aPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
     935           2 :   sheetText.AppendPrintf(
     936             :       "*|*:any-link%s { text-decoration: %s; }\n",
     937             :       underlineLinks ? ":not(svg|a)" : "",
     938           2 :       underlineLinks ? "underline" : "none");
     939             : 
     940             :   // Rules for focus styling.
     941             : 
     942           2 :   bool focusRingOnAnything = aPresContext->GetFocusRingOnAnything();
     943           2 :   uint8_t focusRingWidth = aPresContext->FocusRingWidth();
     944           2 :   uint8_t focusRingStyle = aPresContext->GetFocusRingStyle();
     945             : 
     946           2 :   if ((focusRingWidth != 1 && focusRingWidth <= 4) || focusRingOnAnything) {
     947           0 :     if (focusRingWidth != 1) {
     948             :       // If the focus ring width is different from the default, fix buttons
     949             :       // with rings.
     950           0 :       sheetText.AppendPrintf(
     951             :           "button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner, "
     952             :           "input[type=\"button\"]::-moz-focus-inner, "
     953             :           "input[type=\"submit\"]::-moz-focus-inner { "
     954             :           "border: %dpx %s transparent !important; }\n",
     955             :           focusRingWidth,
     956           0 :           focusRingStyle == 0 ? "solid" : "dotted");
     957             : 
     958             :       sheetText.AppendLiteral(
     959             :           "button:focus::-moz-focus-inner, "
     960             :           "input[type=\"reset\"]:focus::-moz-focus-inner, "
     961             :           "input[type=\"button\"]:focus::-moz-focus-inner, "
     962             :           "input[type=\"submit\"]:focus::-moz-focus-inner { "
     963           0 :           "border-color: ButtonText !important; }\n");
     964             :     }
     965             : 
     966           0 :     sheetText.AppendPrintf(
     967             :         "%s { outline: %dpx %s !important; %s}\n",
     968             :         focusRingOnAnything ?
     969             :           ":focus" :
     970             :           "*|*:link:focus, *|*:visited:focus",
     971             :         focusRingWidth,
     972             :         focusRingStyle == 0 ? // solid
     973             :           "solid -moz-mac-focusring" : "dotted WindowText",
     974             :         focusRingStyle == 0 ? // solid
     975           0 :           "-moz-outline-radius: 3px; outline-offset: 1px; " : "");
     976             :   }
     977             : 
     978           2 :   if (aPresContext->GetUseFocusColors()) {
     979           0 :     nscolor focusText = aPresContext->FocusTextColor();
     980           0 :     nscolor focusBG = aPresContext->FocusBackgroundColor();
     981           0 :     sheetText.AppendPrintf(
     982             :         "*:focus, *:focus > font { color: #%02x%02x%02x !important; "
     983             :         "background-color: #%02x%02x%02x !important; }\n",
     984           0 :         NS_GET_R_G_B(focusText),
     985           0 :         NS_GET_R_G_B(focusBG));
     986             :   }
     987             : 
     988           2 :   NS_ASSERTION(sheetText.Length() <= kPreallocSize,
     989             :                "kPreallocSize should be big enough to build preference style "
     990             :                "sheet without reallocation");
     991             : 
     992           2 :   if (sheet->IsGecko()) {
     993           2 :     sheet->AsGecko()->ReparseSheet(sheetText);
     994             :   } else {
     995           0 :     ServoStyleSheet* servoSheet = sheet->AsServo();
     996             :     // NB: The pref sheet never has @import rules.
     997             :     nsresult rv =
     998           0 :       servoSheet->ParseSheet(nullptr, sheetText, uri, uri, nullptr, 0,
     999           0 :                              eCompatibility_FullStandards);
    1000             :     // Parsing the about:PreferenceStyleSheet URI can only fail on OOM. If we
    1001             :     // are OOM before we parsed any documents we might as well abort.
    1002           0 :     MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
    1003             :   }
    1004             : 
    1005             : #undef NS_GET_R_G_B
    1006           2 : }
    1007             : 
    1008             : mozilla::StaticRefPtr<nsLayoutStylesheetCache>
    1009           3 : nsLayoutStylesheetCache::gStyleCache_Gecko;
    1010             : 
    1011             : mozilla::StaticRefPtr<nsLayoutStylesheetCache>
    1012           3 : nsLayoutStylesheetCache::gStyleCache_Servo;
    1013             : 
    1014             : mozilla::StaticRefPtr<mozilla::css::Loader>
    1015           3 : nsLayoutStylesheetCache::gCSSLoader_Gecko;
    1016             : 
    1017             : mozilla::StaticRefPtr<mozilla::css::Loader>
    1018           3 : nsLayoutStylesheetCache::gCSSLoader_Servo;
    1019             : 
    1020             : mozilla::StaticRefPtr<nsIURI>
    1021           3 : nsLayoutStylesheetCache::gUserContentSheetURL_Gecko;
    1022             : 
    1023             : mozilla::StaticRefPtr<nsIURI>
    1024           9 : nsLayoutStylesheetCache::gUserContentSheetURL_Servo;

Generated by: LCOV version 1.13