SheetLoadData.h 8.97 KB
Newer Older
1
2
3
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
4
5
6
7
8
9
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_css_SheetLoadData_h
#define mozilla_css_SheetLoadData_h

10
11
12
13
#include "mozilla/css/Loader.h"
#include "mozilla/css/SheetParsingMode.h"
#include "mozilla/Encoding.h"
#include "mozilla/NotNull.h"
14
#include "nsIThreadInternal.h"
15
#include "nsProxyRelease.h"
16

17
18
19
20
21
22
23
namespace mozilla {
class StyleSheet;
}
class nsICSSLoaderObserver;
class nsINode;
class nsIPrincipal;
class nsIURI;
24
class nsIReferrerInfo;
25

26
27
28
29
30
31
32
33
namespace mozilla {
namespace css {

/*********************************************
 * Data needed to properly load a stylesheet *
 *********************************************/

static_assert(eAuthorSheetFeatures == 0 && eUserSheetFeatures == 1 &&
34
                  eAgentSheetFeatures == 2,
35
36
37
              "sheet parsing mode constants won't fit "
              "in SheetLoadData::mParsingMode");

38
class SheetLoadData final : public nsIRunnable, public nsIThreadObserver {
39
40
  using MediaMatched = dom::LinkStyle::MediaMatched;
  using IsAlternate = dom::LinkStyle::IsAlternate;
41
42
  using IsPreload = Loader::IsPreload;
  using UseSystemPrincipal = Loader::UseSystemPrincipal;
43
44

 protected:
45
  virtual ~SheetLoadData();
46

47
 public:
48
  // Data for loading a sheet linked from a document
49
  SheetLoadData(Loader* aLoader, const nsAString& aTitle, nsIURI* aURI,
50
                StyleSheet* aSheet, bool aSyncLoad, nsINode* aOwningNode,
51
                IsAlternate aIsAlternate, MediaMatched aMediaMatched,
52
                IsPreload aIsPreload, nsICSSLoaderObserver* aObserver,
53
54
                nsIPrincipal* aTriggeringPrincipal,
                nsIReferrerInfo* aReferrerInfo, nsINode* aRequestingNode);
55
56

  // Data for loading a sheet linked from an @import rule
57
58
  SheetLoadData(Loader* aLoader, nsIURI* aURI, StyleSheet* aSheet,
                SheetLoadData* aParentData, nsICSSLoaderObserver* aObserver,
59
60
                nsIPrincipal* aTriggeringPrincipal,
                nsIReferrerInfo* aReferrerInfo, nsINode* aRequestingNode);
61
62

  // Data for loading a non-document sheet
63
  SheetLoadData(Loader* aLoader, nsIURI* aURI, StyleSheet* aSheet,
64
                bool aSyncLoad, UseSystemPrincipal, IsPreload,
65
                const Encoding* aPreloadEncoding,
66
67
                nsICSSLoaderObserver* aObserver,
                nsIPrincipal* aTriggeringPrincipal,
68
                nsIReferrerInfo* aReferrerInfo, nsINode* aRequestingNode);
69

70
  nsIReferrerInfo* ReferrerInfo() { return mReferrerInfo; }
71

72
  void ScheduleLoadEventIfNeeded();
73
74
75
76

  NotNull<const Encoding*> DetermineNonBOMEncoding(nsACString const& aSegment,
                                                   nsIChannel* aChannel);

77
78
  // The caller may have the bytes for the stylesheet split across two strings,
  // so aBytes1 and aBytes2 refer to those pieces.
79
  nsresult VerifySheetReadyToParse(nsresult aStatus, const nsACString& aBytes1,
80
                                   const nsACString& aBytes2,
81
82
83
84
85
86
87
88
                                   nsIChannel* aChannel);

  NS_DECL_ISUPPORTS
  NS_DECL_NSIRUNNABLE
  NS_DECL_NSITHREADOBSERVER

  // Hold a ref to the CSSLoader so we can call back to it to let it
  // know the load finished
89
  const RefPtr<Loader> mLoader;
90
91
92

  // Title needed to pull datas out of the pending datas table when
  // the preferred title is changed
93
  const nsString mTitle;
94
95
96
97
98
99
100
101
102
103
104

  // The encoding we decided to use for the sheet
  const Encoding* mEncoding;

  // URI we're loading.  Null for inline sheets
  nsCOMPtr<nsIURI> mURI;

  // Should be 1 for non-inline sheets.
  uint32_t mLineNumber;

  // The sheet we're loading data for
105
  const RefPtr<StyleSheet> mSheet;
106

107
108
  // Linked list of datas for the same URI as us.
  RefPtr<SheetLoadData> mNext;
109
110
111

  // Load data for the sheet that @import-ed us if we were @import-ed
  // during the parse
112
  const RefPtr<SheetLoadData> mParentData;
113
114
115
116

  // Number of sheets we @import-ed that are still loading
  uint32_t mPendingChildren;

117
118
119
  // mSyncLoad is true when the load needs to be synchronous.
  // For LoadSheetSync, <link> to chrome stylesheets in UA Widgets,
  // and children of sync loads.
120
  const bool mSyncLoad : 1;
121
122
123
124

