summaryrefslogtreecommitdiffstats
path: root/layout/style/SheetLoadData.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--layout/style/SheetLoadData.h293
1 files changed, 293 insertions, 0 deletions
diff --git a/layout/style/SheetLoadData.h b/layout/style/SheetLoadData.h
new file mode 100644
index 0000000000..f261adcc6d
--- /dev/null
+++ b/layout/style/SheetLoadData.h
@@ -0,0 +1,293 @@
+/* -*- 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
+ * 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
+
+#include "mozilla/css/Loader.h"
+#include "mozilla/css/SheetParsingMode.h"
+#include "mozilla/Encoding.h"
+#include "mozilla/PreloaderBase.h"
+#include "mozilla/SharedSubResourceCache.h"
+#include "mozilla/NotNull.h"
+#include "mozilla/UniquePtr.h"
+#include "nsIThreadInternal.h"
+#include "nsProxyRelease.h"
+
+namespace mozilla {
+class StyleSheet;
+}
+class nsICSSLoaderObserver;
+class nsINode;
+class nsIPrincipal;
+class nsIURI;
+class nsIReferrerInfo;
+
+namespace mozilla::css {
+
+/*********************************************
+ * Data needed to properly load a stylesheet *
+ *********************************************/
+
+static_assert(eAuthorSheetFeatures == 0 && eUserSheetFeatures == 1 &&
+ eAgentSheetFeatures == 2,
+ "sheet parsing mode constants won't fit "
+ "in SheetLoadData::mParsingMode");
+
+class SheetLoadData final
+ : public PreloaderBase,
+ public SharedSubResourceCacheLoadingValueBase<SheetLoadData>,
+ public nsIRunnable,
+ public nsIThreadObserver {
+ using MediaMatched = dom::LinkStyle::MediaMatched;
+ using IsAlternate = dom::LinkStyle::IsAlternate;
+ using UseSystemPrincipal = css::Loader::UseSystemPrincipal;
+
+ protected:
+ virtual ~SheetLoadData();
+
+ public:
+ // PreloaderBase
+ static void PrioritizeAsPreload(nsIChannel* aChannel);
+ void PrioritizeAsPreload() final;
+
+ // If this is a deferred load, start it now.
+ void StartPendingLoad();
+
+ // Data for loading a sheet linked from a document
+ SheetLoadData(css::Loader* aLoader, const nsAString& aTitle, nsIURI* aURI,
+ StyleSheet* aSheet, bool aSyncLoad, nsINode* aOwningNode,
+ IsAlternate aIsAlternate, MediaMatched aMediaMatched,
+ StylePreloadKind aPreloadKind, nsICSSLoaderObserver* aObserver,
+ nsIPrincipal* aTriggeringPrincipal,
+ nsIReferrerInfo* aReferrerInfo);
+
+ // Data for loading a sheet linked from an @import rule
+ SheetLoadData(css::Loader* aLoader, nsIURI* aURI, StyleSheet* aSheet,
+ SheetLoadData* aParentData, nsICSSLoaderObserver* aObserver,
+ nsIPrincipal* aTriggeringPrincipal,
+ nsIReferrerInfo* aReferrerInfo);
+
+ // Data for loading a non-document sheet
+ SheetLoadData(css::Loader* aLoader, nsIURI* aURI, StyleSheet* aSheet,
+ bool aSyncLoad, UseSystemPrincipal, StylePreloadKind,
+ const Encoding* aPreloadEncoding,
+ nsICSSLoaderObserver* aObserver,
+ nsIPrincipal* aTriggeringPrincipal,
+ nsIReferrerInfo* aReferrerInfo);
+
+ nsIReferrerInfo* ReferrerInfo() const { return mReferrerInfo; }
+
+ void ScheduleLoadEventIfNeeded();
+
+ NotNull<const Encoding*> DetermineNonBOMEncoding(const nsACString& aSegment,
+ nsIChannel*) const;
+
+ // The caller may have the bytes for the stylesheet split across two strings,
+ // so aBytes1 and aBytes2 refer to those pieces.
+ nsresult VerifySheetReadyToParse(nsresult aStatus, const nsACString& aBytes1,
+ const nsACString& aBytes2,
+ nsIChannel* aChannel);
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIRUNNABLE
+ NS_DECL_NSITHREADOBSERVER
+
+ css::Loader& Loader() { return *mLoader; }
+
+ void DidCancelLoad() { mIsCancelled = true; }
+
+ // Hold a ref to the CSSLoader so we can call back to it to let it
+ // know the load finished
+ const RefPtr<css::Loader> mLoader;
+
+ // Title needed to pull datas out of the pending datas table when
+ // the preferred title is changed
+ const nsString mTitle;
+
+ // The encoding we decided to use for the sheet
+ const Encoding* mEncoding;
+
+ // URI we're loading. Null for inline or constructable sheets.
+ nsCOMPtr<nsIURI> mURI;
+
+ // Should be 1 for non-inline sheets.
+ uint32_t mLineNumber;
+
+ // The sheet we're loading data for
+ const RefPtr<StyleSheet> mSheet;
+
+ // Load data for the sheet that @import-ed us if we were @import-ed
+ // during the parse
+ const RefPtr<SheetLoadData> mParentData;
+
+ // The expiration time of the channel that has loaded this data, if
+ // applicable.
+ uint32_t mExpirationTime = 0;
+
+ // Number of sheets we @import-ed that are still loading
+ uint32_t mPendingChildren;
+
+ // mSyncLoad is true when the load needs to be synchronous.
+ // For LoadSheetSync, <link> to chrome stylesheets in UA Widgets,
+ // and children of sync loads.
+ const bool mSyncLoad : 1;
+
+ // 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.
+ const bool mIsNonDocumentSheet : 1;
+
+ // Whether this stylesheet is for a child sheet load. This is necessary
+ // because the sheet could be detached mid-load by CSSOM.
+ const bool mIsChildSheet : 1;
+
+ // mIsBeingParsed is true if this stylesheet is currently being parsed.
+ bool mIsBeingParsed : 1;
+
+ // mIsLoading is set to true when a sheet load is initiated. This field is
+ // also used by the SharedSubResourceCache to avoid having multiple loads for
+ // the same resource.
+ bool mIsLoading : 1;
+
+ // 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
+ // mOwningNodeBeforeLoadEvent.
+ bool mMustNotify : 1;
+
+ // mWasAlternate is true if the sheet was an alternate when the load data was
+ // created.
+ const bool mWasAlternate : 1;
+
+ // mMediaMatched is true if the sheet matched its medialist when the load data
+ // was created.
+ const bool mMediaMatched : 1;
+
+ // 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.
+ const bool mUseSystemPrincipal : 1;
+
+ // If true, this SheetLoadData is being used as a way to handle
+ // async observer notification for an already-complete sheet.
+ bool mSheetAlreadyComplete : 1;
+
+ // 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;
+
+ // 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;
+
+ // Whether this is a preload, and which kind of preload it is.
+ //
+ // 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 StylePreloadKind mPreloadKind;
+
+ // This is the node that imported the sheet. Cleared after the load/error
+ // event fires, as we don't need it anymore. Needed to get the charset on it,
+ // and to fire load/error events. Must implement LinkStyle.
+ //
+ // This is only set for top-level sheets (e.g., for an @import-ed sheet it'll
+ // be null).
+ nsCOMPtr<nsINode> mOwningNodeBeforeLoadEvent;
+
+ nsINode* GetRequestingNode() const;
+
+ // The observer that wishes to be notified of load completion
+ nsCOMPtr<nsICSSLoaderObserver> mObserver;
+
+ // The principal that identifies who started loading us.
+ const nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
+
+ // Referrer info of the load.
+ const nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
+
+ // The encoding guessed from attributes and the document character set.
+ const NotNull<const Encoding*> mGuessedEncoding;
+
+ // The quirks mode of the loader at the time the load was triggered.
+ const nsCompatibility mCompatMode;
+
+ // Whether SheetComplete was called.
+ bool mSheetCompleteCalled = false;
+ // Whether we intentionally are not calling SheetComplete because nobody is
+ // listening for the load.
+ bool mIntentionallyDropped = false;
+
+ bool ShouldDefer() const { return mWasAlternate || !mMediaMatched; }
+
+ RefPtr<StyleSheet> ValueForCache() const;
+ uint32_t ExpirationTime() const { return mExpirationTime; }
+
+ // 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);
+ }
+ }
+
+ bool IsPreload() const { return mPreloadKind != StylePreloadKind::None; }
+ bool IsLinkRelPreload() const { return css::IsLinkRelPreload(mPreloadKind); }
+
+ bool BlocksLoadEvent() const { return !RootLoadData().IsLinkRelPreload(); }
+
+ bool IsSyncLoad() const override { return mSyncLoad; }
+ bool IsLoading() const override { return mIsLoading; }
+ bool IsCancelled() const override { return mIsCancelled; }
+
+ void StartLoading() override { mIsLoading = true; }
+ void SetLoadCompleted() override { mIsLoading = false; }
+ void Cancel() override { mIsCancelled = true; }
+
+ private:
+ const SheetLoadData& RootLoadData() const {
+ auto* top = this;
+ while (top->mParentData) {
+ top = top->mParentData;
+ }
+ return *top;
+ }
+
+ void FireLoadEvent(nsIThreadInternal* aThread);
+};
+
+using SheetLoadDataHolder = nsMainThreadPtrHolder<SheetLoadData>;
+
+} // namespace mozilla::css
+
+/**
+ * Casting SheetLoadData to nsISupports is ambiguous.
+ * This method handles that.
+ */
+inline nsISupports* ToSupports(mozilla::css::SheetLoadData* p) {
+ return NS_ISUPPORTS_CAST(nsIRunnable*, p);
+}
+
+#endif // mozilla_css_SheetLoadData_h