StylePropertyMapReadOnly.cpp (10378B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/dom/StylePropertyMapReadOnly.h" 8 9 #include "CSSUnsupportedValue.h" 10 #include "mozilla/Assertions.h" 11 #include "mozilla/ComputedStyle.h" 12 #include "mozilla/DeclarationBlock.h" 13 #include "mozilla/ErrorResult.h" 14 #include "mozilla/RefPtr.h" 15 #include "mozilla/ServoStyleConsts.h" 16 #include "mozilla/dom/CSSKeywordValue.h" 17 #include "mozilla/dom/CSSMathSum.h" 18 #include "mozilla/dom/CSSNumericArray.h" 19 #include "mozilla/dom/CSSStyleRule.h" 20 #include "mozilla/dom/CSSStyleValue.h" 21 #include "mozilla/dom/CSSUnitValue.h" 22 #include "mozilla/dom/Element.h" 23 #include "mozilla/dom/StylePropertyMapReadOnlyBinding.h" 24 #include "nsCSSProps.h" 25 #include "nsComputedDOMStyle.h" 26 #include "nsCycleCollectionParticipant.h" 27 #include "nsReadableUtils.h" 28 29 namespace mozilla::dom { 30 31 namespace { 32 33 template <typename Source> 34 struct DeclarationTraits; 35 36 // Specialization for inline style (specified values) 37 struct InlineStyleDeclarations {}; 38 39 template <> 40 struct DeclarationTraits<InlineStyleDeclarations> { 41 static StylePropertyTypedValueResult Get(Element* aElement, 42 const nsACString& aProperty, 43 ErrorResult& aRv) { 44 MOZ_ASSERT(aElement); 45 46 auto result = StylePropertyTypedValueResult::None(); 47 48 RefPtr<DeclarationBlock> block = aElement->GetInlineStyleDeclaration(); 49 if (!block) { 50 return result; 51 } 52 53 if (!block->GetPropertyTypedValue(aProperty, result)) { 54 return result; 55 } 56 57 return result; 58 } 59 }; 60 61 // Specialization for computed style (computed values) 62 struct ComputedStyleDeclarations {}; 63 64 template <> 65 struct DeclarationTraits<ComputedStyleDeclarations> { 66 static StylePropertyTypedValueResult Get(Element* aElement, 67 const nsACString& aProperty, 68 ErrorResult& aRv) { 69 MOZ_ASSERT(aElement); 70 71 auto result = StylePropertyTypedValueResult::None(); 72 73 RefPtr<const ComputedStyle> style = 74 nsComputedDOMStyle::GetComputedStyle(aElement); 75 if (!style) { 76 return result; 77 } 78 79 if (!style->GetPropertyTypedValue(aProperty, result)) { 80 return result; 81 } 82 83 return result; 84 } 85 }; 86 87 // Specialization for style rule 88 struct StyleRuleDeclarations {}; 89 template <> 90 struct DeclarationTraits<StyleRuleDeclarations> { 91 static StylePropertyTypedValueResult Get(const CSSStyleRule* aRule, 92 const nsACString& aProperty, 93 ErrorResult& aRv) { 94 MOZ_ASSERT(aRule); 95 96 auto result = StylePropertyTypedValueResult::None(); 97 98 if (!aRule->GetDeclarationBlock().GetPropertyTypedValue(aProperty, 99 result)) { 100 return result; 101 } 102 103 return result; 104 } 105 }; 106 107 } // namespace 108 109 StylePropertyMapReadOnly::StylePropertyMapReadOnly(Element* aElement, 110 bool aComputed) 111 : mParent(aElement), mDeclarations(aElement, aComputed) { 112 MOZ_ASSERT(mParent); 113 } 114 115 StylePropertyMapReadOnly::StylePropertyMapReadOnly(CSSStyleRule* aRule) 116 : mParent(aRule), mDeclarations(aRule) { 117 MOZ_ASSERT(mParent); 118 } 119 120 NS_IMPL_CYCLE_COLLECTING_ADDREF(StylePropertyMapReadOnly) 121 NS_IMPL_CYCLE_COLLECTING_RELEASE(StylePropertyMapReadOnly) 122 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StylePropertyMapReadOnly) 123 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 124 NS_INTERFACE_MAP_ENTRY(nsISupports) 125 NS_INTERFACE_MAP_END 126 127 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(StylePropertyMapReadOnly) 128 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(StylePropertyMapReadOnly) 129 // Clear out our weak pointers. 130 tmp->mDeclarations.Unlink(); 131 132 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent) 133 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 134 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 135 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(StylePropertyMapReadOnly) 136 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) 137 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 138 139 nsISupports* StylePropertyMapReadOnly::GetParentObject() const { 140 return mParent; 141 } 142 143 JSObject* StylePropertyMapReadOnly::WrapObject( 144 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { 145 return StylePropertyMapReadOnly_Binding::Wrap(aCx, this, aGivenProto); 146 } 147 148 // start of StylePropertyMapReadOnly Web IDL implementation 149 150 // https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-get 151 // 152 // XXX This is not yet fully implemented and optimized! 153 void StylePropertyMapReadOnly::Get(const nsACString& aProperty, 154 OwningUndefinedOrCSSStyleValue& aRetVal, 155 ErrorResult& aRv) const { 156 if (!mParent) { 157 aRv.Throw(NS_ERROR_UNEXPECTED); 158 return; 159 } 160 // Step 2. 161 162 NonCustomCSSPropertyId id = nsCSSProps::LookupProperty(aProperty); 163 if (id == eCSSProperty_UNKNOWN) { 164 aRv.ThrowTypeError("Invalid property: "_ns + aProperty); 165 return; 166 } 167 168 // Step 3. 169 170 const Declarations& declarations = mDeclarations; 171 172 // Step 4. 173 174 auto result = declarations.Get(aProperty, aRv); 175 if (aRv.Failed()) { 176 return; 177 } 178 179 // XXX Move the creation of CSSStyleValue to a dedicated class for example 180 // CSSStyleValueFactory and eventually split the handling of tags into 181 // separate methods to make the code more readable and accessible for 182 // CSSStyleValue::Parse. See bug 2004057 183 184 RefPtr<CSSStyleValue> styleValue; 185 186 switch (result.tag) { 187 case StylePropertyTypedValueResult::Tag::Typed: { 188 const auto& typedValue = result.AsTyped(); 189 190 switch (typedValue.tag) { 191 case StyleTypedValue::Tag::Keyword: 192 styleValue = 193 MakeRefPtr<CSSKeywordValue>(mParent, typedValue.AsKeyword()); 194 break; 195 196 case StyleTypedValue::Tag::Numeric: { 197 auto numericValue = typedValue.AsNumeric(); 198 199 switch (numericValue.tag) { 200 case StyleNumericValue::Tag::Unit: { 201 auto unitValue = numericValue.AsUnit(); 202 203 styleValue = MakeRefPtr<CSSUnitValue>(mParent, unitValue.value, 204 unitValue.unit); 205 break; 206 } 207 208 case StyleNumericValue::Tag::Sum: { 209 auto mathSum = numericValue.AsSum(); 210 211 nsTArray<RefPtr<CSSNumericValue>> values; 212 213 for (const auto& value : mathSum.values) { 214 // XXX Only supporting units for now 215 if (value.IsUnit()) { 216 auto unitValue = value.AsUnit(); 217 218 values.AppendElement(MakeRefPtr<CSSUnitValue>( 219 mParent, unitValue.value, unitValue.unit)); 220 } 221 } 222 223 auto array = 224 MakeRefPtr<CSSNumericArray>(mParent, std::move(values)); 225 226 styleValue = MakeAndAddRef<CSSMathSum>(mParent, std::move(array)); 227 break; 228 } 229 } 230 231 break; 232 } 233 } 234 break; 235 } 236 237 case StylePropertyTypedValueResult::Tag::Unsupported: { 238 auto propertyId = CSSPropertyId::FromIdOrCustomProperty(id, aProperty); 239 auto rawBlock = result.AsUnsupported(); 240 auto block = MakeRefPtr<DeclarationBlock>(rawBlock.Consume()); 241 styleValue = MakeRefPtr<CSSUnsupportedValue>(mParent, propertyId, 242 std::move(block)); 243 break; 244 } 245 246 case StylePropertyTypedValueResult::Tag::None: 247 break; 248 } 249 250 if (styleValue) { 251 aRetVal.SetAsCSSStyleValue() = std::move(styleValue); 252 } else { 253 aRetVal.SetUndefined(); 254 } 255 } 256 257 // https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-getall 258 // 259 // XXX This is not yet fully implemented and optimized! 260 void StylePropertyMapReadOnly::GetAll(const nsACString& aProperty, 261 nsTArray<RefPtr<CSSStyleValue>>& aRetVal, 262 ErrorResult& aRv) const { 263 OwningUndefinedOrCSSStyleValue retVal; 264 265 Get(aProperty, retVal, aRv); 266 if (aRv.Failed()) { 267 return; 268 } 269 270 if (retVal.IsCSSStyleValue()) { 271 auto styleValue = retVal.GetAsCSSStyleValue(); 272 aRetVal.AppendElement(styleValue); 273 } 274 } 275 276 bool StylePropertyMapReadOnly::Has(const nsACString& aProperty, 277 ErrorResult& aRv) const { 278 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); 279 return false; 280 } 281 282 uint32_t StylePropertyMapReadOnly::Size() const { return 0; } 283 284 uint32_t StylePropertyMapReadOnly::GetIterableLength() const { return 0; } 285 286 const nsACString& StylePropertyMapReadOnly::GetKeyAtIndex( 287 uint32_t aIndex) const { 288 return EmptyCString(); 289 } 290 291 nsTArray<RefPtr<CSSStyleValue>> StylePropertyMapReadOnly::GetValueAtIndex( 292 uint32_t aIndex) const { 293 return nsTArray<RefPtr<CSSStyleValue>>(); 294 } 295 296 // end of StylePropertyMapReadOnly Web IDL implementation 297 298 size_t StylePropertyMapReadOnly::SizeOfExcludingThis( 299 MallocSizeOf aMallocSizeOf) const { 300 return 0; 301 } 302 303 size_t StylePropertyMapReadOnly::SizeOfIncludingThis( 304 MallocSizeOf aMallocSizeOf) const { 305 return SizeOfExcludingThis(aMallocSizeOf) + aMallocSizeOf(this); 306 } 307 308 StylePropertyTypedValueResult StylePropertyMapReadOnly::Declarations::Get( 309 const nsACString& aProperty, ErrorResult& aRv) const { 310 switch (mKind) { 311 case Kind::Inline: 312 return DeclarationTraits<InlineStyleDeclarations>::Get(mElement, 313 aProperty, aRv); 314 315 case Kind::Computed: 316 return DeclarationTraits<ComputedStyleDeclarations>::Get(mElement, 317 aProperty, aRv); 318 319 case Kind::Rule: 320 return DeclarationTraits<StyleRuleDeclarations>::Get(mRule, aProperty, 321 aRv); 322 } 323 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad kind value!"); 324 } 325 326 void StylePropertyMapReadOnly::Declarations::Unlink() { 327 switch (mKind) { 328 case Kind::Inline: 329 case Kind::Computed: 330 mElement = nullptr; 331 break; 332 333 case Kind::Rule: 334 mRule = nullptr; 335 break; 336 } 337 } 338 339 } // namespace mozilla::dom