LCOV - code coverage report
Current view: top level - layout/base - nsStyleSheetService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 94 207 45.4 %
Date: 2017-07-14 16:53:18 Functions: 14 23 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             : /* implementation of interface for managing user and user-agent style sheets */
       8             : 
       9             : #include "nsStyleSheetService.h"
      10             : #include "mozilla/CSSStyleSheet.h"
      11             : #include "mozilla/MemoryReporting.h"
      12             : #include "mozilla/PreloadedStyleSheet.h"
      13             : #include "mozilla/StyleSheet.h"
      14             : #include "mozilla/StyleSheetInlines.h"
      15             : #include "mozilla/Unused.h"
      16             : #include "mozilla/css/Loader.h"
      17             : #include "mozilla/dom/ContentParent.h"
      18             : #include "mozilla/dom/Promise.h"
      19             : #include "mozilla/ipc/URIUtils.h"
      20             : #include "nsIURI.h"
      21             : #include "nsCOMPtr.h"
      22             : #include "nsICategoryManager.h"
      23             : #include "nsISupportsPrimitives.h"
      24             : #include "nsISimpleEnumerator.h"
      25             : #include "nsNetUtil.h"
      26             : #include "nsIConsoleService.h"
      27             : #include "nsIObserverService.h"
      28             : #include "nsLayoutStatics.h"
      29             : 
      30             : using namespace mozilla;
      31             : 
      32             : nsStyleSheetService *nsStyleSheetService::gInstance = nullptr;
      33             : 
      34           3 : nsStyleSheetService::nsStyleSheetService()
      35             : {
      36             :   static_assert(0 == AGENT_SHEET && 1 == USER_SHEET && 2 == AUTHOR_SHEET,
      37             :                 "Convention for Style Sheet");
      38           3 :   NS_ASSERTION(!gInstance, "Someone is using CreateInstance instead of GetService");
      39           3 :   gInstance = this;
      40           3 :   nsLayoutStatics::AddRef();
      41           3 : }
      42             : 
      43           0 : nsStyleSheetService::~nsStyleSheetService()
      44             : {
      45           0 :   UnregisterWeakMemoryReporter(this);
      46             : 
      47           0 :   gInstance = nullptr;
      48           0 :   nsLayoutStatics::Release();
      49           0 : }
      50             : 
      51          42 : NS_IMPL_ISUPPORTS(
      52             :   nsStyleSheetService, nsIStyleSheetService, nsIMemoryReporter)
      53             : 
      54             : void
      55           3 : nsStyleSheetService::RegisterFromEnumerator(nsICategoryManager  *aManager,
      56             :                                             const char          *aCategory,
      57             :                                             nsISimpleEnumerator *aEnumerator,
      58             :                                             uint32_t             aSheetType)
      59             : {
      60           3 :   if (!aEnumerator)
      61           0 :     return;
      62             : 
      63             :   bool hasMore;
      64           5 :   while (NS_SUCCEEDED(aEnumerator->HasMoreElements(&hasMore)) && hasMore) {
      65           2 :     nsCOMPtr<nsISupports> element;
      66           1 :     if (NS_FAILED(aEnumerator->GetNext(getter_AddRefs(element))))
      67           0 :       break;
      68             : 
      69           2 :     nsCOMPtr<nsISupportsCString> icStr = do_QueryInterface(element);
      70           1 :     NS_ASSERTION(icStr,
      71             :                  "category manager entries must be nsISupportsCStrings");
      72             : 
      73           2 :     nsAutoCString name;
      74           1 :     icStr->GetData(name);
      75             : 
      76           2 :     nsXPIDLCString spec;
      77           1 :     aManager->GetCategoryEntry(aCategory, name.get(), getter_Copies(spec));
      78             : 
      79           2 :     nsCOMPtr<nsIURI> uri;
      80           1 :     NS_NewURI(getter_AddRefs(uri), spec);
      81           1 :     if (uri)
      82           1 :       LoadAndRegisterSheetInternal(uri, aSheetType);
      83             :   }
      84             : }
      85             : 
      86             : static bool
      87           0 : SheetHasURI(StyleSheet* aSheet, nsIURI* aSheetURI)
      88             : {
      89           0 :   MOZ_ASSERT(aSheetURI);
      90             : 
      91             :   bool result;
      92           0 :   nsIURI* uri = aSheet->GetSheetURI();
      93           0 :   return uri &&
      94           0 :          NS_SUCCEEDED(uri->Equals(aSheetURI, &result)) &&
      95           0 :          result;
      96             : }
      97             : 
      98             : int32_t
      99           0 : nsStyleSheetService::FindSheetByURI(uint32_t aSheetType,
     100             :                                     nsIURI* aSheetURI)
     101             : {
     102           0 :   MOZ_ASSERT(mGeckoSheets[aSheetType].Length() ==
     103             :                mServoSheets[aSheetType].Length());
     104             : 
     105           0 :   SheetArray& sheets = mGeckoSheets[aSheetType];
     106           0 :   for (int32_t i = sheets.Length() - 1; i >= 0; i-- ) {
     107           0 :     if (SheetHasURI(sheets[i], aSheetURI)) {
     108             : #ifdef MOZ_STYLO
     109             :       MOZ_ASSERT(SheetHasURI(mServoSheets[aSheetType][i], aSheetURI));
     110             : #endif
     111           0 :       return i;
     112             :     }
     113             :   }
     114             : 
     115           0 :   return -1;
     116             : }
     117             : 
     118             : nsresult
     119           3 : nsStyleSheetService::Init()
     120             : {
     121             :   // If you make changes here, consider whether
     122             :   // SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded should be updated too.
     123             : 
     124             :   // Child processes get their style sheets from the ContentParent.
     125           3 :   if (XRE_IsContentProcess()) {
     126           2 :     return NS_OK;
     127             :   }
     128             : 
     129             :   // Enumerate all of the style sheet URIs registered in the category
     130             :   // manager and load them.
     131             : 
     132             :   nsCOMPtr<nsICategoryManager> catMan =
     133           2 :     do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
     134             : 
     135           1 :   NS_ENSURE_TRUE(catMan, NS_ERROR_OUT_OF_MEMORY);
     136             : 
     137           2 :   nsCOMPtr<nsISimpleEnumerator> sheets;
     138           1 :   catMan->EnumerateCategory("agent-style-sheets", getter_AddRefs(sheets));
     139           1 :   RegisterFromEnumerator(catMan, "agent-style-sheets", sheets, AGENT_SHEET);
     140             : 
     141           1 :   catMan->EnumerateCategory("user-style-sheets", getter_AddRefs(sheets));
     142           1 :   RegisterFromEnumerator(catMan, "user-style-sheets", sheets, USER_SHEET);
     143             : 
     144           1 :   catMan->EnumerateCategory("author-style-sheets", getter_AddRefs(sheets));
     145           1 :   RegisterFromEnumerator(catMan, "author-style-sheets", sheets, AUTHOR_SHEET);
     146             : 
     147           1 :   RegisterWeakMemoryReporter(this);
     148             : 
     149           1 :   return NS_OK;
     150             : }
     151             : 
     152             : NS_IMETHODIMP
     153           2 : nsStyleSheetService::LoadAndRegisterSheet(nsIURI *aSheetURI,
     154             :                                           uint32_t aSheetType)
     155             : {
     156             :   // Warn developers if their stylesheet URL has a #ref at the end.
     157             :   // Stylesheet URIs don't benefit from having a #ref suffix -- and if the
     158             :   // sheet is a data URI, someone might've created this #ref by accident (and
     159             :   // truncated their data-URI stylesheet) by using an unescaped # character in
     160             :   // a #RRGGBB color or #foo() ID-selector in their data-URI representation.
     161             :   bool hasRef;
     162           2 :   nsresult rv = aSheetURI->GetHasRef(&hasRef);
     163           2 :   NS_ENSURE_SUCCESS(rv, rv);
     164           2 :   if (aSheetURI && hasRef) {
     165             :     nsCOMPtr<nsIConsoleService> consoleService =
     166           0 :       do_GetService(NS_CONSOLESERVICE_CONTRACTID);
     167           0 :     NS_WARNING_ASSERTION(consoleService, "Failed to get console service!");
     168           0 :     if (consoleService) {
     169             :       const char16_t* message = u"nsStyleSheetService::LoadAndRegisterSheet: "
     170             :         u"URI contains unescaped hash character, which might be truncating "
     171           0 :         u"the sheet, if it's a data URI.";
     172           0 :       consoleService->LogStringMessage(message);
     173             :     }
     174             :   }
     175             : 
     176           2 :   rv = LoadAndRegisterSheetInternal(aSheetURI, aSheetType);
     177           2 :   if (NS_SUCCEEDED(rv)) {
     178             :     // We're guaranteed that the new sheet is the last sheet in
     179             :     // m{Gecko,Servo}Sheets[aSheetType]
     180             : 
     181           2 :     MOZ_ASSERT(mGeckoSheets[aSheetType].Length() ==
     182             :                  mServoSheets[aSheetType].Length());
     183             : 
     184           4 :     RefPtr<StyleSheet> geckoSheet = mGeckoSheets[aSheetType].LastElement();
     185           4 :     RefPtr<StyleSheet> servoSheet = mServoSheets[aSheetType].LastElement();
     186             : 
     187             :     // Hold on to a copy of the registered PresShells.
     188           4 :     nsTArray<nsCOMPtr<nsIPresShell>> toNotify(mPresShells);
     189           2 :     for (nsIPresShell* presShell : toNotify) {
     190           0 :       if (presShell->StyleSet()) {
     191           0 :         StyleSheet* sheet = presShell->StyleSet()->IsGecko() ? geckoSheet
     192           0 :                                                              : servoSheet;
     193           0 :         presShell->NotifyStyleSheetServiceSheetAdded(sheet, aSheetType);
     194             :       }
     195             :     }
     196             : 
     197           2 :     if (XRE_IsParentProcess()) {
     198           0 :       nsTArray<dom::ContentParent*> children;
     199           0 :       dom::ContentParent::GetAll(children);
     200             : 
     201           0 :       if (children.IsEmpty()) {
     202           0 :         return rv;
     203             :       }
     204             : 
     205           0 :       mozilla::ipc::URIParams uri;
     206           0 :       SerializeURI(aSheetURI, uri);
     207             : 
     208           0 :       for (uint32_t i = 0; i < children.Length(); i++) {
     209           0 :         Unused << children[i]->SendLoadAndRegisterSheet(uri, aSheetType);
     210             :       }
     211             :     }
     212             :   }
     213           2 :   return rv;
     214             : }
     215             : 
     216             : static nsresult
     217           3 : LoadSheet(nsIURI* aURI,
     218             :           css::SheetParsingMode aParsingMode,
     219             :           StyleBackendType aType,
     220             :           RefPtr<StyleSheet>* aResult)
     221             : {
     222           6 :   RefPtr<css::Loader> loader = new css::Loader(aType, nullptr);
     223           6 :   return loader->LoadSheetSync(aURI, aParsingMode, true, aResult);
     224             : }
     225             : 
     226             : nsresult
     227           3 : nsStyleSheetService::LoadAndRegisterSheetInternal(nsIURI *aSheetURI,
     228             :                                                   uint32_t aSheetType)
     229             : {
     230           3 :   NS_ENSURE_ARG_POINTER(aSheetURI);
     231             : 
     232             :   css::SheetParsingMode parsingMode;
     233           3 :   switch (aSheetType) {
     234             :     case AGENT_SHEET:
     235           3 :       parsingMode = css::eAgentSheetFeatures;
     236           3 :       break;
     237             : 
     238             :     case USER_SHEET:
     239           0 :       parsingMode = css::eUserSheetFeatures;
     240           0 :       break;
     241             : 
     242             :     case AUTHOR_SHEET:
     243           0 :       parsingMode = css::eAuthorSheetFeatures;
     244           0 :       break;
     245             : 
     246             :     default:
     247           0 :       NS_WARNING("invalid sheet type argument");
     248           0 :       return NS_ERROR_INVALID_ARG;
     249             :   }
     250             : 
     251             :   nsresult rv;
     252             : 
     253           6 :   RefPtr<StyleSheet> geckoSheet;
     254           6 :   RefPtr<StyleSheet> servoSheet;
     255             : 
     256           3 :   rv = LoadSheet(aSheetURI, parsingMode, StyleBackendType::Gecko, &geckoSheet);
     257           3 :   NS_ENSURE_SUCCESS(rv, rv);
     258           3 :   MOZ_ASSERT(geckoSheet);
     259             : 
     260             : #ifdef MOZ_STYLO
     261             :   rv = LoadSheet(aSheetURI, parsingMode, StyleBackendType::Servo, &servoSheet);
     262             :   NS_ENSURE_SUCCESS(rv, rv);
     263             :   MOZ_ASSERT(servoSheet);
     264             : #endif
     265             : 
     266           3 :   mGeckoSheets[aSheetType].AppendElement(geckoSheet);
     267           3 :   mServoSheets[aSheetType].AppendElement(servoSheet);
     268             : 
     269           3 :   return NS_OK;
     270             : }
     271             : 
     272             : NS_IMETHODIMP
     273           0 : nsStyleSheetService::SheetRegistered(nsIURI *sheetURI,
     274             :                                      uint32_t aSheetType, bool *_retval)
     275             : {
     276           0 :   NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
     277             :                 aSheetType == USER_SHEET ||
     278             :                 aSheetType == AUTHOR_SHEET);
     279           0 :   NS_ENSURE_ARG_POINTER(sheetURI);
     280           0 :   NS_PRECONDITION(_retval, "Null out param");
     281             : 
     282           0 :   *_retval = (FindSheetByURI(aSheetType, sheetURI) >= 0);
     283             : 
     284           0 :   return NS_OK;
     285             : }
     286             : 
     287             : static nsresult
     288           1 : GetParsingMode(uint32_t aSheetType, css::SheetParsingMode* aParsingMode)
     289             : {
     290           1 :   switch (aSheetType) {
     291             :     case nsStyleSheetService::AGENT_SHEET:
     292           0 :       *aParsingMode = css::eAgentSheetFeatures;
     293           0 :       return NS_OK;
     294             : 
     295             :     case nsStyleSheetService::USER_SHEET:
     296           0 :       *aParsingMode = css::eUserSheetFeatures;
     297           0 :       return NS_OK;
     298             : 
     299             :     case nsStyleSheetService::AUTHOR_SHEET:
     300           1 :       *aParsingMode = css::eAuthorSheetFeatures;
     301           1 :       return NS_OK;
     302             : 
     303             :     default:
     304           0 :       NS_WARNING("invalid sheet type argument");
     305           0 :       return NS_ERROR_INVALID_ARG;
     306             :   }
     307             : }
     308             : 
     309             : NS_IMETHODIMP
     310           1 : nsStyleSheetService::PreloadSheet(nsIURI* aSheetURI, uint32_t aSheetType,
     311             :                                   nsIPreloadedStyleSheet** aSheet)
     312             : {
     313           1 :   NS_PRECONDITION(aSheet, "Null out param");
     314           1 :   NS_ENSURE_ARG_POINTER(aSheetURI);
     315             : 
     316             :   css::SheetParsingMode parsingMode;
     317           1 :   nsresult rv = GetParsingMode(aSheetType, &parsingMode);
     318           1 :   NS_ENSURE_SUCCESS(rv, rv);
     319             : 
     320           2 :   RefPtr<PreloadedStyleSheet> sheet;
     321           1 :   rv = PreloadedStyleSheet::Create(aSheetURI, parsingMode,
     322           2 :                                    getter_AddRefs(sheet));
     323           1 :   NS_ENSURE_SUCCESS(rv, rv);
     324             : 
     325           1 :   rv = sheet->Preload();
     326           1 :   NS_ENSURE_SUCCESS(rv, rv);
     327             : 
     328           1 :   sheet.forget(aSheet);
     329           1 :   return NS_OK;
     330             : }
     331             : 
     332             : NS_IMETHODIMP
     333           0 : nsStyleSheetService::PreloadSheetAsync(nsIURI* aSheetURI, uint32_t aSheetType,
     334             :                                        JSContext* aCx,
     335             :                                        JS::MutableHandleValue aRval)
     336             : {
     337           0 :   NS_ENSURE_ARG_POINTER(aSheetURI);
     338             : 
     339             :   css::SheetParsingMode parsingMode;
     340           0 :   nsresult rv = GetParsingMode(aSheetType, &parsingMode);
     341           0 :   NS_ENSURE_SUCCESS(rv, rv);
     342             : 
     343             :   nsCOMPtr<nsIGlobalObject> global =
     344           0 :     xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
     345           0 :   NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
     346             : 
     347           0 :   ErrorResult errv;
     348           0 :   RefPtr<dom::Promise> promise = dom::Promise::Create(global, errv);
     349           0 :   if (errv.Failed()) {
     350           0 :     return errv.StealNSResult();
     351             :   }
     352             : 
     353           0 :   RefPtr<PreloadedStyleSheet> sheet;
     354           0 :   rv = PreloadedStyleSheet::Create(aSheetURI, parsingMode,
     355           0 :                                    getter_AddRefs(sheet));
     356           0 :   NS_ENSURE_SUCCESS(rv, rv);
     357             : 
     358           0 :   sheet->PreloadAsync(WrapNotNull(promise));
     359             : 
     360           0 :   if (!ToJSValue(aCx, promise, aRval)) {
     361           0 :     return NS_ERROR_FAILURE;
     362             :   }
     363           0 :   return NS_OK;
     364             : }
     365             : 
     366             : NS_IMETHODIMP
     367           0 : nsStyleSheetService::UnregisterSheet(nsIURI *aSheetURI, uint32_t aSheetType)
     368             : {
     369           0 :   NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
     370             :                 aSheetType == USER_SHEET ||
     371             :                 aSheetType == AUTHOR_SHEET);
     372           0 :   NS_ENSURE_ARG_POINTER(aSheetURI);
     373             : 
     374           0 :   MOZ_ASSERT(mGeckoSheets[aSheetType].Length() ==
     375             :                mServoSheets[aSheetType].Length());
     376             : 
     377           0 :   int32_t foundIndex = FindSheetByURI(aSheetType, aSheetURI);
     378           0 :   NS_ENSURE_TRUE(foundIndex >= 0, NS_ERROR_INVALID_ARG);
     379             : 
     380           0 :   RefPtr<StyleSheet> geckoSheet = mGeckoSheets[aSheetType][foundIndex];
     381           0 :   RefPtr<StyleSheet> servoSheet = mServoSheets[aSheetType][foundIndex];
     382             : 
     383           0 :   mGeckoSheets[aSheetType].RemoveElementAt(foundIndex);
     384           0 :   mServoSheets[aSheetType].RemoveElementAt(foundIndex);
     385             : 
     386             :   // Hold on to a copy of the registered PresShells.
     387           0 :   nsTArray<nsCOMPtr<nsIPresShell>> toNotify(mPresShells);
     388           0 :   for (nsIPresShell* presShell : toNotify) {
     389           0 :     if (presShell->StyleSet()) {
     390           0 :       StyleSheet* sheet = presShell->StyleSet()->IsGecko() ? geckoSheet
     391           0 :                                                            : servoSheet;
     392           0 :       presShell->NotifyStyleSheetServiceSheetRemoved(sheet, aSheetType);
     393             :     }
     394             :   }
     395             : 
     396           0 :   if (XRE_IsParentProcess()) {
     397           0 :     nsTArray<dom::ContentParent*> children;
     398           0 :     dom::ContentParent::GetAll(children);
     399             : 
     400           0 :     if (children.IsEmpty()) {
     401           0 :       return NS_OK;
     402             :     }
     403             : 
     404           0 :     mozilla::ipc::URIParams uri;
     405           0 :     SerializeURI(aSheetURI, uri);
     406             : 
     407           0 :     for (uint32_t i = 0; i < children.Length(); i++) {
     408           0 :       Unused << children[i]->SendUnregisterSheet(uri, aSheetType);
     409             :     }
     410             :   }
     411             : 
     412           0 :   return NS_OK;
     413             : }
     414             : 
     415             : //static
     416             : nsStyleSheetService *
     417          82 : nsStyleSheetService::GetInstance()
     418             : {
     419             :   static bool first = true;
     420          82 :   if (first) {
     421             :     // make sure at first call that it's inited
     422             :     nsCOMPtr<nsIStyleSheetService> dummy =
     423           6 :       do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
     424           3 :     first = false;
     425             :   }
     426             : 
     427          82 :   return gInstance;
     428             : }
     429             : 
     430           0 : MOZ_DEFINE_MALLOC_SIZE_OF(StyleSheetServiceMallocSizeOf)
     431             : 
     432             : NS_IMETHODIMP
     433           0 : nsStyleSheetService::CollectReports(nsIHandleReportCallback* aHandleReport,
     434             :                                     nsISupports* aData, bool aAnonymize)
     435             : {
     436           0 :   MOZ_COLLECT_REPORT(
     437             :     "explicit/layout/style-sheet-service", KIND_HEAP, UNITS_BYTES,
     438             :     SizeOfIncludingThis(StyleSheetServiceMallocSizeOf),
     439           0 :     "Memory used for style sheets held by the style sheet service.");
     440             : 
     441           0 :   return NS_OK;
     442             : }
     443             : 
     444             : size_t
     445           0 : nsStyleSheetService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     446             : {
     447           0 :   size_t n = aMallocSizeOf(this);
     448           0 :   for (auto* sheetArrays : { &mGeckoSheets, &mServoSheets }) {
     449           0 :     for (auto& sheetArray : *sheetArrays) {
     450           0 :       n += sheetArray.ShallowSizeOfExcludingThis(aMallocSizeOf);
     451           0 :       for (StyleSheet* sheet : sheetArray) {
     452           0 :         if (sheet) {
     453           0 :           n += sheet->SizeOfIncludingThis(aMallocSizeOf);
     454             :         }
     455             :       }
     456             :     }
     457             :   }
     458           0 :   return n;
     459             : }
     460             : 
     461             : void
     462          28 : nsStyleSheetService::RegisterPresShell(nsIPresShell* aPresShell)
     463             : {
     464          28 :   MOZ_ASSERT(!mPresShells.Contains(aPresShell));
     465          28 :   mPresShells.AppendElement(aPresShell);
     466          28 : }
     467             : 
     468             : void
     469           4 : nsStyleSheetService::UnregisterPresShell(nsIPresShell* aPresShell)
     470             : {
     471           4 :   MOZ_ASSERT(mPresShells.Contains(aPresShell));
     472           4 :   mPresShells.RemoveElement(aPresShell);
     473           4 : }

Generated by: LCOV version 1.13