tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsStyleSheetService.cpp (10141B)


      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 
     11 #include "mozilla/MemoryReporting.h"
     12 #include "mozilla/PreloadedStyleSheet.h"
     13 #include "mozilla/PresShell.h"
     14 #include "mozilla/PresShellInlines.h"
     15 #include "mozilla/StyleSheet.h"
     16 #include "mozilla/StyleSheetInlines.h"
     17 #include "mozilla/css/Loader.h"
     18 #include "mozilla/dom/ContentParent.h"
     19 #include "mozilla/dom/Promise.h"
     20 #include "mozilla/ipc/URIUtils.h"
     21 #include "nsCOMPtr.h"
     22 #include "nsIConsoleService.h"
     23 #include "nsISimpleEnumerator.h"
     24 #include "nsISupportsPrimitives.h"
     25 #include "nsIURI.h"
     26 #include "nsLayoutStatics.h"
     27 #include "nsLayoutUtils.h"
     28 #include "nsNetUtil.h"
     29 
     30 using namespace mozilla;
     31 
     32 nsStyleSheetService* nsStyleSheetService::gInstance = nullptr;
     33 
     34 nsStyleSheetService::nsStyleSheetService() {
     35  static_assert(0 == AGENT_SHEET && 1 == USER_SHEET && 2 == AUTHOR_SHEET,
     36                "Convention for Style Sheet");
     37  NS_ASSERTION(!gInstance,
     38               "Someone is using CreateInstance instead of GetService");
     39  if (!gInstance) {
     40    gInstance = this;
     41  }
     42  nsLayoutStatics::AddRef();
     43 }
     44 
     45 nsStyleSheetService::~nsStyleSheetService() {
     46  UnregisterWeakMemoryReporter(this);
     47 
     48  if (gInstance == this) {
     49    gInstance = nullptr;
     50  }
     51  nsLayoutStatics::Release();
     52 }
     53 
     54 NS_IMPL_ISUPPORTS(nsStyleSheetService, nsIStyleSheetService, nsIMemoryReporter)
     55 
     56 static bool SheetHasOriginalURI(StyleSheet* aSheet, nsIURI* aSheetURI) {
     57  MOZ_ASSERT(aSheetURI);
     58 
     59  bool result;
     60  nsIURI* uri = aSheet->GetOriginalURI();
     61  return uri && NS_SUCCEEDED(uri->Equals(aSheetURI, &result)) && result;
     62 }
     63 
     64 int32_t nsStyleSheetService::FindSheetByURI(uint32_t aSheetType,
     65                                            nsIURI* aSheetURI) {
     66  SheetArray& sheets = mSheets[aSheetType];
     67  for (int32_t i = sheets.Length() - 1; i >= 0; i--) {
     68    if (SheetHasOriginalURI(sheets[i], aSheetURI)) {
     69      return i;
     70    }
     71  }
     72 
     73  return -1;
     74 }
     75 
     76 nsresult nsStyleSheetService::Init() {
     77  // Child processes get their style sheets from the ContentParent.
     78  if (XRE_IsContentProcess()) {
     79    return NS_OK;
     80  }
     81 
     82  RegisterWeakMemoryReporter(this);
     83 
     84  return NS_OK;
     85 }
     86 
     87 NS_IMETHODIMP
     88 nsStyleSheetService::LoadAndRegisterSheet(nsIURI* aSheetURI,
     89                                          uint32_t aSheetType) {
     90  // Warn developers if their stylesheet URL has a #ref at the end.
     91  // Stylesheet URIs don't benefit from having a #ref suffix -- and if the
     92  // sheet is a data URI, someone might've created this #ref by accident (and
     93  // truncated their data-URI stylesheet) by using an unescaped # character in
     94  // a #RRGGBB color or #foo() ID-selector in their data-URI representation.
     95  bool hasRef;
     96  nsresult rv = aSheetURI->GetHasRef(&hasRef);
     97  NS_ENSURE_SUCCESS(rv, rv);
     98  if (aSheetURI && hasRef) {
     99    nsCOMPtr<nsIConsoleService> consoleService =
    100        do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    101    NS_WARNING_ASSERTION(consoleService, "Failed to get console service!");
    102    if (consoleService) {
    103      const char16_t* message =
    104          u"nsStyleSheetService::LoadAndRegisterSheet: "
    105          u"URI contains unescaped hash character, which might be truncating "
    106          u"the sheet, if it's a data URI.";
    107      consoleService->LogStringMessage(message);
    108    }
    109  }
    110 
    111  rv = LoadAndRegisterSheetInternal(aSheetURI, aSheetType);
    112  if (NS_SUCCEEDED(rv)) {
    113    // Hold on to a copy of the registered PresShells.
    114    for (PresShell* presShell : mPresShells.Clone()) {
    115      StyleSheet* sheet = mSheets[aSheetType].LastElement();
    116      presShell->NotifyStyleSheetServiceSheetAdded(sheet, aSheetType);
    117    }
    118 
    119    if (XRE_IsParentProcess()) {
    120      nsTArray<dom::ContentParent*> children;
    121      dom::ContentParent::GetAll(children);
    122 
    123      if (children.IsEmpty()) {
    124        return rv;
    125      }
    126 
    127      for (uint32_t i = 0; i < children.Length(); i++) {
    128        (void)children[i]->SendLoadAndRegisterSheet(aSheetURI, aSheetType);
    129      }
    130    }
    131  }
    132  return rv;
    133 }
    134 
    135 nsresult nsStyleSheetService::LoadAndRegisterSheetInternal(
    136    nsIURI* aSheetURI, uint32_t aSheetType) {
    137  NS_ENSURE_ARG_POINTER(aSheetURI);
    138 
    139  css::SheetParsingMode parsingMode;
    140  switch (aSheetType) {
    141    case AGENT_SHEET:
    142      parsingMode = css::eAgentSheetFeatures;
    143      break;
    144 
    145    case USER_SHEET:
    146      parsingMode = css::eUserSheetFeatures;
    147      break;
    148 
    149    case AUTHOR_SHEET:
    150      parsingMode = css::eAuthorSheetFeatures;
    151      break;
    152 
    153    default:
    154      NS_WARNING("invalid sheet type argument");
    155      return NS_ERROR_INVALID_ARG;
    156  }
    157 
    158  auto loader = MakeRefPtr<css::Loader>();
    159  auto result = loader->LoadSheetSync(aSheetURI, parsingMode,
    160                                      css::Loader::UseSystemPrincipal::Yes);
    161  if (result.isErr()) {
    162    return result.unwrapErr();
    163  }
    164  mSheets[aSheetType].AppendElement(result.unwrap());
    165  return NS_OK;
    166 }
    167 
    168 NS_IMETHODIMP
    169 nsStyleSheetService::SheetRegistered(nsIURI* sheetURI, uint32_t aSheetType,
    170                                     bool* _retval) {
    171  NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET ||
    172                aSheetType == AUTHOR_SHEET);
    173  NS_ENSURE_ARG_POINTER(sheetURI);
    174  MOZ_ASSERT(_retval, "Null out param");
    175 
    176  // Check to see if we have the sheet.
    177  *_retval = FindSheetByURI(aSheetType, sheetURI) >= 0;
    178  return NS_OK;
    179 }
    180 
    181 static nsresult GetParsingMode(uint32_t aSheetType,
    182                               css::SheetParsingMode* aParsingMode) {
    183  switch (aSheetType) {
    184    case nsStyleSheetService::AGENT_SHEET:
    185      *aParsingMode = css::eAgentSheetFeatures;
    186      return NS_OK;
    187 
    188    case nsStyleSheetService::USER_SHEET:
    189      *aParsingMode = css::eUserSheetFeatures;
    190      return NS_OK;
    191 
    192    case nsStyleSheetService::AUTHOR_SHEET:
    193      *aParsingMode = css::eAuthorSheetFeatures;
    194      return NS_OK;
    195 
    196    default:
    197      NS_WARNING("invalid sheet type argument");
    198      return NS_ERROR_INVALID_ARG;
    199  }
    200 }
    201 
    202 NS_IMETHODIMP
    203 nsStyleSheetService::PreloadSheet(nsIURI* aSheetURI, uint32_t aSheetType,
    204                                  nsIPreloadedStyleSheet** aSheet) {
    205  MOZ_ASSERT(aSheet, "Null out param");
    206  NS_ENSURE_ARG_POINTER(aSheetURI);
    207 
    208  css::SheetParsingMode parsingMode;
    209  nsresult rv = GetParsingMode(aSheetType, &parsingMode);
    210  NS_ENSURE_SUCCESS(rv, rv);
    211 
    212  auto sheet = MakeRefPtr<PreloadedStyleSheet>(aSheetURI, parsingMode);
    213  NS_ENSURE_SUCCESS(rv, rv);
    214 
    215  rv = sheet->Preload();
    216  NS_ENSURE_SUCCESS(rv, rv);
    217 
    218  sheet.forget(aSheet);
    219  return NS_OK;
    220 }
    221 
    222 NS_IMETHODIMP
    223 nsStyleSheetService::PreloadSheetAsync(nsIURI* aSheetURI, uint32_t aSheetType,
    224                                       JSContext* aCx,
    225                                       JS::MutableHandle<JS::Value> aRval) {
    226  NS_ENSURE_ARG_POINTER(aSheetURI);
    227 
    228  css::SheetParsingMode parsingMode;
    229  nsresult rv = GetParsingMode(aSheetType, &parsingMode);
    230  NS_ENSURE_SUCCESS(rv, rv);
    231 
    232  nsCOMPtr<nsIGlobalObject> global = xpc::CurrentNativeGlobal(aCx);
    233  NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
    234 
    235  ErrorResult errv;
    236  RefPtr<dom::Promise> promise = dom::Promise::Create(global, errv);
    237  if (errv.Failed()) {
    238    return errv.StealNSResult();
    239  }
    240 
    241  auto sheet = MakeRefPtr<PreloadedStyleSheet>(aSheetURI, parsingMode);
    242  sheet->PreloadAsync(WrapNotNull(promise));
    243 
    244  if (!ToJSValue(aCx, promise, aRval)) {
    245    return NS_ERROR_FAILURE;
    246  }
    247  return NS_OK;
    248 }
    249 
    250 NS_IMETHODIMP
    251 nsStyleSheetService::UnregisterSheet(nsIURI* aSheetURI, uint32_t aSheetType) {
    252  NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET ||
    253                aSheetType == AUTHOR_SHEET);
    254  NS_ENSURE_ARG_POINTER(aSheetURI);
    255 
    256  RefPtr<StyleSheet> sheet;
    257  int32_t foundIndex = FindSheetByURI(aSheetType, aSheetURI);
    258  if (foundIndex >= 0) {
    259    sheet = mSheets[aSheetType][foundIndex];
    260    mSheets[aSheetType].RemoveElementAt(foundIndex);
    261  }
    262 
    263  // Hold on to a copy of the registered PresShells.
    264  for (PresShell* presShell : mPresShells.Clone()) {
    265    if (presShell->StyleSet()) {
    266      if (sheet) {
    267        presShell->NotifyStyleSheetServiceSheetRemoved(sheet, aSheetType);
    268      }
    269    }
    270  }
    271 
    272  if (XRE_IsParentProcess()) {
    273    nsTArray<dom::ContentParent*> children;
    274    dom::ContentParent::GetAll(children);
    275 
    276    if (children.IsEmpty()) {
    277      return NS_OK;
    278    }
    279 
    280    for (uint32_t i = 0; i < children.Length(); i++) {
    281      (void)children[i]->SendUnregisterSheet(aSheetURI, aSheetType);
    282    }
    283  }
    284 
    285  return NS_OK;
    286 }
    287 
    288 // static
    289 nsStyleSheetService* nsStyleSheetService::GetInstance() {
    290  static bool first = true;
    291  if (first) {
    292    // make sure at first call that it's inited
    293    nsCOMPtr<nsIStyleSheetService> dummy =
    294        do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
    295    first = false;
    296  }
    297 
    298  return gInstance;
    299 }
    300 
    301 MOZ_DEFINE_MALLOC_SIZE_OF(StyleSheetServiceMallocSizeOf)
    302 
    303 NS_IMETHODIMP
    304 nsStyleSheetService::CollectReports(nsIHandleReportCallback* aHandleReport,
    305                                    nsISupports* aData, bool aAnonymize) {
    306  MOZ_COLLECT_REPORT(
    307      "explicit/layout/style-sheet-service", KIND_HEAP, UNITS_BYTES,
    308      SizeOfIncludingThis(StyleSheetServiceMallocSizeOf),
    309      "Memory used for style sheets held by the style sheet service.");
    310 
    311  return NS_OK;
    312 }
    313 
    314 size_t nsStyleSheetService::SizeOfIncludingThis(
    315    mozilla::MallocSizeOf aMallocSizeOf) const {
    316  size_t n = aMallocSizeOf(this);
    317  for (const auto& sheetArray : mSheets) {
    318    n += sheetArray.ShallowSizeOfExcludingThis(aMallocSizeOf);
    319    for (StyleSheet* sheet : sheetArray) {
    320      if (sheet) {
    321        n += sheet->SizeOfIncludingThis(aMallocSizeOf);
    322      }
    323    }
    324  }
    325  return n;
    326 }
    327 
    328 void nsStyleSheetService::RegisterPresShell(PresShell* aPresShell) {
    329  MOZ_ASSERT(!mPresShells.Contains(aPresShell));
    330  mPresShells.AppendElement(aPresShell);
    331 }
    332 
    333 void nsStyleSheetService::UnregisterPresShell(PresShell* aPresShell) {
    334  MOZ_ASSERT(mPresShells.Contains(aPresShell));
    335  mPresShells.RemoveElement(aPresShell);
    336 }