nsLayoutStylesheetCache.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsLayoutStylesheetCache.h"
  6. #include "nsAppDirectoryServiceDefs.h"
  7. #include "mozilla/StyleSheetInlines.h"
  8. #include "mozilla/MemoryReporting.h"
  9. #include "mozilla/Preferences.h"
  10. #include "mozilla/StyleSheet.h"
  11. #include "mozilla/StyleSheetInlines.h"
  12. #include "mozilla/css/Loader.h"
  13. #include "mozilla/dom/SRIMetadata.h"
  14. #include "nsIConsoleService.h"
  15. #include "nsIFile.h"
  16. #include "nsNetUtil.h"
  17. #include "nsIObserverService.h"
  18. #include "nsServiceManagerUtils.h"
  19. #include "nsIXULRuntime.h"
  20. #include "nsPrintfCString.h"
  21. #include "nsXULAppAPI.h"
  22. using namespace mozilla;
  23. using namespace mozilla::css;
  24. static bool sNumberControlEnabled;
  25. #define NUMBER_CONTROL_PREF "dom.forms.number"
  26. NS_IMPL_ISUPPORTS(
  27. nsLayoutStylesheetCache, nsIObserver, nsIMemoryReporter)
  28. nsresult
  29. nsLayoutStylesheetCache::Observe(nsISupports* aSubject,
  30. const char* aTopic,
  31. const char16_t* aData)
  32. {
  33. if (!strcmp(aTopic, "profile-before-change")) {
  34. mUserContentSheet = nullptr;
  35. mUserChromeSheet = nullptr;
  36. }
  37. else if (!strcmp(aTopic, "profile-do-change")) {
  38. InitFromProfile();
  39. }
  40. else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
  41. strcmp(aTopic, "chrome-flush-caches") == 0) {
  42. mScrollbarsSheet = nullptr;
  43. mFormsSheet = nullptr;
  44. mNumberControlSheet = nullptr;
  45. }
  46. else {
  47. NS_NOTREACHED("Unexpected observer topic.");
  48. }
  49. return NS_OK;
  50. }
  51. StyleSheet*
  52. nsLayoutStylesheetCache::ScrollbarsSheet()
  53. {
  54. if (!mScrollbarsSheet) {
  55. // Scrollbars don't need access to unsafe rules
  56. LoadSheetURL("chrome://global/skin/scrollbars.css",
  57. &mScrollbarsSheet, eAuthorSheetFeatures, eCrash);
  58. }
  59. return mScrollbarsSheet;
  60. }
  61. StyleSheet*
  62. nsLayoutStylesheetCache::FormsSheet()
  63. {
  64. if (!mFormsSheet) {
  65. // forms.css needs access to unsafe rules
  66. LoadSheetURL("resource://gre-resources/forms.css",
  67. &mFormsSheet, eAgentSheetFeatures, eCrash);
  68. }
  69. return mFormsSheet;
  70. }
  71. StyleSheet*
  72. nsLayoutStylesheetCache::NumberControlSheet()
  73. {
  74. if (!sNumberControlEnabled) {
  75. return nullptr;
  76. }
  77. if (!mNumberControlSheet) {
  78. LoadSheetURL("resource://gre-resources/number-control.css",
  79. &mNumberControlSheet, eAgentSheetFeatures, eCrash);
  80. }
  81. return mNumberControlSheet;
  82. }
  83. StyleSheet*
  84. nsLayoutStylesheetCache::UserContentSheet()
  85. {
  86. return mUserContentSheet;
  87. }
  88. StyleSheet*
  89. nsLayoutStylesheetCache::UserChromeSheet()
  90. {
  91. return mUserChromeSheet;
  92. }
  93. StyleSheet*
  94. nsLayoutStylesheetCache::UASheet()
  95. {
  96. if (!mUASheet) {
  97. LoadSheetURL("resource://gre-resources/ua.css",
  98. &mUASheet, eAgentSheetFeatures, eCrash);
  99. }
  100. return mUASheet;
  101. }
  102. StyleSheet*
  103. nsLayoutStylesheetCache::HTMLSheet()
  104. {
  105. if (!mHTMLSheet) {
  106. LoadSheetURL("resource://gre-resources/html.css",
  107. &mHTMLSheet, eAgentSheetFeatures, eCrash);
  108. }
  109. return mHTMLSheet;
  110. }
  111. StyleSheet*
  112. nsLayoutStylesheetCache::MinimalXULSheet()
  113. {
  114. return mMinimalXULSheet;
  115. }
  116. StyleSheet*
  117. nsLayoutStylesheetCache::XULSheet()
  118. {
  119. return mXULSheet;
  120. }
  121. StyleSheet*
  122. nsLayoutStylesheetCache::QuirkSheet()
  123. {
  124. return mQuirkSheet;
  125. }
  126. StyleSheet*
  127. nsLayoutStylesheetCache::SVGSheet()
  128. {
  129. return mSVGSheet;
  130. }
  131. StyleSheet*
  132. nsLayoutStylesheetCache::MathMLSheet()
  133. {
  134. if (!mMathMLSheet) {
  135. LoadSheetURL("resource://gre-resources/mathml.css",
  136. &mMathMLSheet, eAgentSheetFeatures, eCrash);
  137. }
  138. return mMathMLSheet;
  139. }
  140. StyleSheet*
  141. nsLayoutStylesheetCache::CounterStylesSheet()
  142. {
  143. return mCounterStylesSheet;
  144. }
  145. StyleSheet*
  146. nsLayoutStylesheetCache::NoScriptSheet()
  147. {
  148. if (!mNoScriptSheet) {
  149. LoadSheetURL("resource://gre-resources/noscript.css",
  150. &mNoScriptSheet, eAgentSheetFeatures, eCrash);
  151. }
  152. return mNoScriptSheet;
  153. }
  154. StyleSheet*
  155. nsLayoutStylesheetCache::NoFramesSheet()
  156. {
  157. if (!mNoFramesSheet) {
  158. LoadSheetURL("resource://gre-resources/noframes.css",
  159. &mNoFramesSheet, eAgentSheetFeatures, eCrash);
  160. }
  161. return mNoFramesSheet;
  162. }
  163. StyleSheet*
  164. nsLayoutStylesheetCache::ChromePreferenceSheet(nsPresContext* aPresContext)
  165. {
  166. if (!mChromePreferenceSheet) {
  167. BuildPreferenceSheet(&mChromePreferenceSheet, aPresContext);
  168. }
  169. return mChromePreferenceSheet;
  170. }
  171. StyleSheet*
  172. nsLayoutStylesheetCache::ContentPreferenceSheet(nsPresContext* aPresContext)
  173. {
  174. if (!mContentPreferenceSheet) {
  175. BuildPreferenceSheet(&mContentPreferenceSheet, aPresContext);
  176. }
  177. return mContentPreferenceSheet;
  178. }
  179. StyleSheet*
  180. nsLayoutStylesheetCache::ContentEditableSheet()
  181. {
  182. if (!mContentEditableSheet) {
  183. LoadSheetURL("resource://gre/res/contenteditable.css",
  184. &mContentEditableSheet, eAgentSheetFeatures, eCrash);
  185. }
  186. return mContentEditableSheet;
  187. }
  188. StyleSheet*
  189. nsLayoutStylesheetCache::DesignModeSheet()
  190. {
  191. if (!mDesignModeSheet) {
  192. LoadSheetURL("resource://gre/res/designmode.css",
  193. &mDesignModeSheet, eAgentSheetFeatures, eCrash);
  194. }
  195. return mDesignModeSheet;
  196. }
  197. void
  198. nsLayoutStylesheetCache::Shutdown()
  199. {
  200. gCSSLoader_Gecko = nullptr;
  201. gCSSLoader_Servo = nullptr;
  202. gStyleCache_Gecko = nullptr;
  203. gStyleCache_Servo = nullptr;
  204. MOZ_ASSERT(!gUserContentSheetURL, "Got the URL but never used?");
  205. }
  206. void
  207. nsLayoutStylesheetCache::SetUserContentCSSURL(nsIURI* aURI)
  208. {
  209. MOZ_ASSERT(XRE_IsContentProcess(), "Only used in content processes.");
  210. gUserContentSheetURL = aURI;
  211. }
  212. MOZ_DEFINE_MALLOC_SIZE_OF(LayoutStylesheetCacheMallocSizeOf)
  213. NS_IMETHODIMP
  214. nsLayoutStylesheetCache::CollectReports(nsIHandleReportCallback* aHandleReport,
  215. nsISupports* aData, bool aAnonymize)
  216. {
  217. MOZ_COLLECT_REPORT(
  218. "explicit/layout/style-sheet-cache", KIND_HEAP, UNITS_BYTES,
  219. SizeOfIncludingThis(LayoutStylesheetCacheMallocSizeOf),
  220. "Memory used for some built-in style sheets.");
  221. return NS_OK;
  222. }
  223. size_t
  224. nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
  225. {
  226. size_t n = aMallocSizeOf(this);
  227. #define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0;
  228. MEASURE(mChromePreferenceSheet);
  229. MEASURE(mContentEditableSheet);
  230. MEASURE(mContentPreferenceSheet);
  231. MEASURE(mCounterStylesSheet);
  232. MEASURE(mDesignModeSheet);
  233. MEASURE(mFormsSheet);
  234. MEASURE(mHTMLSheet);
  235. MEASURE(mMathMLSheet);
  236. MEASURE(mMinimalXULSheet);
  237. MEASURE(mNoFramesSheet);
  238. MEASURE(mNoScriptSheet);
  239. MEASURE(mNumberControlSheet);
  240. MEASURE(mQuirkSheet);
  241. MEASURE(mSVGSheet);
  242. MEASURE(mScrollbarsSheet);
  243. MEASURE(mUASheet);
  244. MEASURE(mUserChromeSheet);
  245. MEASURE(mUserContentSheet);
  246. MEASURE(mXULSheet);
  247. // Measurement of the following members may be added later if DMD finds it is
  248. // worthwhile:
  249. // - gCSSLoader_Gecko
  250. // - gCSSLoader_Servo
  251. return n;
  252. }
  253. nsLayoutStylesheetCache::nsLayoutStylesheetCache(StyleBackendType aType)
  254. : mBackendType(aType)
  255. {
  256. nsCOMPtr<nsIObserverService> obsSvc =
  257. mozilla::services::GetObserverService();
  258. NS_ASSERTION(obsSvc, "No global observer service?");
  259. if (obsSvc) {
  260. obsSvc->AddObserver(this, "profile-before-change", false);
  261. obsSvc->AddObserver(this, "profile-do-change", false);
  262. obsSvc->AddObserver(this, "chrome-flush-skin-caches", false);
  263. obsSvc->AddObserver(this, "chrome-flush-caches", false);
  264. }
  265. InitFromProfile();
  266. // And make sure that we load our UA sheets. No need to do this
  267. // per-profile, since they're profile-invariant.
  268. LoadSheetURL("resource://gre-resources/counterstyles.css",
  269. &mCounterStylesSheet, eAgentSheetFeatures, eCrash);
  270. LoadSheetURL("chrome://global/content/minimal-xul.css",
  271. &mMinimalXULSheet, eAgentSheetFeatures, eCrash);
  272. LoadSheetURL("resource://gre-resources/quirk.css",
  273. &mQuirkSheet, eAgentSheetFeatures, eCrash);
  274. LoadSheetURL("resource://gre/res/svg.css",
  275. &mSVGSheet, eAgentSheetFeatures, eCrash);
  276. LoadSheetURL("chrome://global/content/xul.css",
  277. &mXULSheet, eAgentSheetFeatures, eCrash);
  278. if (gUserContentSheetURL) {
  279. MOZ_ASSERT(XRE_IsContentProcess(), "Only used in content processes.");
  280. LoadSheet(gUserContentSheetURL, &mUserContentSheet, eUserSheetFeatures, eLogToConsole);
  281. gUserContentSheetURL = nullptr;
  282. }
  283. // The remaining sheets are created on-demand do to their use being rarer
  284. // (which helps save memory for Firefox OS apps) or because they need to
  285. // be re-loadable in DependentPrefChanged.
  286. }
  287. nsLayoutStylesheetCache::~nsLayoutStylesheetCache()
  288. {
  289. mozilla::UnregisterWeakMemoryReporter(this);
  290. }
  291. void
  292. nsLayoutStylesheetCache::InitMemoryReporter()
  293. {
  294. mozilla::RegisterWeakMemoryReporter(this);
  295. }
  296. /* static */ nsLayoutStylesheetCache*
  297. nsLayoutStylesheetCache::For(StyleBackendType aType)
  298. {
  299. MOZ_ASSERT(NS_IsMainThread());
  300. bool mustInit = !gStyleCache_Gecko && !gStyleCache_Servo;
  301. auto& cache = aType == StyleBackendType::Gecko ? gStyleCache_Gecko :
  302. gStyleCache_Servo;
  303. if (!cache) {
  304. cache = new nsLayoutStylesheetCache(aType);
  305. cache->InitMemoryReporter();
  306. }
  307. if (mustInit) {
  308. // Initialization that only needs to be done once for both
  309. // nsLayoutStylesheetCaches.
  310. Preferences::AddBoolVarCache(&sNumberControlEnabled, NUMBER_CONTROL_PREF,
  311. true);
  312. // For each pref that controls a CSS feature that a UA style sheet depends
  313. // on (such as a pref that enables a property that a UA style sheet uses),
  314. // register DependentPrefChanged as a callback to ensure that the relevant
  315. // style sheets will be re-parsed.
  316. // Preferences::RegisterCallback(&DependentPrefChanged,
  317. // "layout.css.example-pref.enabled");
  318. Preferences::RegisterCallback(&DependentPrefChanged,
  319. "layout.css.grid.enabled");
  320. Preferences::RegisterCallback(&DependentPrefChanged,
  321. "dom.details_element.enabled");
  322. }
  323. return cache;
  324. }
  325. void
  326. nsLayoutStylesheetCache::InitFromProfile()
  327. {
  328. nsCOMPtr<nsIXULRuntime> appInfo = do_GetService("@mozilla.org/xre/app-info;1");
  329. if (appInfo) {
  330. bool inSafeMode = false;
  331. appInfo->GetInSafeMode(&inSafeMode);
  332. if (inSafeMode)
  333. return;
  334. }
  335. nsCOMPtr<nsIFile> contentFile;
  336. nsCOMPtr<nsIFile> chromeFile;
  337. NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR,
  338. getter_AddRefs(contentFile));
  339. if (!contentFile) {
  340. // if we don't have a profile yet, that's OK!
  341. return;
  342. }
  343. contentFile->Clone(getter_AddRefs(chromeFile));
  344. if (!chromeFile) return;
  345. contentFile->Append(NS_LITERAL_STRING("userContent.css"));
  346. chromeFile->Append(NS_LITERAL_STRING("userChrome.css"));
  347. LoadSheetFile(contentFile, &mUserContentSheet, eUserSheetFeatures, eLogToConsole);
  348. LoadSheetFile(chromeFile, &mUserChromeSheet, eUserSheetFeatures, eLogToConsole);
  349. }
  350. void
  351. nsLayoutStylesheetCache::LoadSheetURL(const char* aURL,
  352. RefPtr<StyleSheet>* aSheet,
  353. SheetParsingMode aParsingMode,
  354. FailureAction aFailureAction)
  355. {
  356. nsCOMPtr<nsIURI> uri;
  357. NS_NewURI(getter_AddRefs(uri), aURL);
  358. LoadSheet(uri, aSheet, aParsingMode, aFailureAction);
  359. if (!aSheet) {
  360. NS_ERROR(nsPrintfCString("Could not load %s", aURL).get());
  361. }
  362. }
  363. void
  364. nsLayoutStylesheetCache::LoadSheetFile(nsIFile* aFile,
  365. RefPtr<StyleSheet>* aSheet,
  366. SheetParsingMode aParsingMode,
  367. FailureAction aFailureAction)
  368. {
  369. bool exists = false;
  370. aFile->Exists(&exists);
  371. if (!exists) return;
  372. nsCOMPtr<nsIURI> uri;
  373. NS_NewFileURI(getter_AddRefs(uri), aFile);
  374. LoadSheet(uri, aSheet, aParsingMode, aFailureAction);
  375. }
  376. static void
  377. ErrorLoadingSheet(nsIURI* aURI, const char* aMsg, FailureAction aFailureAction)
  378. {
  379. nsPrintfCString errorMessage("%s loading built-in stylesheet '%s'",
  380. aMsg,
  381. aURI ? aURI->GetSpecOrDefault().get() : "");
  382. if (aFailureAction == eLogToConsole) {
  383. nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
  384. if (cs) {
  385. cs->LogStringMessage(NS_ConvertUTF8toUTF16(errorMessage).get());
  386. return;
  387. }
  388. }
  389. NS_RUNTIMEABORT(errorMessage.get());
  390. }
  391. void
  392. nsLayoutStylesheetCache::LoadSheet(nsIURI* aURI,
  393. RefPtr<StyleSheet>* aSheet,
  394. SheetParsingMode aParsingMode,
  395. FailureAction aFailureAction)
  396. {
  397. if (!aURI) {
  398. ErrorLoadingSheet(aURI, "null URI", eCrash);
  399. return;
  400. }
  401. auto& loader = mBackendType == StyleBackendType::Gecko ?
  402. gCSSLoader_Gecko :
  403. gCSSLoader_Servo;
  404. if (!loader) {
  405. loader = new mozilla::css::Loader(mBackendType);
  406. if (!loader) {
  407. ErrorLoadingSheet(aURI, "no Loader", eCrash);
  408. return;
  409. }
  410. }
  411. nsresult rv = loader->LoadSheetSync(aURI, aParsingMode, true, aSheet);
  412. if (NS_FAILED(rv)) {
  413. ErrorLoadingSheet(aURI,
  414. nsPrintfCString("LoadSheetSync failed with error %x", rv).get(),
  415. aFailureAction);
  416. }
  417. }
  418. /* static */ void
  419. nsLayoutStylesheetCache::InvalidateSheet(RefPtr<StyleSheet>* aGeckoSheet,
  420. RefPtr<StyleSheet>* aServoSheet)
  421. {
  422. MOZ_ASSERT(gCSSLoader_Gecko || gCSSLoader_Servo,
  423. "pref changed before we loaded a sheet?");
  424. const bool gotGeckoSheet = aGeckoSheet && *aGeckoSheet;
  425. const bool gotServoSheet = aServoSheet && *aServoSheet;
  426. // Make sure sheets have the expected types
  427. MOZ_ASSERT(!gotGeckoSheet || (*aGeckoSheet)->IsGecko());
  428. MOZ_ASSERT(!gotServoSheet || (*aServoSheet)->IsServo());
  429. // Make sure the URIs match
  430. MOZ_ASSERT(!gotServoSheet || !gotGeckoSheet ||
  431. (*aGeckoSheet)->GetSheetURI() == (*aServoSheet)->GetSheetURI(),
  432. "Sheets passed should have the same URI");
  433. nsIURI* uri;
  434. if (gotGeckoSheet) {
  435. uri = (*aGeckoSheet)->GetSheetURI();
  436. } else if (gotServoSheet) {
  437. uri = (*aServoSheet)->GetSheetURI();
  438. } else {
  439. return;
  440. }
  441. if (gCSSLoader_Gecko) {
  442. gCSSLoader_Gecko->ObsoleteSheet(uri);
  443. }
  444. if (gCSSLoader_Servo) {
  445. gCSSLoader_Servo->ObsoleteSheet(uri);
  446. }
  447. if (gotGeckoSheet) {
  448. *aGeckoSheet = nullptr;
  449. }
  450. if (gotServoSheet) {
  451. *aServoSheet = nullptr;
  452. }
  453. }
  454. /* static */ void
  455. nsLayoutStylesheetCache::DependentPrefChanged(const char* aPref, void* aData)
  456. {
  457. MOZ_ASSERT(gStyleCache_Gecko || gStyleCache_Servo,
  458. "pref changed after shutdown?");
  459. // Cause any UA style sheets whose parsing depends on the value of prefs
  460. // to be re-parsed by dropping the sheet from gCSSLoader_{Gecko,Servo}'s cache
  461. // then setting our cached sheet pointer to null. This will only work for
  462. // sheets that are loaded lazily.
  463. #define INVALIDATE(sheet_) \
  464. InvalidateSheet(gStyleCache_Gecko ? &gStyleCache_Gecko->sheet_ : nullptr, \
  465. gStyleCache_Servo ? &gStyleCache_Servo->sheet_ : nullptr);
  466. INVALIDATE(mUASheet); // for layout.css.grid.enabled
  467. INVALIDATE(mHTMLSheet); // for dom.details_element.enabled
  468. #undef INVALIDATE
  469. }
  470. /* static */ void
  471. nsLayoutStylesheetCache::InvalidatePreferenceSheets()
  472. {
  473. if (gStyleCache_Gecko) {
  474. gStyleCache_Gecko->mContentPreferenceSheet = nullptr;
  475. gStyleCache_Gecko->mChromePreferenceSheet = nullptr;
  476. }
  477. if (gStyleCache_Servo) {
  478. gStyleCache_Servo->mContentPreferenceSheet = nullptr;
  479. gStyleCache_Servo->mChromePreferenceSheet = nullptr;
  480. }
  481. }
  482. void
  483. nsLayoutStylesheetCache::BuildPreferenceSheet(RefPtr<StyleSheet>* aSheet,
  484. nsPresContext* aPresContext)
  485. {
  486. if (mBackendType == StyleBackendType::Gecko) {
  487. *aSheet = new CSSStyleSheet(eAgentSheetFeatures, CORS_NONE,
  488. mozilla::net::RP_Default);
  489. } else {
  490. *aSheet = new ServoStyleSheet(eAgentSheetFeatures, CORS_NONE,
  491. mozilla::net::RP_Default, dom::SRIMetadata());
  492. }
  493. StyleSheet* sheet = *aSheet;
  494. nsCOMPtr<nsIURI> uri;
  495. NS_NewURI(getter_AddRefs(uri), "about:PreferenceStyleSheet", nullptr);
  496. MOZ_ASSERT(uri, "URI creation shouldn't fail");
  497. sheet->SetURIs(uri, uri, uri);
  498. sheet->SetComplete();
  499. static const uint32_t kPreallocSize = 1024;
  500. nsString sheetText;
  501. sheetText.SetCapacity(kPreallocSize);
  502. #define NS_GET_R_G_B(color_) \
  503. NS_GET_R(color_), NS_GET_G(color_), NS_GET_B(color_)
  504. sheetText.AppendLiteral(
  505. "@namespace url(http://www.w3.org/1999/xhtml);\n"
  506. "@namespace svg url(http://www.w3.org/2000/svg);\n");
  507. // Rules for link styling.
  508. nscolor linkColor = aPresContext->DefaultLinkColor();
  509. nscolor activeColor = aPresContext->DefaultActiveLinkColor();
  510. nscolor visitedColor = aPresContext->DefaultVisitedLinkColor();
  511. sheetText.AppendPrintf(
  512. "*|*:link { color: #%02x%02x%02x; }\n"
  513. "*|*:any-link:active { color: #%02x%02x%02x; }\n"
  514. "*|*:visited { color: #%02x%02x%02x; }\n",
  515. NS_GET_R_G_B(linkColor),
  516. NS_GET_R_G_B(activeColor),
  517. NS_GET_R_G_B(visitedColor));
  518. bool underlineLinks =
  519. aPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
  520. sheetText.AppendPrintf(
  521. "*|*:any-link%s { text-decoration: %s; }\n",
  522. underlineLinks ? ":not(svg|a)" : "",
  523. underlineLinks ? "underline" : "none");
  524. // Rules for focus styling.
  525. bool focusRingOnAnything = aPresContext->GetFocusRingOnAnything();
  526. uint8_t focusRingWidth = aPresContext->FocusRingWidth();
  527. uint8_t focusRingStyle = aPresContext->GetFocusRingStyle();
  528. if ((focusRingWidth != 1 && focusRingWidth <= 4) || focusRingOnAnything) {
  529. if (focusRingWidth != 1) {
  530. // If the focus ring width is different from the default, fix buttons
  531. // with rings.
  532. sheetText.AppendPrintf(
  533. "button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner, "
  534. "input[type=\"button\"]::-moz-focus-inner, "
  535. "input[type=\"submit\"]::-moz-focus-inner { "
  536. "padding: 1px 2px 1px 2px; "
  537. "border: %dpx %s transparent !important; }\n",
  538. focusRingWidth,
  539. focusRingStyle == 0 ? "solid" : "dotted");
  540. sheetText.AppendLiteral(
  541. "button:focus::-moz-focus-inner, "
  542. "input[type=\"reset\"]:focus::-moz-focus-inner, "
  543. "input[type=\"button\"]:focus::-moz-focus-inner, "
  544. "input[type=\"submit\"]:focus::-moz-focus-inner { "
  545. "border-color: ButtonText !important; }\n");
  546. }
  547. sheetText.AppendPrintf(
  548. "%s { outline: %dpx %s !important; %s}\n",
  549. focusRingOnAnything ?
  550. ":focus" :
  551. "*|*:link:focus, *|*:visited:focus",
  552. focusRingWidth,
  553. focusRingStyle == 0 ? // solid
  554. "solid -moz-mac-focusring" : "dotted WindowText",
  555. focusRingStyle == 0 ? // solid
  556. "-moz-outline-radius: 3px; outline-offset: 1px; " : "");
  557. }
  558. if (aPresContext->GetUseFocusColors()) {
  559. nscolor focusText = aPresContext->FocusTextColor();
  560. nscolor focusBG = aPresContext->FocusBackgroundColor();
  561. sheetText.AppendPrintf(
  562. "*:focus, *:focus > font { color: #%02x%02x%02x !important; "
  563. "background-color: #%02x%02x%02x !important; }\n",
  564. NS_GET_R_G_B(focusText),
  565. NS_GET_R_G_B(focusBG));
  566. }
  567. NS_ASSERTION(sheetText.Length() <= kPreallocSize,
  568. "kPreallocSize should be big enough to build preference style "
  569. "sheet without reallocation");
  570. if (sheet->IsGecko()) {
  571. sheet->AsGecko()->ReparseSheet(sheetText);
  572. } else {
  573. nsresult rv = sheet->AsServo()->ParseSheet(sheetText, uri, uri, nullptr, 0);
  574. // Parsing the about:PreferenceStyleSheet URI can only fail on OOM. If we
  575. // are OOM before we parsed any documents we might as well abort.
  576. MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
  577. }
  578. #undef NS_GET_R_G_B
  579. }
  580. mozilla::StaticRefPtr<nsLayoutStylesheetCache>
  581. nsLayoutStylesheetCache::gStyleCache_Gecko;
  582. mozilla::StaticRefPtr<nsLayoutStylesheetCache>
  583. nsLayoutStylesheetCache::gStyleCache_Servo;
  584. mozilla::StaticRefPtr<mozilla::css::Loader>
  585. nsLayoutStylesheetCache::gCSSLoader_Gecko;
  586. mozilla::StaticRefPtr<mozilla::css::Loader>
  587. nsLayoutStylesheetCache::gCSSLoader_Servo;
  588. mozilla::StaticRefPtr<nsIURI>
  589. nsLayoutStylesheetCache::gUserContentSheetURL;