summaryrefslogtreecommitdiffstats
path: root/layout/style/StyleSheet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/style/StyleSheet.cpp')
-rw-r--r--layout/style/StyleSheet.cpp329
1 files changed, 329 insertions, 0 deletions
diff --git a/layout/style/StyleSheet.cpp b/layout/style/StyleSheet.cpp
new file mode 100644
index 000000000..9ff90b8d2
--- /dev/null
+++ b/layout/style/StyleSheet.cpp
@@ -0,0 +1,329 @@
+/* -*- 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/. */
+
+#include "mozilla/StyleSheet.h"
+
+#include "mozilla/dom/CSSRuleList.h"
+#include "mozilla/dom/ShadowRoot.h"
+#include "mozilla/ServoStyleSheet.h"
+#include "mozilla/StyleSheetInlines.h"
+#include "mozilla/CSSStyleSheet.h"
+
+#include "nsNullPrincipal.h"
+
+namespace mozilla {
+
+StyleSheet::StyleSheet(StyleBackendType aType, css::SheetParsingMode aParsingMode)
+ : mDocument(nullptr)
+ , mOwningNode(nullptr)
+ , mParsingMode(aParsingMode)
+ , mType(aType)
+ , mDisabled(false)
+{
+}
+
+StyleSheet::StyleSheet(const StyleSheet& aCopy,
+ nsIDocument* aDocumentToUse,
+ nsINode* aOwningNodeToUse)
+ : mTitle(aCopy.mTitle)
+ , mDocument(aDocumentToUse)
+ , mOwningNode(aOwningNodeToUse)
+ , mParsingMode(aCopy.mParsingMode)
+ , mType(aCopy.mType)
+ , mDisabled(aCopy.mDisabled)
+{
+}
+
+// QueryInterface implementation for StyleSheet
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheet)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheet)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleSheet)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheet)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(StyleSheet)
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(StyleSheet)
+
+mozilla::dom::CSSStyleSheetParsingMode
+StyleSheet::ParsingModeDOM()
+{
+#define CHECK(X, Y) \
+ static_assert(static_cast<int>(X) == static_cast<int>(Y), \
+ "mozilla::dom::CSSStyleSheetParsingMode and mozilla::css::SheetParsingMode should have identical values");
+
+ CHECK(mozilla::dom::CSSStyleSheetParsingMode::Agent, css::eAgentSheetFeatures);
+ CHECK(mozilla::dom::CSSStyleSheetParsingMode::User, css::eUserSheetFeatures);
+ CHECK(mozilla::dom::CSSStyleSheetParsingMode::Author, css::eAuthorSheetFeatures);
+
+#undef CHECK
+
+ return static_cast<mozilla::dom::CSSStyleSheetParsingMode>(mParsingMode);
+}
+
+bool
+StyleSheet::IsComplete() const
+{
+ return SheetInfo().mComplete;
+}
+
+void
+StyleSheet::SetComplete()
+{
+ NS_ASSERTION(!IsGecko() || !AsGecko()->mDirty,
+ "Can't set a dirty sheet complete!");
+ SheetInfo().mComplete = true;
+ if (mDocument && !mDisabled) {
+ // Let the document know
+ mDocument->BeginUpdate(UPDATE_STYLE);
+ mDocument->SetStyleSheetApplicableState(this, true);
+ mDocument->EndUpdate(UPDATE_STYLE);
+ }
+
+ if (mOwningNode && !mDisabled &&
+ mOwningNode->HasFlag(NODE_IS_IN_SHADOW_TREE) &&
+ mOwningNode->IsContent()) {
+ dom::ShadowRoot* shadowRoot = mOwningNode->AsContent()->GetContainingShadow();
+ shadowRoot->StyleSheetChanged();
+ }
+}
+
+StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode,
+ ReferrerPolicy aReferrerPolicy,
+ const dom::SRIMetadata& aIntegrity)
+ : mPrincipal(nsNullPrincipal::Create())
+ , mCORSMode(aCORSMode)
+ , mReferrerPolicy(aReferrerPolicy)
+ , mIntegrity(aIntegrity)
+ , mComplete(false)
+#ifdef DEBUG
+ , mPrincipalSet(false)
+#endif
+{
+ if (!mPrincipal) {
+ NS_RUNTIMEABORT("nsNullPrincipal::Init failed");
+ }
+}
+
+// nsIDOMStyleSheet interface
+
+NS_IMETHODIMP
+StyleSheet::GetType(nsAString& aType)
+{
+ aType.AssignLiteral("text/css");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+StyleSheet::GetDisabled(bool* aDisabled)
+{
+ *aDisabled = Disabled();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+StyleSheet::SetDisabled(bool aDisabled)
+{
+ // DOM method, so handle BeginUpdate/EndUpdate
+ MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_STYLE, true);
+ if (IsGecko()) {
+ AsGecko()->SetEnabled(!aDisabled);
+ } else {
+ MOZ_CRASH("stylo: unimplemented SetEnabled");
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+StyleSheet::GetOwnerNode(nsIDOMNode** aOwnerNode)
+{
+ nsCOMPtr<nsIDOMNode> ownerNode = do_QueryInterface(GetOwnerNode());
+ ownerNode.forget(aOwnerNode);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+StyleSheet::GetHref(nsAString& aHref)
+{
+ if (nsIURI* sheetURI = SheetInfo().mOriginalSheetURI) {
+ nsAutoCString str;
+ nsresult rv = sheetURI->GetSpec(str);
+ NS_ENSURE_SUCCESS(rv, rv);
+ CopyUTF8toUTF16(str, aHref);
+ } else {
+ SetDOMStringToNull(aHref);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+StyleSheet::GetTitle(nsAString& aTitle)
+{
+ aTitle.Assign(mTitle);
+ return NS_OK;
+}
+
+// nsIDOMStyleSheet interface
+
+NS_IMETHODIMP
+StyleSheet::GetParentStyleSheet(nsIDOMStyleSheet** aParentStyleSheet)
+{
+ NS_ENSURE_ARG_POINTER(aParentStyleSheet);
+ NS_IF_ADDREF(*aParentStyleSheet = GetParentStyleSheet());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+StyleSheet::GetMedia(nsIDOMMediaList** aMedia)
+{
+ NS_ADDREF(*aMedia = Media());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+StyleSheet::GetOwnerRule(nsIDOMCSSRule** aOwnerRule)
+{
+ NS_IF_ADDREF(*aOwnerRule = GetDOMOwnerRule());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+StyleSheet::GetCssRules(nsIDOMCSSRuleList** aCssRules)
+{
+ ErrorResult rv;
+ nsCOMPtr<nsIDOMCSSRuleList> rules =
+ GetCssRules(*nsContentUtils::SubjectPrincipal(), rv);
+ rules.forget(aCssRules);
+ return rv.StealNSResult();
+}
+
+NS_IMETHODIMP
+StyleSheet::InsertRule(const nsAString& aRule, uint32_t aIndex,
+ uint32_t* aReturn)
+{
+ ErrorResult rv;
+ *aReturn =
+ InsertRule(aRule, aIndex, *nsContentUtils::SubjectPrincipal(), rv);
+ return rv.StealNSResult();
+}
+
+NS_IMETHODIMP
+StyleSheet::DeleteRule(uint32_t aIndex)
+{
+ ErrorResult rv;
+ DeleteRule(aIndex, *nsContentUtils::SubjectPrincipal(), rv);
+ return rv.StealNSResult();
+}
+
+// WebIDL CSSStyleSheet API
+
+#define FORWARD_INTERNAL(method_, args_) \
+ if (IsServo()) { \
+ return AsServo()->method_ args_; \
+ } \
+ return AsGecko()->method_ args_;
+
+dom::CSSRuleList*
+StyleSheet::GetCssRules(nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv)
+{
+ if (!AreRulesAvailable(aSubjectPrincipal, aRv)) {
+ return nullptr;
+ }
+ FORWARD_INTERNAL(GetCssRulesInternal, (aRv))
+}
+
+uint32_t
+StyleSheet::InsertRule(const nsAString& aRule, uint32_t aIndex,
+ nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv)
+{
+ if (!AreRulesAvailable(aSubjectPrincipal, aRv)) {
+ return 0;
+ }
+ FORWARD_INTERNAL(InsertRuleInternal, (aRule, aIndex, aRv))
+}
+
+void
+StyleSheet::DeleteRule(uint32_t aIndex,
+ nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv)
+{
+ if (!AreRulesAvailable(aSubjectPrincipal, aRv)) {
+ return;
+ }
+ FORWARD_INTERNAL(DeleteRuleInternal, (aIndex, aRv))
+}
+
+#undef FORWARD_INTERNAL
+
+void
+StyleSheet::SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv)
+{
+ StyleSheetInfo& info = SheetInfo();
+
+ if (aSubjectPrincipal.Subsumes(info.mPrincipal)) {
+ return;
+ }
+
+ // Allow access only if CORS mode is not NONE
+ if (GetCORSMode() == CORS_NONE) {
+ aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return;
+ }
+
+ // Now make sure we set the principal of our inner to the subjectPrincipal.
+ // We do this because we're in a situation where the caller would not normally
+ // be able to access the sheet, but the sheet has opted in to being read.
+ // Unfortunately, that means it's also opted in to being _edited_, and if the
+ // caller now makes edits to the sheet we want the resulting resource loads,
+ // if any, to look as if they are coming from the caller's principal, not the
+ // original sheet principal.
+ //
+ // That means we need a unique inner, of course. But we don't want to do that
+ // if we're not complete yet. Luckily, all the callers of this method throw
+ // anyway if not complete, so we can just do that here too.
+ if (!info.mComplete) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+ return;
+ }
+
+ WillDirty();
+
+ info.mPrincipal = &aSubjectPrincipal;
+
+ DidDirty();
+}
+
+bool
+StyleSheet::AreRulesAvailable(nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv)
+{
+ // Rules are not available on incomplete sheets.
+ if (!SheetInfo().mComplete) {
+ aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+ return false;
+ }
+ //-- Security check: Only scripts whose principal subsumes that of the
+ // style sheet can access rule collections.
+ SubjectSubsumesInnerPrincipal(aSubjectPrincipal, aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return false;
+ }
+ return true;
+}
+
+// nsWrapperCache
+
+JSObject*
+StyleSheet::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return CSSStyleSheetBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace mozilla