  // mIsNonDocumentSheet is true if the load was triggered by LoadSheetSync or
  // LoadSheet or an @import from such a sheet.  Non-document sheet loads can
  // proceed even if we have no document.
125
  const bool mIsNonDocumentSheet : 1;
126
127
128
129
130
131
132

  // mIsLoading is true from the moment we are placed in the loader's
  // "loading datas" table (right after the async channel is opened)
  // to the moment we are removed from said table (due to the load
  // completing or being cancelled).
  bool mIsLoading : 1;

133
134
135
  // mIsBeingParsed is true if this stylesheet is currently being parsed.
  bool mIsBeingParsed : 1;

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  // mIsCancelled is set to true when a sheet load is stopped by
  // Stop() or StopLoadingSheet() (which was removed in Bug 556446).
  // SheetLoadData::OnStreamComplete() checks this to avoid parsing
  // sheets that have been cancelled and such.
  bool mIsCancelled : 1;

  // mMustNotify is true if the load data is being loaded async and
  // the original function call that started the load has returned.
  // This applies only to observer notifications; load/error events
  // are fired for any SheetLoadData that has a non-null
  // mOwningElement.
  bool mMustNotify : 1;

  // mWasAlternate is true if the sheet was an alternate when the load data was
  // created.
151
  const bool mWasAlternate : 1;
152

153
154
  // mMediaMatched is true if the sheet matched its medialist when the load data
  // was created.
155
  const bool mMediaMatched : 1;
156

157
158
159
  // mUseSystemPrincipal is true if the system principal should be used for
  // this sheet, no matter what the channel principal is.  Only true for sync
  // loads.
160
  const bool mUseSystemPrincipal : 1;
161
162
163
164

  // If true, this SheetLoadData is being used as a way to handle
  // async observer notification for an already-complete sheet.
  bool mSheetAlreadyComplete : 1;
165
166
167
168
169
170
171
172
173
174
175
176

  // If true, the sheet is being loaded cross-origin without CORS permissions.
  // This is completely normal and CORS isn't needed for such loads.  This
  // flag is simply useful in determining whether to set mBlockResourceTiming
  // for a child sheet.
  bool mIsCrossOriginNoCORS : 1;

  // If this flag is true, LoadSheet will call SetReportResourceTiming(false)
  // on the timedChannel. This is to mark resources that are loaded by a
  // cross-origin stylesheet with a no-cors policy.
  // https://www.w3.org/TR/resource-timing/#processing-model
  bool mBlockResourceTiming : 1;
177

178
179
180
181
  // Boolean flag indicating whether the load has failed.  This will be set
  // to true if this load, or the load of any descendant import, fails.
  bool mLoadFailed : 1;

182
  // Whether this is a preload, and which kind of preload it is.
183
184
185
186
187
  //
  // TODO(emilio): This can become a bitfield once we build with a GCC version
  // that has the fix for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414,
  // which causes a false positive warning here.
  const IsPreload mIsPreload;
188

189
190
191
  // This is the node that imported the sheet. Needed to get the charset set on
  // it, and to fire load/error events. Must implement LinkStyle.
  const nsCOMPtr<nsINode> mOwningNode;
192
193

  // The observer that wishes to be notified of load completion
194
  const nsCOMPtr<nsICSSLoaderObserver> mObserver;
195
196

  // The principal that identifies who started loading us.
197
  const nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
198

199
  // Referrer info of the load.
200
  const nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
201

202
  // The node that identifies who started loading us.
203
  const nsCOMPtr<nsINode> mRequestingNode;
204
205
206

  // The encoding to use for preloading Must be empty if mOwningElement
  // is non-null.
207
  const Encoding* const mPreloadEncoding;
208

209
210
211
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
  // Whether SheetComplete was called.
  bool mSheetCompleteCalled = false;
212
213
214
  // Whether we intentionally are not calling SheetComplete because nobody is
  // listening for the load.
  bool mIntentionallyDropped = false;
215
216
#endif

217
  bool ShouldDefer() const { return mWasAlternate || !mMediaMatched; }
218

219
220
221
222
223
224
225
226
227
228
229
  // If there are no child sheets outstanding, mark us as complete.
  // Otherwise, the children are holding strong refs to the data
  // and will call SheetComplete() on it when they complete.
  void SheetFinishedParsingAsync() {
    MOZ_ASSERT(mIsBeingParsed);
    mIsBeingParsed = false;
    if (!mPendingChildren) {
      mLoader->SheetComplete(*this, NS_OK);
    }
  }

230
231
  bool IsLinkPreload() const { return mIsPreload == IsPreload::FromLink; }

232
 private:
233
234
235
  void FireLoadEvent(nsIThreadInternal* aThread);
};

236
using SheetLoadDataHolder = nsMainThreadPtrHolder<SheetLoadData>;
237

238
239
}  // namespace css
}  // namespace mozilla
240

241
242
243
244
/**
 * Casting SheetLoadData to nsISupports is ambiguous.
 * This method handles that.
 */
245
inline nsISupports* ToSupports(mozilla::css::SheetLoadData* p) {
246
247
248
  return NS_ISUPPORTS_CAST(nsIRunnable*, p);
}

249
#endif  // mozilla_css_SheetLoadData_h