diff options
Diffstat (limited to 'layout/style/SheetLoadData.h')
-rw-r--r-- | layout/style/SheetLoadData.h | 293 |
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 |