Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : // vim:cindent:tabstop=2:expandtab:shiftwidth=2:
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 : /* a CSS style sheet returned from nsIStyleSheetService.preloadSheet */
8 :
9 : #include "PreloadedStyleSheet.h"
10 :
11 : #include "mozilla/css/Loader.h"
12 : #include "mozilla/dom/Promise.h"
13 : #include "nsICSSLoaderObserver.h"
14 : #include "nsLayoutUtils.h"
15 :
16 : namespace mozilla {
17 :
18 1 : PreloadedStyleSheet::PreloadedStyleSheet(nsIURI* aURI,
19 1 : css::SheetParsingMode aParsingMode)
20 : : mLoaded(false)
21 : , mURI(aURI)
22 1 : , mParsingMode(aParsingMode)
23 : {
24 1 : }
25 :
26 : /* static */ nsresult
27 1 : PreloadedStyleSheet::Create(nsIURI* aURI,
28 : css::SheetParsingMode aParsingMode,
29 : PreloadedStyleSheet** aResult)
30 : {
31 1 : *aResult = nullptr;
32 :
33 : RefPtr<PreloadedStyleSheet> preloadedSheet =
34 2 : new PreloadedStyleSheet(aURI, aParsingMode);
35 :
36 1 : preloadedSheet.forget(aResult);
37 2 : return NS_OK;
38 : }
39 :
40 10 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PreloadedStyleSheet)
41 9 : NS_INTERFACE_MAP_ENTRY(nsIPreloadedStyleSheet)
42 7 : NS_INTERFACE_MAP_ENTRY(nsISupports)
43 6 : NS_INTERFACE_MAP_END
44 :
45 5 : NS_IMPL_CYCLE_COLLECTING_ADDREF(PreloadedStyleSheet)
46 3 : NS_IMPL_CYCLE_COLLECTING_RELEASE(PreloadedStyleSheet)
47 :
48 0 : NS_IMPL_CYCLE_COLLECTION(PreloadedStyleSheet, mGecko, mServo)
49 :
50 : nsresult
51 2 : PreloadedStyleSheet::GetSheet(StyleBackendType aType, StyleSheet** aResult)
52 : {
53 2 : *aResult = nullptr;
54 :
55 2 : MOZ_DIAGNOSTIC_ASSERT(mLoaded);
56 :
57 : RefPtr<StyleSheet>& sheet =
58 2 : aType == StyleBackendType::Gecko ? mGecko : mServo;
59 :
60 2 : if (!sheet) {
61 2 : RefPtr<css::Loader> loader = new css::Loader(aType, nullptr);
62 1 : nsresult rv = loader->LoadSheetSync(mURI, mParsingMode, true, &sheet);
63 1 : NS_ENSURE_SUCCESS(rv, rv);
64 1 : MOZ_ASSERT(sheet);
65 : }
66 :
67 2 : *aResult = sheet;
68 2 : return NS_OK;
69 : }
70 :
71 : nsresult
72 1 : PreloadedStyleSheet::Preload()
73 : {
74 1 : MOZ_DIAGNOSTIC_ASSERT(!mLoaded);
75 :
76 : // The nsIStyleSheetService.preloadSheet API doesn't tell us which backend
77 : // the sheet will be used with, and it seems wasteful to eagerly create
78 : // both a CSSStyleSheet and a ServoStyleSheet. So instead, we guess that
79 : // the sheet type we will want matches the current value of the stylo pref,
80 : // and preload a sheet of that type.
81 : //
82 : // If we guess wrong, we will re-load the sheet later with the requested type,
83 : // and we won't really have front loaded the loading time as the name
84 : // "preload" might suggest. Also, in theory we could get different data from
85 : // fetching the URL again, but for the usage patterns of this API this is
86 : // unlikely, and it doesn't seem worth trying to store the contents of the URL
87 : // and duplicating a bunch of css::Loader's logic.
88 1 : auto type = nsLayoutUtils::StyloEnabled() ? StyleBackendType::Servo
89 1 : : StyleBackendType::Gecko;
90 :
91 1 : mLoaded = true;
92 :
93 : StyleSheet* sheet;
94 1 : return GetSheet(type, &sheet);
95 : }
96 :
97 0 : NS_IMPL_ISUPPORTS(PreloadedStyleSheet::StylesheetPreloadObserver,
98 : nsICSSLoaderObserver)
99 :
100 : NS_IMETHODIMP
101 0 : PreloadedStyleSheet::StylesheetPreloadObserver::StyleSheetLoaded(
102 : StyleSheet* aSheet, bool aWasAlternate, nsresult aStatus)
103 : {
104 0 : MOZ_DIAGNOSTIC_ASSERT(!mPreloadedSheet->mLoaded);
105 0 : mPreloadedSheet->mLoaded = true;
106 :
107 0 : if (NS_FAILED(aStatus)) {
108 0 : mPromise->MaybeReject(aStatus);
109 : } else {
110 0 : mPromise->MaybeResolve(mPreloadedSheet);
111 : }
112 :
113 0 : return NS_OK;
114 : }
115 :
116 : // Note: After calling this method, the preloaded sheet *must not* be used
117 : // until the observer is notified that the sheet has finished loading.
118 : nsresult
119 0 : PreloadedStyleSheet::PreloadAsync(NotNull<dom::Promise*> aPromise)
120 : {
121 0 : MOZ_DIAGNOSTIC_ASSERT(!mLoaded);
122 :
123 : // As with the Preload() method, we can't be sure that the sheet will only be
124 : // used with the backend that we're preloading it for now. If it's used with
125 : // a different backend later, it will be synchronously loaded for that
126 : // backend the first time it's used.
127 0 : auto type = nsLayoutUtils::StyloEnabled() ? StyleBackendType::Servo
128 0 : : StyleBackendType::Gecko;
129 :
130 : RefPtr<StyleSheet>& sheet =
131 0 : type == StyleBackendType::Gecko ? mGecko : mServo;
132 :
133 0 : RefPtr<css::Loader> loader = new css::Loader(type, nullptr);
134 :
135 : RefPtr<StylesheetPreloadObserver> obs =
136 0 : new StylesheetPreloadObserver(aPromise, this);
137 :
138 0 : return loader->LoadSheet(mURI, mParsingMode, false, obs, &sheet);
139 : }
140 :
141 : } // namespace mozilla
|