/* 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/dom/StylePropertyMapReadOnly.h" #include "CSSUnsupportedValue.h" #include "mozilla/Assertions.h" #include "mozilla/ComputedStyle.h" #include "mozilla/DeclarationBlock.h" #include "mozilla/ErrorResult.h" #include "mozilla/RefPtr.h" #include "mozilla/ServoStyleConsts.h" #include "mozilla/dom/CSSStyleRule.h" #include "mozilla/dom/CSSStyleValue.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/StylePropertyMapReadOnlyBinding.h" #include "nsCSSProps.h" #include "nsComputedDOMStyle.h" #include "nsCycleCollectionParticipant.h" #include "nsReadableUtils.h" namespace mozilla::dom { namespace { template struct DeclarationTraits; // Specialization for inline style (specified values) struct InlineStyleDeclarations {}; template <> struct DeclarationTraits { static StylePropertyTypedValue Get(Element* aElement, const nsACString& aProperty, ErrorResult& aRv) { MOZ_ASSERT(aElement); auto value = StylePropertyTypedValue::None(); RefPtr block = aElement->GetInlineStyleDeclaration(); if (!block) { return value; } if (!block->GetPropertyTypedValue(aProperty, value)) { return value; } return value; } }; // Specialization for computed style (computed values) struct ComputedStyleDeclarations {}; template <> struct DeclarationTraits { static StylePropertyTypedValue Get(Element* aElement, const nsACString& aProperty, ErrorResult& aRv) { MOZ_ASSERT(aElement); auto value = StylePropertyTypedValue::None(); RefPtr style = nsComputedDOMStyle::GetComputedStyle(aElement); if (!style) { return value; } if (!style->GetPropertyTypedValue(aProperty, value)) { return value; } return value; } }; // Specialization for style rule struct StyleRuleDeclarations {}; template <> struct DeclarationTraits { static StylePropertyTypedValue Get(const CSSStyleRule* aRule, const nsACString& aProperty, ErrorResult& aRv) { MOZ_ASSERT(aRule); auto value = StylePropertyTypedValue::None(); if (!aRule->GetDeclarationBlock().GetPropertyTypedValue(aProperty, value)) { return value; } return value; } }; } // namespace StylePropertyMapReadOnly::StylePropertyMapReadOnly(Element* aElement, bool aComputed) : mParent(aElement), mDeclarations(aElement, aComputed) { MOZ_ASSERT(mParent); } StylePropertyMapReadOnly::StylePropertyMapReadOnly(CSSStyleRule* aRule) : mParent(aRule), mDeclarations(aRule) { MOZ_ASSERT(mParent); } NS_IMPL_CYCLE_COLLECTING_ADDREF(StylePropertyMapReadOnly) NS_IMPL_CYCLE_COLLECTING_RELEASE(StylePropertyMapReadOnly) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StylePropertyMapReadOnly) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(StylePropertyMapReadOnly) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(StylePropertyMapReadOnly) // Clear out our weak pointers. tmp->mDeclarations.Unlink(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(StylePropertyMapReadOnly) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END nsISupports* StylePropertyMapReadOnly::GetParentObject() const { return mParent; } JSObject* StylePropertyMapReadOnly::WrapObject( JSContext* aCx, JS::Handle aGivenProto) { return StylePropertyMapReadOnly_Binding::Wrap(aCx, this, aGivenProto); } // start of StylePropertyMapReadOnly Web IDL implementation // https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-get // // XXX This is not yet fully implemented and optimized! void StylePropertyMapReadOnly::Get(const nsACString& aProperty, OwningUndefinedOrCSSStyleValue& aRetVal, ErrorResult& aRv) const { if (!mParent) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } // Step 2. NonCustomCSSPropertyId id = nsCSSProps::LookupProperty(aProperty); if (id == eCSSProperty_UNKNOWN) { aRv.ThrowTypeError("Invalid property: "_ns + aProperty); return; } // Step 3. const Declarations& declarations = mDeclarations; // Step 4. auto value = declarations.Get(aProperty, aRv); if (aRv.Failed()) { return; } RefPtr styleValue = CSSStyleValue::Create( mParent, CSSPropertyId::FromIdOrCustomProperty(id, aProperty), std::move(value)); if (styleValue) { aRetVal.SetAsCSSStyleValue() = std::move(styleValue); } else { aRetVal.SetUndefined(); } } // https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-getall // // XXX This is not yet fully implemented and optimized! void StylePropertyMapReadOnly::GetAll(const nsACString& aProperty, nsTArray>& aRetVal, ErrorResult& aRv) const { OwningUndefinedOrCSSStyleValue retVal; Get(aProperty, retVal, aRv); if (aRv.Failed()) { return; } if (retVal.IsCSSStyleValue()) { auto styleValue = retVal.GetAsCSSStyleValue(); aRetVal.AppendElement(styleValue); } } bool StylePropertyMapReadOnly::Has(const nsACString& aProperty, ErrorResult& aRv) const { aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); return false; } uint32_t StylePropertyMapReadOnly::Size() const { return 0; } uint32_t StylePropertyMapReadOnly::GetIterableLength() const { return 0; } const nsACString& StylePropertyMapReadOnly::GetKeyAtIndex( uint32_t aIndex) const { return EmptyCString(); } nsTArray> StylePropertyMapReadOnly::GetValueAtIndex( uint32_t aIndex) const { return nsTArray>(); } // end of StylePropertyMapReadOnly Web IDL implementation size_t StylePropertyMapReadOnly::SizeOfExcludingThis( MallocSizeOf aMallocSizeOf) const { return 0; } size_t StylePropertyMapReadOnly::SizeOfIncludingThis( MallocSizeOf aMallocSizeOf) const { return SizeOfExcludingThis(aMallocSizeOf) + aMallocSizeOf(this); } StylePropertyTypedValue StylePropertyMapReadOnly::Declarations::Get( const nsACString& aProperty, ErrorResult& aRv) const { switch (mKind) { case Kind::Inline: return DeclarationTraits::Get(mElement, aProperty, aRv); case Kind::Computed: return DeclarationTraits::Get(mElement, aProperty, aRv); case Kind::Rule: return DeclarationTraits::Get(mRule, aProperty, aRv); } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad kind value!"); } void StylePropertyMapReadOnly::Declarations::Unlink() { switch (mKind) { case Kind::Inline: case Kind::Computed: mElement = nullptr; break; case Kind::Rule: mRule = nullptr; break; } } } // namespace mozilla::dom