layout/base/nsStyleSheetService.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     7 /* implementation of interface for managing user and user-agent style sheets */
     9 #include "nsStyleSheetService.h"
    10 #include "nsIStyleSheet.h"
    11 #include "mozilla/MemoryReporting.h"
    12 #include "mozilla/unused.h"
    13 #include "mozilla/css/Loader.h"
    14 #include "mozilla/dom/ContentParent.h"
    15 #include "mozilla/ipc/URIUtils.h"
    16 #include "nsCSSStyleSheet.h"
    17 #include "nsIURI.h"
    18 #include "nsCOMPtr.h"
    19 #include "nsICategoryManager.h"
    20 #include "nsISupportsPrimitives.h"
    21 #include "nsNetUtil.h"
    22 #include "nsIObserverService.h"
    23 #include "nsLayoutStatics.h"
    25 using namespace mozilla;
    27 nsStyleSheetService *nsStyleSheetService::gInstance = nullptr;
    29 nsStyleSheetService::nsStyleSheetService()
    30 {
    31   PR_STATIC_ASSERT(0 == AGENT_SHEET && 1 == USER_SHEET && 2 == AUTHOR_SHEET);
    32   NS_ASSERTION(!gInstance, "Someone is using CreateInstance instead of GetService");
    33   gInstance = this;
    34   nsLayoutStatics::AddRef();
    35 }
    37 nsStyleSheetService::~nsStyleSheetService()
    38 {
    39   UnregisterWeakMemoryReporter(this);
    41   gInstance = nullptr;
    42   nsLayoutStatics::Release();
    43 }
    45 NS_IMPL_ISUPPORTS(
    46   nsStyleSheetService, nsIStyleSheetService, nsIMemoryReporter)
    48 void
    49 nsStyleSheetService::RegisterFromEnumerator(nsICategoryManager  *aManager,
    50                                             const char          *aCategory,
    51                                             nsISimpleEnumerator *aEnumerator,
    52                                             uint32_t             aSheetType)
    53 {
    54   if (!aEnumerator)
    55     return;
    57   bool hasMore;
    58   while (NS_SUCCEEDED(aEnumerator->HasMoreElements(&hasMore)) && hasMore) {
    59     nsCOMPtr<nsISupports> element;
    60     if (NS_FAILED(aEnumerator->GetNext(getter_AddRefs(element))))
    61       break;
    63     nsCOMPtr<nsISupportsCString> icStr = do_QueryInterface(element);
    64     NS_ASSERTION(icStr,
    65                  "category manager entries must be nsISupportsCStrings");
    67     nsAutoCString name;
    68     icStr->GetData(name);
    70     nsXPIDLCString spec;
    71     aManager->GetCategoryEntry(aCategory, name.get(), getter_Copies(spec));
    73     nsCOMPtr<nsIURI> uri;
    74     NS_NewURI(getter_AddRefs(uri), spec);
    75     if (uri)
    76       LoadAndRegisterSheetInternal(uri, aSheetType);
    77   }
    78 }
    80 int32_t
    81 nsStyleSheetService::FindSheetByURI(const nsCOMArray<nsIStyleSheet> &sheets,
    82                                     nsIURI *sheetURI)
    83 {
    84   for (int32_t i = sheets.Count() - 1; i >= 0; i-- ) {
    85     bool bEqual;
    86     nsIURI* uri = sheets[i]->GetSheetURI();
    87     if (uri
    88         && NS_SUCCEEDED(uri->Equals(sheetURI, &bEqual))
    89         && bEqual) {
    90       return i;
    91     }
    92   }
    94   return -1;
    95 }
    97 nsresult
    98 nsStyleSheetService::Init()
    99 {
   100   // Child processes get their style sheets from the ContentParent.
   101   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   102     return NS_OK;
   103   }
   105   // Enumerate all of the style sheet URIs registered in the category
   106   // manager and load them.
   108   nsCOMPtr<nsICategoryManager> catMan =
   109     do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
   111   NS_ENSURE_TRUE(catMan, NS_ERROR_OUT_OF_MEMORY);
   113   nsCOMPtr<nsISimpleEnumerator> sheets;
   114   catMan->EnumerateCategory("agent-style-sheets", getter_AddRefs(sheets));
   115   RegisterFromEnumerator(catMan, "agent-style-sheets", sheets, AGENT_SHEET);
   117   catMan->EnumerateCategory("user-style-sheets", getter_AddRefs(sheets));
   118   RegisterFromEnumerator(catMan, "user-style-sheets", sheets, USER_SHEET);
   120   catMan->EnumerateCategory("author-style-sheets", getter_AddRefs(sheets));
   121   RegisterFromEnumerator(catMan, "author-style-sheets", sheets, AUTHOR_SHEET);
   123   RegisterWeakMemoryReporter(this);
   125   return NS_OK;
   126 }
   128 NS_IMETHODIMP
   129 nsStyleSheetService::LoadAndRegisterSheet(nsIURI *aSheetURI,
   130                                           uint32_t aSheetType)
   131 {
   132   nsresult rv = LoadAndRegisterSheetInternal(aSheetURI, aSheetType);
   133   if (NS_SUCCEEDED(rv)) {
   134     const char* message;
   135     switch (aSheetType) {
   136       case AGENT_SHEET:
   137         message = "agent-sheet-added";
   138         break;
   139       case USER_SHEET:
   140         message = "user-sheet-added";
   141         break;
   142       case AUTHOR_SHEET:
   143         message = "author-sheet-added";
   144         break;
   145       default:
   146         return NS_ERROR_INVALID_ARG;
   147     }
   148     nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
   149     if (serv) {
   150       // We're guaranteed that the new sheet is the last sheet in
   151       // mSheets[aSheetType]
   152       const nsCOMArray<nsIStyleSheet> & sheets = mSheets[aSheetType];
   153       serv->NotifyObservers(sheets[sheets.Count() - 1], message, nullptr);
   154     }
   156     if (XRE_GetProcessType() == GeckoProcessType_Default) {
   157       nsTArray<dom::ContentParent*> children;
   158       dom::ContentParent::GetAll(children);
   160       if (children.IsEmpty()) {
   161         return rv;
   162       }
   164       mozilla::ipc::URIParams uri;
   165       SerializeURI(aSheetURI, uri);
   167       for (uint32_t i = 0; i < children.Length(); i++) {
   168         unused << children[i]->SendLoadAndRegisterSheet(uri, aSheetType);
   169       }
   170     }
   171   }
   172   return rv;
   173 }
   175 nsresult
   176 nsStyleSheetService::LoadAndRegisterSheetInternal(nsIURI *aSheetURI,
   177                                                   uint32_t aSheetType)
   178 {
   179   NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
   180                 aSheetType == USER_SHEET ||
   181                 aSheetType == AUTHOR_SHEET);
   182   NS_ENSURE_ARG_POINTER(aSheetURI);
   184   nsRefPtr<css::Loader> loader = new css::Loader();
   186   nsRefPtr<nsCSSStyleSheet> sheet;
   187   // Allow UA sheets, but not user sheets, to use unsafe rules
   188   nsresult rv = loader->LoadSheetSync(aSheetURI, aSheetType == AGENT_SHEET,
   189                                       true, getter_AddRefs(sheet));
   190   NS_ENSURE_SUCCESS(rv, rv);
   192   if (!mSheets[aSheetType].AppendObject(sheet)) {
   193     rv = NS_ERROR_OUT_OF_MEMORY;
   194   }
   196   return rv;
   197 }
   199 NS_IMETHODIMP
   200 nsStyleSheetService::SheetRegistered(nsIURI *sheetURI,
   201                                      uint32_t aSheetType, bool *_retval)
   202 {
   203   NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
   204                 aSheetType == USER_SHEET ||
   205                 aSheetType == AUTHOR_SHEET);
   206   NS_ENSURE_ARG_POINTER(sheetURI);
   207   NS_PRECONDITION(_retval, "Null out param");
   209   *_retval = (FindSheetByURI(mSheets[aSheetType], sheetURI) >= 0);
   211   return NS_OK;
   212 }
   214 NS_IMETHODIMP
   215 nsStyleSheetService::UnregisterSheet(nsIURI *aSheetURI, uint32_t aSheetType)
   216 {
   217   NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
   218                 aSheetType == USER_SHEET ||
   219                 aSheetType == AUTHOR_SHEET);
   220   NS_ENSURE_ARG_POINTER(aSheetURI);
   222   int32_t foundIndex = FindSheetByURI(mSheets[aSheetType], aSheetURI);
   223   NS_ENSURE_TRUE(foundIndex >= 0, NS_ERROR_INVALID_ARG);
   224   nsCOMPtr<nsIStyleSheet> sheet = mSheets[aSheetType][foundIndex];
   225   mSheets[aSheetType].RemoveObjectAt(foundIndex);
   227   const char* message;
   228   switch (aSheetType) {
   229     case AGENT_SHEET:
   230       message = "agent-sheet-removed";
   231       break;
   232     case USER_SHEET:
   233       message = "user-sheet-removed";
   234       break;
   235     case AUTHOR_SHEET:
   236       message = "author-sheet-removed";
   237       break;
   238   }
   240   nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
   241   if (serv)
   242     serv->NotifyObservers(sheet, message, nullptr);
   244   if (XRE_GetProcessType() == GeckoProcessType_Default) {
   245     nsTArray<dom::ContentParent*> children;
   246     dom::ContentParent::GetAll(children);
   248     if (children.IsEmpty()) {
   249       return NS_OK;
   250     }
   252     mozilla::ipc::URIParams uri;
   253     SerializeURI(aSheetURI, uri);
   255     for (uint32_t i = 0; i < children.Length(); i++) {
   256       unused << children[i]->SendUnregisterSheet(uri, aSheetType);
   257     }
   258   }
   260   return NS_OK;
   261 }
   263 //static
   264 nsStyleSheetService *
   265 nsStyleSheetService::GetInstance()
   266 {
   267   static bool first = true;
   268   if (first) {
   269     // make sure at first call that it's inited
   270     nsCOMPtr<nsIStyleSheetService> dummy =
   271       do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
   272     first = false;
   273   }
   275   return gInstance;
   276 }
   278 static size_t
   279 SizeOfElementIncludingThis(nsIStyleSheet* aElement,
   280                            MallocSizeOf aMallocSizeOf, void *aData)
   281 {
   282   return aElement->SizeOfIncludingThis(aMallocSizeOf);
   283 }
   285 MOZ_DEFINE_MALLOC_SIZE_OF(StyleSheetServiceMallocSizeOf)
   287 NS_IMETHODIMP
   288 nsStyleSheetService::CollectReports(nsIHandleReportCallback* aHandleReport,
   289                                     nsISupports* aData)
   290 {
   291   return MOZ_COLLECT_REPORT(
   292     "explicit/layout/style-sheet-service", KIND_HEAP, UNITS_BYTES,
   293     SizeOfIncludingThis(StyleSheetServiceMallocSizeOf),
   294     "Memory used for style sheets held by the style sheet service.");
   295 }
   297 size_t
   298 nsStyleSheetService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
   299 {
   300   size_t n = aMallocSizeOf(this);
   301   n += mSheets[AGENT_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis,
   302                                                 aMallocSizeOf);
   303   n += mSheets[USER_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis,
   304                                                aMallocSizeOf);
   305   n += mSheets[AUTHOR_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis,
   306                                                  aMallocSizeOf);
   307   return n;
   308 }

mercurial