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/. */
7 /* DOM object returned from element.getComputedStyle() */
9 #include "nsComputedDOMStyle.h"
11 #include "mozilla/ArrayUtils.h"
12 #include "mozilla/FloatingPoint.h"
13 #include "mozilla/FontPropertyTypes.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/PresShell.h"
16 #include "mozilla/PresShellInlines.h"
17 #include "mozilla/ScopeExit.h"
18 #include "mozilla/StaticPtr.h"
19 #include "mozilla/StaticPrefs_layout.h"
23 #include "nsIFrameInlines.h"
24 #include "mozilla/ComputedStyle.h"
25 #include "nsIScrollableFrame.h"
26 #include "nsContentUtils.h"
27 #include "nsDocShell.h"
28 #include "nsIContent.h"
29 #include "nsStyleConsts.h"
31 #include "nsDOMCSSValueList.h"
32 #include "nsFlexContainerFrame.h"
33 #include "nsGridContainerFrame.h"
34 #include "nsGkAtoms.h"
35 #include "mozilla/ReflowInput.h"
36 #include "nsStyleUtil.h"
37 #include "nsStyleStructInlines.h"
38 #include "nsROCSSPrimitiveValue.h"
40 #include "nsPresContext.h"
41 #include "mozilla/dom/Document.h"
43 #include "nsCSSProps.h"
44 #include "nsCSSPseudoElements.h"
45 #include "mozilla/EffectSet.h"
46 #include "mozilla/IntegerRange.h"
47 #include "mozilla/ServoStyleSet.h"
48 #include "mozilla/RestyleManager.h"
49 #include "mozilla/ViewportFrame.h"
50 #include "nsLayoutUtils.h"
51 #include "nsDisplayList.h"
52 #include "nsDOMCSSDeclaration.h"
53 #include "nsStyleTransformMatrix.h"
54 #include "mozilla/dom/Element.h"
55 #include "mozilla/dom/ElementInlines.h"
57 #include "nsWrapperCacheInlines.h"
58 #include "mozilla/AppUnits.h"
60 #include "mozilla/ComputedStyleInlines.h"
61 #include "nsPrintfCString.h"
63 using namespace mozilla
;
64 using namespace mozilla::dom
;
67 * This is the implementation of the readonly CSSStyleDeclaration that is
68 * returned by the getComputedStyle() function.
71 already_AddRefed
<nsComputedDOMStyle
> NS_NewComputedDOMStyle(
72 dom::Element
* aElement
, const nsAString
& aPseudoElt
, Document
* aDocument
,
73 nsComputedDOMStyle::StyleType aStyleType
, mozilla::ErrorResult
&) {
74 auto [pseudo
, functionalPseudoParameter
] =
75 nsCSSPseudoElements::ParsePseudoElement(aPseudoElt
,
76 CSSEnabledState::ForAllContent
);
77 auto returnEmpty
= nsComputedDOMStyle::AlwaysReturnEmptyStyle::No
;
79 if (!aPseudoElt
.IsEmpty() && aPseudoElt
.First() == u
':') {
80 returnEmpty
= nsComputedDOMStyle::AlwaysReturnEmptyStyle::Yes
;
82 pseudo
.emplace(PseudoStyleType::NotPseudo
);
84 RefPtr
<nsComputedDOMStyle
> computedStyle
=
85 new nsComputedDOMStyle(aElement
, *pseudo
, functionalPseudoParameter
,
86 aDocument
, aStyleType
, returnEmpty
);
87 return computedStyle
.forget();
90 static nsDOMCSSValueList
* GetROCSSValueList(bool aCommaDelimited
) {
91 return new nsDOMCSSValueList(aCommaDelimited
);
94 static const Element
* GetRenderedElement(const Element
* aElement
,
95 PseudoStyleType aPseudo
) {
96 if (aPseudo
== PseudoStyleType::NotPseudo
) {
99 if (aPseudo
== PseudoStyleType::before
) {
100 return nsLayoutUtils::GetBeforePseudo(aElement
);
102 if (aPseudo
== PseudoStyleType::after
) {
103 return nsLayoutUtils::GetAfterPseudo(aElement
);
105 if (aPseudo
== PseudoStyleType::marker
) {
106 return nsLayoutUtils::GetMarkerPseudo(aElement
);
111 // Whether aDocument needs to restyle for aElement
112 static bool ElementNeedsRestyle(Element
* aElement
, PseudoStyleType aPseudo
,
113 bool aMayNeedToFlushLayout
) {
114 const Document
* doc
= aElement
->GetComposedDoc();
116 // If the element is out of the document we don't return styles for it, so
121 PresShell
* presShell
= doc
->GetPresShell();
123 // If there's no pres-shell we'll just either mint a new style from our
124 // caller document, or return no styles, so nothing to do (unless our owner
125 // element needs to get restyled, which could cause us to gain a pres shell,
126 // but the caller checks that).
130 // Unfortunately we don't know if the sheet change affects mElement or not, so
131 // just assume it will and that we need to flush normally.
132 ServoStyleSet
* styleSet
= presShell
->StyleSet();
133 if (styleSet
->StyleSheetsHaveChanged()) {
137 nsPresContext
* presContext
= presShell
->GetPresContext();
138 MOZ_ASSERT(presContext
);
140 // Pending media query updates can definitely change style on the element. For
141 // example, if you change the zoom factor and then call getComputedStyle, you
142 // should be able to observe the style with the new media queries.
144 // TODO(emilio): Does this need to also check the user font set? (it affects
146 if (presContext
->HasPendingMediaQueryUpdates()) {
151 // If the pseudo-element is animating, make sure to flush.
152 if (aElement
->MayHaveAnimations() && aPseudo
!= PseudoStyleType::NotPseudo
&&
153 AnimationUtils::IsSupportedPseudoForAnimations(aPseudo
)) {
154 if (EffectSet::Get(aElement
, aPseudo
)) {
159 // For Servo, we need to process the restyle-hint-invalidations first, to
160 // expand LaterSiblings hint, so that we can look whether ancestors need
162 RestyleManager
* restyleManager
= presContext
->RestyleManager();
163 restyleManager
->ProcessAllPendingAttributeAndStateInvalidations();
165 if (!presContext
->EffectCompositor()->HasPendingStyleUpdates() &&
166 !doc
->GetServoRestyleRoot()) {
170 // If there's a pseudo, we need to prefer that element, as the pseudo itself
171 // may have explicit restyles.
172 const Element
* styledElement
= GetRenderedElement(aElement
, aPseudo
);
173 // Try to skip the restyle otherwise.
174 return Servo_HasPendingRestyleAncestor(
175 styledElement
? styledElement
: aElement
, aMayNeedToFlushLayout
);
179 * An object that represents the ordered set of properties that are exposed on
180 * an nsComputedDOMStyle object and how their computed values can be obtained.
182 struct ComputedStyleMap
{
183 friend class nsComputedDOMStyle
;
186 // Create a pointer-to-member-function type.
187 using ComputeMethod
= already_AddRefed
<CSSValue
> (nsComputedDOMStyle::*)();
189 nsCSSPropertyID mProperty
;
191 // Whether the property can ever be exposed in getComputedStyle(). For
192 // example, @page descriptors implemented as CSS properties or other
193 // internal properties, would have this flag set to `false`.
194 bool mCanBeExposed
= false;
196 ComputeMethod mGetter
= nullptr;
198 bool IsEnumerable() const {
199 return IsEnabled() && !nsCSSProps::IsShorthand(mProperty
);
202 bool IsEnabled() const {
203 if (!mCanBeExposed
||
204 !nsCSSProps::IsEnabled(mProperty
, CSSEnabledState::ForAllContent
)) {
207 if (nsCSSProps::IsShorthand(mProperty
) &&
208 !StaticPrefs::layout_css_computed_style_shorthands()) {
209 return nsCSSProps::PropHasFlags(
210 mProperty
, CSSPropFlags::ShorthandUnconditionallyExposedOnGetCS
);
216 // This generated file includes definition of kEntries which is typed
217 // Entry[] and used below, so this #include has to be put here.
218 #include "nsComputedDOMStyleGenerated.inc"
221 * Returns the number of properties that should be exposed on an
222 * nsComputedDOMStyle, ecxluding any disabled properties.
226 return mEnumerablePropertyCount
;
230 * Returns the property at the given index in the list of properties
231 * that should be exposed on an nsComputedDOMStyle, excluding any
232 * disabled properties.
234 nsCSSPropertyID
PropertyAt(uint32_t aIndex
) {
236 return kEntries
[EntryIndex(aIndex
)].mProperty
;
240 * Searches for and returns the computed style map entry for the given
241 * property, or nullptr if the property is not exposed on nsComputedDOMStyle
242 * or is currently disabled.
244 const Entry
* FindEntryForProperty(nsCSSPropertyID aPropID
) {
245 if (size_t(aPropID
) >= ArrayLength(kEntryIndices
)) {
246 MOZ_ASSERT(aPropID
== eCSSProperty_UNKNOWN
);
249 MOZ_ASSERT(kEntryIndices
[aPropID
] < ArrayLength(kEntries
));
250 const auto& entry
= kEntries
[kEntryIndices
[aPropID
]];
251 if (!entry
.IsEnabled()) {
258 * Records that mIndexMap needs updating, due to prefs changing that could
259 * affect the set of properties exposed on an nsComputedDOMStyle.
261 void MarkDirty() { mEnumerablePropertyCount
= 0; }
263 // The member variables are public so that we can use an initializer in
264 // nsComputedDOMStyle::GetComputedStyleMap. Use the member functions
265 // above to get information from this object.
268 * The number of properties that should be exposed on an nsComputedDOMStyle.
269 * This will be less than eComputedStyleProperty_COUNT if some property
270 * prefs are disabled. A value of 0 indicates that it and mIndexMap are out
273 uint32_t mEnumerablePropertyCount
= 0;
276 * A map of indexes on the nsComputedDOMStyle object to indexes into kEntries.
278 uint32_t mIndexMap
[ArrayLength(kEntries
)];
282 * Returns whether mEnumerablePropertyCount and mIndexMap are out of date.
284 bool IsDirty() { return mEnumerablePropertyCount
== 0; }
287 * Updates mEnumerablePropertyCount and mIndexMap to take into account
288 * properties whose prefs are currently disabled.
293 * Maps an nsComputedDOMStyle indexed getter index to an index into kEntries.
295 uint32_t EntryIndex(uint32_t aIndex
) const {
296 MOZ_ASSERT(aIndex
< mEnumerablePropertyCount
);
297 return mIndexMap
[aIndex
];
301 constexpr ComputedStyleMap::Entry
302 ComputedStyleMap::kEntries
[ArrayLength(kEntries
)];
304 constexpr size_t ComputedStyleMap::kEntryIndices
[ArrayLength(kEntries
)];
306 void ComputedStyleMap::Update() {
312 for (uint32_t i
= 0; i
< ArrayLength(kEntries
); i
++) {
313 if (kEntries
[i
].IsEnumerable()) {
314 mIndexMap
[index
++] = i
;
317 mEnumerablePropertyCount
= index
;
320 nsComputedDOMStyle::nsComputedDOMStyle(dom::Element
* aElement
,
321 PseudoStyleType aPseudo
,
322 nsAtom
* aFunctionalPseudoParameter
,
324 StyleType aStyleType
,
325 AlwaysReturnEmptyStyle aAlwaysEmpty
)
326 : mDocumentWeak(nullptr),
327 mOuterFrame(nullptr),
328 mInnerFrame(nullptr),
331 mFunctionalPseudoParameter(aFunctionalPseudoParameter
),
332 mStyleType(aStyleType
),
333 mAlwaysReturnEmpty(aAlwaysEmpty
) {
334 MOZ_ASSERT(aElement
);
335 MOZ_ASSERT(aDocument
);
336 // TODO(emilio, bug 548397, https://github.com/w3c/csswg-drafts/issues/2403):
337 // Should use aElement->OwnerDoc() instead.
338 mDocumentWeak
= do_GetWeakReference(aDocument
);
342 nsComputedDOMStyle::~nsComputedDOMStyle() {
343 MOZ_ASSERT(!mResolvedComputedStyle
,
344 "Should have called ClearComputedStyle() during last release.");
347 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(nsComputedDOMStyle
)
349 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsComputedDOMStyle
)
350 tmp
->ClearComputedStyle(); // remove observer before clearing mElement
351 NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement
)
352 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
353 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
355 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsComputedDOMStyle
)
356 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement
)
357 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
359 // We can skip the nsComputedDOMStyle if it has no wrapper and its
360 // element is skippable, because it will have no outgoing edges, so
361 // it can't be part of a cycle.
363 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle
)
364 if (!tmp
->GetWrapperPreserveColor()) {
365 return !tmp
->mElement
||
366 mozilla::dom::FragmentOrElement::CanSkip(tmp
->mElement
, true);
368 return tmp
->HasKnownLiveWrapper();
369 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
371 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsComputedDOMStyle
)
372 if (!tmp
->GetWrapperPreserveColor()) {
373 return !tmp
->mElement
||
374 mozilla::dom::FragmentOrElement::CanSkipInCC(tmp
->mElement
);
376 return tmp
->HasKnownLiveWrapper();
377 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
379 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsComputedDOMStyle
)
380 if (!tmp
->GetWrapperPreserveColor()) {
381 return !tmp
->mElement
||
382 mozilla::dom::FragmentOrElement::CanSkipThis(tmp
->mElement
);
384 return tmp
->HasKnownLiveWrapper();
385 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
387 // QueryInterface implementation for nsComputedDOMStyle
388 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsComputedDOMStyle
)
389 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
390 NS_INTERFACE_MAP_ENTRY(nsIMutationObserver
)
391 NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration
)
393 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsComputedDOMStyle
)
394 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsComputedDOMStyle
,
395 ClearComputedStyle())
397 void nsComputedDOMStyle::GetPropertyValue(const nsCSSPropertyID aPropID
,
398 nsACString
& aValue
) {
399 return GetPropertyValue(aPropID
, EmptyCString(), aValue
);
402 void nsComputedDOMStyle::SetPropertyValue(const nsCSSPropertyID aPropID
,
403 const nsACString
& aValue
,
404 nsIPrincipal
* aSubjectPrincipal
,
406 aRv
.ThrowNoModificationAllowedError(nsPrintfCString(
407 "Can't set value for property '%s' in computed style",
408 PromiseFlatCString(nsCSSProps::GetStringValue(aPropID
)).get()));
411 void nsComputedDOMStyle::GetCssText(nsACString
& aCssText
) {
415 void nsComputedDOMStyle::SetCssText(const nsACString
& aCssText
,
416 nsIPrincipal
* aSubjectPrincipal
,
418 aRv
.ThrowNoModificationAllowedError("Can't set cssText on computed style");
421 uint32_t nsComputedDOMStyle::Length() {
422 // Make sure we have up to date style so that we can include custom
424 UpdateCurrentStyleSources(eCSSPropertyExtra_variable
);
425 if (!mComputedStyle
) {
429 uint32_t length
= GetComputedStyleMap()->Length() +
430 Servo_GetCustomPropertiesCount(mComputedStyle
);
432 ClearCurrentStyleSources();
437 css::Rule
* nsComputedDOMStyle::GetParentRule() { return nullptr; }
439 void nsComputedDOMStyle::GetPropertyValue(const nsACString
& aPropertyName
,
440 nsACString
& aReturn
) {
441 nsCSSPropertyID prop
= nsCSSProps::LookupProperty(aPropertyName
);
442 GetPropertyValue(prop
, aPropertyName
, aReturn
);
445 void nsComputedDOMStyle::GetPropertyValue(
446 nsCSSPropertyID aPropID
, const nsACString
& aMaybeCustomPropertyName
,
447 nsACString
& aReturn
) {
448 MOZ_ASSERT(aReturn
.IsEmpty());
450 const ComputedStyleMap::Entry
* entry
= nullptr;
451 if (aPropID
!= eCSSPropertyExtra_variable
) {
452 entry
= GetComputedStyleMap()->FindEntryForProperty(aPropID
);
458 UpdateCurrentStyleSources(aPropID
);
459 if (!mComputedStyle
) {
463 auto cleanup
= mozilla::MakeScopeExit([&] { ClearCurrentStyleSources(); });
466 MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aMaybeCustomPropertyName
));
467 const nsACString
& name
=
468 Substring(aMaybeCustomPropertyName
, CSS_CUSTOM_NAME_PREFIX_LENGTH
);
469 Servo_GetCustomPropertyValue(
470 mComputedStyle
, mPresShell
->StyleSet()->RawData(), &name
, &aReturn
);
474 if (nsCSSProps::PropHasFlags(aPropID
, CSSPropFlags::IsLogical
)) {
476 MOZ_ASSERT(entry
->mGetter
== &nsComputedDOMStyle::DummyGetter
);
478 DebugOnly
<nsCSSPropertyID
> logicalProp
= aPropID
;
480 aPropID
= Servo_ResolveLogicalProperty(aPropID
, mComputedStyle
);
481 entry
= GetComputedStyleMap()->FindEntryForProperty(aPropID
);
483 MOZ_ASSERT(NeedsToFlushLayout(logicalProp
) == NeedsToFlushLayout(aPropID
),
484 "Logical and physical property don't agree on whether layout is "
488 if (!nsCSSProps::PropHasFlags(aPropID
, CSSPropFlags::SerializedByServo
)) {
489 if (RefPtr
<CSSValue
> value
= (this->*entry
->mGetter
)()) {
491 value
->GetCssText(text
);
492 CopyUTF16toUTF8(text
, aReturn
);
497 MOZ_ASSERT(entry
->mGetter
== &nsComputedDOMStyle::DummyGetter
);
498 Servo_GetResolvedValue(mComputedStyle
, aPropID
,
499 mPresShell
->StyleSet()->RawData(), mElement
, &aReturn
);
503 already_AddRefed
<const ComputedStyle
> nsComputedDOMStyle::GetComputedStyle(
504 Element
* aElement
, PseudoStyleType aPseudo
,
505 nsAtom
* aFunctionalPseudoParameter
, StyleType aStyleType
) {
506 if (Document
* doc
= aElement
->GetComposedDoc()) {
507 doc
->FlushPendingNotifications(FlushType::Style
);
509 return GetComputedStyleNoFlush(aElement
, aPseudo
, aFunctionalPseudoParameter
,
514 * The following function checks whether we need to explicitly resolve the style
515 * again, even though we have a style coming from the frame.
517 * This basically checks whether the style is or may be under a ::first-line or
518 * ::first-letter frame, in which case we can't return the frame style, and we
519 * need to resolve it. See bug 505515.
521 static bool MustReresolveStyle(const ComputedStyle
* aStyle
) {
524 // TODO(emilio): We may want to avoid re-resolving pseudo-element styles
526 return aStyle
->HasPseudoElementData() && !aStyle
->IsPseudoElement();
529 static bool IsInFlatTree(const Element
& aElement
) {
530 const auto* topmost
= &aElement
;
532 if (topmost
->HasServoData()) {
533 // If we have styled this element then we know it's in the flat tree.
536 const Element
* parent
= topmost
->GetFlattenedTreeParentElement();
542 auto* root
= topmost
->GetFlattenedTreeParentNode();
543 return root
&& root
->IsDocument();
546 already_AddRefed
<const ComputedStyle
>
547 nsComputedDOMStyle::DoGetComputedStyleNoFlush(
548 const Element
* aElement
, PseudoStyleType aPseudo
,
549 nsAtom
* aFunctionalPseudoParameter
, PresShell
* aPresShell
,
550 StyleType aStyleType
) {
551 MOZ_ASSERT(aElement
, "NULL element");
553 // If the content has a pres shell, we must use it. Otherwise we'd
554 // potentially mix rule trees by using the wrong pres shell's style
555 // set. Using the pres shell from the content also means that any
556 // content that's actually *in* a document will get the style from the
558 PresShell
* presShell
= nsContentUtils::GetPresShellForContent(aElement
);
559 bool inDocWithShell
= true;
561 inDocWithShell
= false;
562 presShell
= aPresShell
;
568 MOZ_ASSERT(aPseudo
== PseudoStyleType::NotPseudo
||
569 PseudoStyle::IsPseudoElement(aPseudo
));
570 if (!aElement
->IsInComposedDoc()) {
571 // Don't return styles for disconnected elements, that makes no sense. This
572 // can only happen with a non-null presShell for cross-document calls.
576 if (!IsInFlatTree(*aElement
)) {
580 // XXX the !aElement->IsHTMLElement(nsGkAtoms::area)
581 // check is needed due to bug 135040 (to avoid using
582 // mPrimaryFrame). Remove it once that's fixed.
583 if (inDocWithShell
&& aStyleType
== StyleType::All
&&
584 !aElement
->IsHTMLElement(nsGkAtoms::area
)) {
585 if (const Element
* element
= GetRenderedElement(aElement
, aPseudo
)) {
586 if (element
->HasServoData()) {
587 const ComputedStyle
* result
=
588 Servo_Element_GetMaybeOutOfDateStyle(element
);
589 return do_AddRef(result
);
594 // No frame has been created, or we have a pseudo, or we're looking
595 // for the default style, so resolve the style ourselves.
596 ServoStyleSet
* styleSet
= presShell
->StyleSet();
598 StyleRuleInclusion rules
= aStyleType
== StyleType::DefaultOnly
599 ? StyleRuleInclusion::DefaultOnly
600 : StyleRuleInclusion::All
;
601 RefPtr
<ComputedStyle
> result
= styleSet
->ResolveStyleLazily(
602 *aElement
, aPseudo
, aFunctionalPseudoParameter
, rules
);
603 return result
.forget();
606 already_AddRefed
<const ComputedStyle
>
607 nsComputedDOMStyle::GetUnanimatedComputedStyleNoFlush(
608 Element
* aElement
, PseudoStyleType aPseudo
,
609 nsAtom
* aFunctionalPseudoParameter
) {
610 RefPtr
<const ComputedStyle
> style
=
611 GetComputedStyleNoFlush(aElement
, aPseudo
, aFunctionalPseudoParameter
);
616 PresShell
* presShell
= aElement
->OwnerDoc()->GetPresShell();
617 MOZ_ASSERT(presShell
,
618 "How in the world did we get a style a few lines above?");
620 Element
* elementOrPseudoElement
=
621 AnimationUtils::GetElementForRestyle(aElement
, aPseudo
);
622 if (!elementOrPseudoElement
) {
626 return presShell
->StyleSet()->GetBaseContextForElement(elementOrPseudoElement
,
630 nsMargin
nsComputedDOMStyle::GetAdjustedValuesForBoxSizing() {
631 // We want the width/height of whatever parts 'width' or 'height' controls,
632 // which can be different depending on the value of the 'box-sizing' property.
633 const nsStylePosition
* stylePos
= StylePosition();
636 if (stylePos
->mBoxSizing
== StyleBoxSizing::Border
) {
637 adjustment
= mInnerFrame
->GetUsedBorderAndPadding();
643 static void AddImageURL(nsIURI
& aURI
, nsTArray
<nsCString
>& aURLs
) {
645 nsresult rv
= aURI
.GetSpec(spec
);
650 aURLs
.AppendElement(std::move(spec
));
653 static void AddImageURL(const StyleComputedUrl
& aURL
,
654 nsTArray
<nsCString
>& aURLs
) {
655 if (aURL
.IsLocalRef()) {
659 if (nsIURI
* uri
= aURL
.GetURI()) {
660 AddImageURL(*uri
, aURLs
);
664 static void AddImageURL(const StyleImage
& aImage
, nsTArray
<nsCString
>& aURLs
) {
665 if (auto* urlValue
= aImage
.GetImageRequestURLValue()) {
666 AddImageURL(*urlValue
, aURLs
);
670 static void AddImageURL(const StyleShapeOutside
& aShapeOutside
,
671 nsTArray
<nsCString
>& aURLs
) {
672 if (aShapeOutside
.IsImage()) {
673 AddImageURL(aShapeOutside
.AsImage(), aURLs
);
677 static void AddImageURL(const StyleClipPath
& aClipPath
,
678 nsTArray
<nsCString
>& aURLs
) {
679 if (aClipPath
.IsUrl()) {
680 AddImageURL(aClipPath
.AsUrl(), aURLs
);
684 static void AddImageURLs(const nsStyleImageLayers
& aLayers
,
685 nsTArray
<nsCString
>& aURLs
) {
686 for (auto i
: IntegerRange(aLayers
.mLayers
.Length())) {
687 AddImageURL(aLayers
.mLayers
[i
].mImage
, aURLs
);
691 static void CollectImageURLsForProperty(nsCSSPropertyID aProp
,
692 const ComputedStyle
& aStyle
,
693 nsTArray
<nsCString
>& aURLs
) {
694 if (nsCSSProps::IsShorthand(aProp
)) {
695 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aProp
,
696 CSSEnabledState::ForAllContent
) {
697 CollectImageURLsForProperty(*p
, aStyle
, aURLs
);
703 case eCSSProperty_cursor
:
704 for (auto& image
: aStyle
.StyleUI()->Cursor().images
.AsSpan()) {
705 AddImageURL(image
.image
, aURLs
);
708 case eCSSProperty_background_image
:
709 AddImageURLs(aStyle
.StyleBackground()->mImage
, aURLs
);
711 case eCSSProperty_mask_clip
:
712 AddImageURLs(aStyle
.StyleSVGReset()->mMask
, aURLs
);
714 case eCSSProperty_list_style_image
: {
715 const auto& image
= aStyle
.StyleList()->mListStyleImage
;
717 AddImageURL(image
.AsUrl(), aURLs
);
721 case eCSSProperty_border_image_source
:
722 AddImageURL(aStyle
.StyleBorder()->mBorderImageSource
, aURLs
);
724 case eCSSProperty_clip_path
:
725 AddImageURL(aStyle
.StyleSVGReset()->mClipPath
, aURLs
);
727 case eCSSProperty_shape_outside
:
728 AddImageURL(aStyle
.StyleDisplay()->mShapeOutside
, aURLs
);
735 void nsComputedDOMStyle::GetCSSImageURLs(const nsACString
& aPropertyName
,
736 nsTArray
<nsCString
>& aImageURLs
,
737 mozilla::ErrorResult
& aRv
) {
738 nsCSSPropertyID prop
= nsCSSProps::LookupProperty(aPropertyName
);
739 if (prop
== eCSSProperty_UNKNOWN
) {
740 // Note: not using nsPrintfCString here in case aPropertyName contains
742 aRv
.ThrowSyntaxError("Invalid property name '"_ns
+ aPropertyName
+ "'"_ns
);
746 UpdateCurrentStyleSources(prop
);
748 if (!mComputedStyle
) {
752 CollectImageURLsForProperty(prop
, *mComputedStyle
, aImageURLs
);
753 ClearCurrentStyleSources();
756 // nsDOMCSSDeclaration abstract methods which should never be called
757 // on a nsComputedDOMStyle object, but must be defined to avoid
759 DeclarationBlock
* nsComputedDOMStyle::GetOrCreateCSSDeclaration(
760 Operation aOperation
, DeclarationBlock
** aCreated
) {
761 MOZ_CRASH("called nsComputedDOMStyle::GetCSSDeclaration");
764 nsresult
nsComputedDOMStyle::SetCSSDeclaration(DeclarationBlock
*,
765 MutationClosureData
*) {
766 MOZ_CRASH("called nsComputedDOMStyle::SetCSSDeclaration");
769 Document
* nsComputedDOMStyle::DocToUpdate() {
770 MOZ_CRASH("called nsComputedDOMStyle::DocToUpdate");
773 nsDOMCSSDeclaration::ParsingEnvironment
774 nsComputedDOMStyle::GetParsingEnvironment(
775 nsIPrincipal
* aSubjectPrincipal
) const {
776 MOZ_CRASH("called nsComputedDOMStyle::GetParsingEnvironment");
779 void nsComputedDOMStyle::ClearComputedStyle() {
780 if (mResolvedComputedStyle
) {
781 mResolvedComputedStyle
= false;
782 mElement
->RemoveMutationObserver(this);
784 mComputedStyle
= nullptr;
787 void nsComputedDOMStyle::SetResolvedComputedStyle(
788 RefPtr
<const ComputedStyle
>&& aContext
, uint64_t aGeneration
) {
789 if (!mResolvedComputedStyle
) {
790 mResolvedComputedStyle
= true;
791 mElement
->AddMutationObserver(this);
793 mComputedStyle
= aContext
;
794 mComputedStyleGeneration
= aGeneration
;
795 mPresShellId
= mPresShell
->GetPresShellId();
798 void nsComputedDOMStyle::SetFrameComputedStyle(mozilla::ComputedStyle
* aStyle
,
799 uint64_t aGeneration
) {
800 ClearComputedStyle();
801 mComputedStyle
= aStyle
;
802 mComputedStyleGeneration
= aGeneration
;
803 mPresShellId
= mPresShell
->GetPresShellId();
806 static bool MayNeedToFlushLayout(nsCSSPropertyID aPropID
) {
808 case eCSSProperty_width
:
809 case eCSSProperty_height
:
810 case eCSSProperty_block_size
:
811 case eCSSProperty_inline_size
:
812 case eCSSProperty_line_height
:
813 case eCSSProperty_grid_template_rows
:
814 case eCSSProperty_grid_template_columns
:
815 case eCSSProperty_perspective_origin
:
816 case eCSSProperty_transform_origin
:
817 case eCSSProperty_transform
:
818 case eCSSProperty_border_top_width
:
819 case eCSSProperty_border_bottom_width
:
820 case eCSSProperty_border_left_width
:
821 case eCSSProperty_border_right_width
:
822 case eCSSProperty_border_block_start_width
:
823 case eCSSProperty_border_block_end_width
:
824 case eCSSProperty_border_inline_start_width
:
825 case eCSSProperty_border_inline_end_width
:
826 case eCSSProperty_top
:
827 case eCSSProperty_right
:
828 case eCSSProperty_bottom
:
829 case eCSSProperty_left
:
830 case eCSSProperty_inset_block_start
:
831 case eCSSProperty_inset_block_end
:
832 case eCSSProperty_inset_inline_start
:
833 case eCSSProperty_inset_inline_end
:
834 case eCSSProperty_padding_top
:
835 case eCSSProperty_padding_right
:
836 case eCSSProperty_padding_bottom
:
837 case eCSSProperty_padding_left
:
838 case eCSSProperty_padding_block_start
:
839 case eCSSProperty_padding_block_end
:
840 case eCSSProperty_padding_inline_start
:
841 case eCSSProperty_padding_inline_end
:
842 case eCSSProperty_margin_top
:
843 case eCSSProperty_margin_right
:
844 case eCSSProperty_margin_bottom
:
845 case eCSSProperty_margin_left
:
846 case eCSSProperty_margin_block_start
:
847 case eCSSProperty_margin_block_end
:
848 case eCSSProperty_margin_inline_start
:
849 case eCSSProperty_margin_inline_end
:
856 bool nsComputedDOMStyle::NeedsToFlushStyle(nsCSSPropertyID aPropID
) const {
857 bool mayNeedToFlushLayout
= MayNeedToFlushLayout(aPropID
);
859 // We always compute styles from the element's owner document.
860 if (ElementNeedsRestyle(mElement
, mPseudo
, mayNeedToFlushLayout
)) {
864 Document
* doc
= mElement
->OwnerDoc();
865 // If parent document is there, also needs to check if there is some change
866 // that needs to flush this document (e.g. size change for iframe).
867 while (doc
->StyleOrLayoutObservablyDependsOnParentDocumentLayout()) {
868 if (Element
* element
= doc
->GetEmbedderElement()) {
869 if (ElementNeedsRestyle(element
, PseudoStyleType::NotPseudo
,
870 mayNeedToFlushLayout
)) {
875 doc
= doc
->GetInProcessParentDocument();
881 static bool IsNonReplacedInline(nsIFrame
* aFrame
) {
882 // FIXME: this should be IsInlineInsideStyle() since width/height
883 // doesn't apply to ruby boxes.
884 return aFrame
->StyleDisplay()->IsInlineFlow() &&
885 !aFrame
->IsFrameOfType(nsIFrame::eReplaced
) &&
886 !aFrame
->IsFieldSetFrame() && !aFrame
->IsBlockFrame() &&
887 !aFrame
->IsScrollFrame() && !aFrame
->IsColumnSetWrapperFrame();
890 static Side
SideForPaddingOrMarginOrInsetProperty(nsCSSPropertyID aPropID
) {
892 case eCSSProperty_top
:
893 case eCSSProperty_margin_top
:
894 case eCSSProperty_padding_top
:
896 case eCSSProperty_right
:
897 case eCSSProperty_margin_right
:
898 case eCSSProperty_padding_right
:
900 case eCSSProperty_bottom
:
901 case eCSSProperty_margin_bottom
:
902 case eCSSProperty_padding_bottom
:
904 case eCSSProperty_left
:
905 case eCSSProperty_margin_left
:
906 case eCSSProperty_padding_left
:
909 MOZ_ASSERT_UNREACHABLE("Unexpected property");
914 static bool PaddingNeedsUsedValue(const LengthPercentage
& aValue
,
915 const ComputedStyle
& aStyle
) {
916 return !aValue
.ConvertsToLength() || aStyle
.StyleDisplay()->HasAppearance();
919 bool nsComputedDOMStyle::NeedsToFlushLayout(nsCSSPropertyID aPropID
) const {
920 MOZ_ASSERT(aPropID
!= eCSSProperty_UNKNOWN
);
921 if (aPropID
== eCSSPropertyExtra_variable
) {
924 nsIFrame
* outerFrame
= GetOuterFrame();
928 nsIFrame
* frame
= nsLayoutUtils::GetStyleFrame(outerFrame
);
929 auto* style
= frame
->Style();
930 if (nsCSSProps::PropHasFlags(aPropID
, CSSPropFlags::IsLogical
)) {
931 aPropID
= Servo_ResolveLogicalProperty(aPropID
, style
);
935 case eCSSProperty_width
:
936 case eCSSProperty_height
:
937 return !IsNonReplacedInline(frame
);
938 case eCSSProperty_line_height
:
939 return frame
->StyleFont()->mLineHeight
.IsMozBlockHeight();
940 case eCSSProperty_grid_template_rows
:
941 case eCSSProperty_grid_template_columns
:
942 return !!nsGridContainerFrame::GetGridContainerFrame(frame
);
943 case eCSSProperty_perspective_origin
:
944 return style
->StyleDisplay()->mPerspectiveOrigin
.HasPercent();
945 case eCSSProperty_transform_origin
:
946 return style
->StyleDisplay()->mTransformOrigin
.HasPercent();
947 case eCSSProperty_transform
:
948 return style
->StyleDisplay()->mTransform
.HasPercent();
949 case eCSSProperty_border_top_width
:
950 case eCSSProperty_border_bottom_width
:
951 case eCSSProperty_border_left_width
:
952 case eCSSProperty_border_right_width
:
953 // FIXME(emilio): This should return false per spec (bug 1551000), but
954 // themed borders don't make that easy, so for now flush for that case.
956 // TODO(emilio): If we make GetUsedBorder() stop returning 0 for an
957 // unreflowed frame, or something of that sort, then we can stop flushing
958 // layout for themed frames.
959 return style
->StyleDisplay()->HasAppearance();
960 case eCSSProperty_top
:
961 case eCSSProperty_right
:
962 case eCSSProperty_bottom
:
963 case eCSSProperty_left
:
964 // Doing better than this is actually hard.
965 return style
->StyleDisplay()->mPosition
!= StylePositionProperty::Static
;
966 case eCSSProperty_padding_top
:
967 case eCSSProperty_padding_right
:
968 case eCSSProperty_padding_bottom
:
969 case eCSSProperty_padding_left
: {
970 Side side
= SideForPaddingOrMarginOrInsetProperty(aPropID
);
971 // Theming can override used padding, sigh.
973 // TODO(emilio): If we make GetUsedPadding() stop returning 0 for an
974 // unreflowed frame, or something of that sort, then we can stop flushing
975 // layout for themed frames.
976 return PaddingNeedsUsedValue(style
->StylePadding()->mPadding
.Get(side
),
979 case eCSSProperty_margin_top
:
980 case eCSSProperty_margin_right
:
981 case eCSSProperty_margin_bottom
:
982 case eCSSProperty_margin_left
: {
983 // NOTE(emilio): This is dubious, but matches other browsers.
984 // See https://github.com/w3c/csswg-drafts/issues/2328
985 Side side
= SideForPaddingOrMarginOrInsetProperty(aPropID
);
986 return !style
->StyleMargin()->mMargin
.Get(side
).ConvertsToLength();
993 void nsComputedDOMStyle::Flush(Document
& aDocument
, FlushType aFlushType
) {
994 MOZ_ASSERT(mElement
->IsInComposedDoc());
998 nsCOMPtr
<Document
> document
= do_QueryReferent(mDocumentWeak
);
999 MOZ_ASSERT(document
== &aDocument
);
1003 aDocument
.FlushPendingNotifications(aFlushType
);
1004 if (MOZ_UNLIKELY(&aDocument
!= mElement
->OwnerDoc())) {
1005 mElement
->OwnerDoc()->FlushPendingNotifications(aFlushType
);
1009 nsIFrame
* nsComputedDOMStyle::GetOuterFrame() const {
1010 if (mPseudo
== PseudoStyleType::NotPseudo
) {
1011 return mElement
->GetPrimaryFrame();
1013 nsAtom
* property
= nullptr;
1014 if (mPseudo
== PseudoStyleType::before
) {
1015 property
= nsGkAtoms::beforePseudoProperty
;
1016 } else if (mPseudo
== PseudoStyleType::after
) {
1017 property
= nsGkAtoms::afterPseudoProperty
;
1018 } else if (mPseudo
== PseudoStyleType::marker
) {
1019 property
= nsGkAtoms::markerPseudoProperty
;
1024 auto* pseudo
= static_cast<Element
*>(mElement
->GetProperty(property
));
1025 return pseudo
? pseudo
->GetPrimaryFrame() : nullptr;
1028 void nsComputedDOMStyle::UpdateCurrentStyleSources(nsCSSPropertyID aPropID
) {
1029 nsCOMPtr
<Document
> document
= do_QueryReferent(mDocumentWeak
);
1031 ClearComputedStyle();
1035 // We don't return styles for disconnected elements anymore, so don't go
1036 // through the trouble of flushing or what not.
1038 // TODO(emilio): We may want to return earlier for elements outside of the
1039 // flat tree too: https://github.com/w3c/csswg-drafts/issues/1964
1040 if (!mElement
->IsInComposedDoc()) {
1041 ClearComputedStyle();
1045 if (mAlwaysReturnEmpty
== AlwaysReturnEmptyStyle::Yes
) {
1046 ClearComputedStyle();
1050 DebugOnly
<bool> didFlush
= false;
1051 if (NeedsToFlushStyle(aPropID
)) {
1053 // We look at the frame in NeedsToFlushLayout, so flush frames, not only
1055 Flush(*document
, FlushType::Frames
);
1058 if (NeedsToFlushLayout(aPropID
)) {
1059 MOZ_ASSERT(MayNeedToFlushLayout(aPropID
));
1061 Flush(*document
, FlushType::Layout
);
1063 mFlushedPendingReflows
= true;
1067 mFlushedPendingReflows
= false;
1071 mPresShell
= document
->GetPresShell();
1072 if (!mPresShell
|| !mPresShell
->GetPresContext()) {
1073 ClearComputedStyle();
1077 // We need to use GetUndisplayedRestyleGeneration instead of
1078 // GetRestyleGeneration, because the caching of mComputedStyle is an
1079 // optimization that is useful only for displayed elements.
1080 // For undisplayed elements we need to take into account any DOM changes that
1081 // might cause a restyle, because Servo will not increase the generation for
1082 // undisplayed elements.
1083 uint64_t currentGeneration
=
1084 mPresShell
->GetPresContext()->GetUndisplayedRestyleGeneration();
1086 if (mComputedStyle
&& mComputedStyleGeneration
== currentGeneration
&&
1087 mPresShellId
== mPresShell
->GetPresShellId()) {
1088 // Our cached style is still valid.
1092 mComputedStyle
= nullptr;
1094 // XXX the !mElement->IsHTMLElement(nsGkAtoms::area) check is needed due to
1095 // bug 135040 (to avoid using mPrimaryFrame). Remove it once that's fixed.
1096 if (mStyleType
== StyleType::All
&&
1097 !mElement
->IsHTMLElement(nsGkAtoms::area
)) {
1098 mOuterFrame
= GetOuterFrame();
1099 mInnerFrame
= mOuterFrame
;
1101 mInnerFrame
= nsLayoutUtils::GetStyleFrame(mOuterFrame
);
1102 SetFrameComputedStyle(mInnerFrame
->Style(), currentGeneration
);
1103 NS_ASSERTION(mComputedStyle
, "Frame without style?");
1107 if (!mComputedStyle
|| MustReresolveStyle(mComputedStyle
)) {
1108 PresShell
* presShellForContent
= mElement
->OwnerDoc()->GetPresShell();
1109 // Need to resolve a style.
1110 RefPtr
<const ComputedStyle
> resolvedComputedStyle
=
1111 DoGetComputedStyleNoFlush(
1112 mElement
, mPseudo
, mFunctionalPseudoParameter
,
1113 presShellForContent
? presShellForContent
: mPresShell
, mStyleType
);
1114 if (!resolvedComputedStyle
) {
1115 ClearComputedStyle();
1119 // No need to re-get the generation, even though GetComputedStyle
1120 // will flush, since we flushed style at the top of this function.
1121 // We don't need to check this if we only flushed the parent.
1124 currentGeneration
==
1125 mPresShell
->GetPresContext()->GetUndisplayedRestyleGeneration(),
1126 "why should we have flushed style again?");
1128 SetResolvedComputedStyle(std::move(resolvedComputedStyle
),
1130 NS_ASSERTION(mPseudo
!= PseudoStyleType::NotPseudo
||
1131 !mComputedStyle
->HasPseudoElementData(),
1132 "should not have pseudo-element data");
1135 // mExposeVisitedStyle is set to true only by testing APIs that
1136 // require chrome privilege.
1137 MOZ_ASSERT(!mExposeVisitedStyle
|| nsContentUtils::IsCallerChrome(),
1138 "mExposeVisitedStyle set incorrectly");
1139 if (mExposeVisitedStyle
&& mComputedStyle
->RelevantLinkVisited()) {
1140 if (const auto* styleIfVisited
= mComputedStyle
->GetStyleIfVisited()) {
1141 mComputedStyle
= styleIfVisited
;
1146 void nsComputedDOMStyle::ClearCurrentStyleSources() {
1147 // Release the current style if we got it off the frame.
1149 // For a style we resolved, keep it around so that we can re-use it next time
1150 // this object is queried, but not if it-s a re-resolved style because we were
1151 // inside a pseudo-element.
1152 if (!mResolvedComputedStyle
|| mOuterFrame
) {
1153 ClearComputedStyle();
1156 mOuterFrame
= nullptr;
1157 mInnerFrame
= nullptr;
1158 mPresShell
= nullptr;
1161 void nsComputedDOMStyle::RemoveProperty(const nsACString
& aPropertyName
,
1162 nsACString
& aReturn
, ErrorResult
& aRv
) {
1163 // Note: not using nsPrintfCString here in case aPropertyName contains
1165 aRv
.ThrowNoModificationAllowedError("Can't remove property '"_ns
+
1167 "' from computed style"_ns
);
1170 void nsComputedDOMStyle::GetPropertyPriority(const nsACString
& aPropertyName
,
1171 nsACString
& aReturn
) {
1175 void nsComputedDOMStyle::SetProperty(const nsACString
& aPropertyName
,
1176 const nsACString
& aValue
,
1177 const nsACString
& aPriority
,
1178 nsIPrincipal
* aSubjectPrincipal
,
1180 // Note: not using nsPrintfCString here in case aPropertyName contains
1182 aRv
.ThrowNoModificationAllowedError("Can't set value for property '"_ns
+
1183 aPropertyName
+ "' in computed style"_ns
);
1186 void nsComputedDOMStyle::IndexedGetter(uint32_t aIndex
, bool& aFound
,
1187 nsACString
& aPropName
) {
1188 ComputedStyleMap
* map
= GetComputedStyleMap();
1189 uint32_t length
= map
->Length();
1191 if (aIndex
< length
) {
1193 aPropName
.Assign(nsCSSProps::GetStringValue(map
->PropertyAt(aIndex
)));
1197 // Custom properties are exposed with indexed properties just after all
1198 // of the built-in properties.
1199 UpdateCurrentStyleSources(eCSSPropertyExtra_variable
);
1200 if (!mComputedStyle
) {
1205 uint32_t count
= Servo_GetCustomPropertiesCount(mComputedStyle
);
1207 const uint32_t index
= aIndex
- length
;
1208 if (index
< count
) {
1210 aPropName
.AssignLiteral("--");
1211 if (nsAtom
* atom
= Servo_GetCustomPropertyNameAt(mComputedStyle
, index
)) {
1212 aPropName
.Append(nsAtomCString(atom
));
1218 ClearCurrentStyleSources();
1221 // Property getters...
1223 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBottom() {
1224 return GetOffsetWidthFor(eSideBottom
);
1227 static Position
MaybeResolvePositionForTransform(const LengthPercentage
& aX
,
1228 const LengthPercentage
& aY
,
1229 nsIFrame
* aInnerFrame
) {
1233 nsStyleTransformMatrix::TransformReferenceBox
refBox(aInnerFrame
);
1234 CSSPoint p
= nsStyleTransformMatrix::Convert2DPosition(aX
, aY
, refBox
);
1235 return {LengthPercentage::FromPixels(p
.x
), LengthPercentage::FromPixels(p
.y
)};
1238 /* Convert the stored representation into a list of two values and then hand
1241 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetTransformOrigin() {
1242 /* We need to build up a list of two values. We'll call them
1246 /* Store things as a value list */
1247 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(false);
1249 /* Now, get the values. */
1250 const auto& origin
= StyleDisplay()->mTransformOrigin
;
1252 RefPtr
<nsROCSSPrimitiveValue
> width
= new nsROCSSPrimitiveValue
;
1253 auto position
= MaybeResolvePositionForTransform(
1254 origin
.horizontal
, origin
.vertical
, mInnerFrame
);
1255 SetValueToPosition(position
, valueList
);
1256 if (!origin
.depth
.IsZero()) {
1257 RefPtr
<nsROCSSPrimitiveValue
> depth
= new nsROCSSPrimitiveValue
;
1258 depth
->SetPixels(origin
.depth
.ToCSSPixels());
1259 valueList
->AppendCSSValue(depth
.forget());
1261 return valueList
.forget();
1264 /* Convert the stored representation into a list of two values and then hand
1267 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetPerspectiveOrigin() {
1268 /* We need to build up a list of two values. We'll call them
1272 /* Store things as a value list */
1273 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(false);
1275 /* Now, get the values. */
1276 const auto& origin
= StyleDisplay()->mPerspectiveOrigin
;
1278 auto position
= MaybeResolvePositionForTransform(
1279 origin
.horizontal
, origin
.vertical
, mInnerFrame
);
1280 SetValueToPosition(position
, valueList
);
1281 return valueList
.forget();
1284 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetTransform() {
1285 const nsStyleDisplay
* display
= StyleDisplay();
1286 return GetTransformValue(display
->mTransform
);
1290 already_AddRefed
<nsROCSSPrimitiveValue
> nsComputedDOMStyle::MatrixToCSSValue(
1291 const mozilla::gfx::Matrix4x4
& matrix
) {
1292 bool is3D
= !matrix
.Is2D();
1294 nsAutoString
resultString(u
"matrix"_ns
);
1296 resultString
.AppendLiteral("3d");
1299 resultString
.Append('(');
1300 resultString
.AppendFloat(matrix
._11
);
1301 resultString
.AppendLiteral(", ");
1302 resultString
.AppendFloat(matrix
._12
);
1303 resultString
.AppendLiteral(", ");
1305 resultString
.AppendFloat(matrix
._13
);
1306 resultString
.AppendLiteral(", ");
1307 resultString
.AppendFloat(matrix
._14
);
1308 resultString
.AppendLiteral(", ");
1310 resultString
.AppendFloat(matrix
._21
);
1311 resultString
.AppendLiteral(", ");
1312 resultString
.AppendFloat(matrix
._22
);
1313 resultString
.AppendLiteral(", ");
1315 resultString
.AppendFloat(matrix
._23
);
1316 resultString
.AppendLiteral(", ");
1317 resultString
.AppendFloat(matrix
._24
);
1318 resultString
.AppendLiteral(", ");
1319 resultString
.AppendFloat(matrix
._31
);
1320 resultString
.AppendLiteral(", ");
1321 resultString
.AppendFloat(matrix
._32
);
1322 resultString
.AppendLiteral(", ");
1323 resultString
.AppendFloat(matrix
._33
);
1324 resultString
.AppendLiteral(", ");
1325 resultString
.AppendFloat(matrix
._34
);
1326 resultString
.AppendLiteral(", ");
1328 resultString
.AppendFloat(matrix
._41
);
1329 resultString
.AppendLiteral(", ");
1330 resultString
.AppendFloat(matrix
._42
);
1332 resultString
.AppendLiteral(", ");
1333 resultString
.AppendFloat(matrix
._43
);
1334 resultString
.AppendLiteral(", ");
1335 resultString
.AppendFloat(matrix
._44
);
1337 resultString
.Append(')');
1339 /* Create a value to hold our result. */
1340 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1342 val
->SetString(resultString
);
1343 return val
.forget();
1346 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMozOsxFontSmoothing() {
1347 if (nsContentUtils::ShouldResistFingerprinting(
1348 mPresShell
->GetPresContext()->GetDocShell(),
1349 RFPTarget::DOMStyleOsxFontSmoothing
)) {
1353 nsAutoCString result
;
1354 mComputedStyle
->GetComputedPropertyValue(eCSSProperty__moz_osx_font_smoothing
,
1356 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1357 val
->SetString(result
);
1358 return val
.forget();
1361 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetImageLayerPosition(
1362 const nsStyleImageLayers
& aLayers
) {
1363 if (aLayers
.mPositionXCount
!= aLayers
.mPositionYCount
) {
1364 // No value to return. We can't express this combination of
1365 // values as a shorthand.
1369 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(true);
1370 for (uint32_t i
= 0, i_end
= aLayers
.mPositionXCount
; i
< i_end
; ++i
) {
1371 RefPtr
<nsDOMCSSValueList
> itemList
= GetROCSSValueList(false);
1373 SetValueToPosition(aLayers
.mLayers
[i
].mPosition
, itemList
);
1374 valueList
->AppendCSSValue(itemList
.forget());
1377 return valueList
.forget();
1380 void nsComputedDOMStyle::SetValueToPosition(const Position
& aPosition
,
1381 nsDOMCSSValueList
* aValueList
) {
1382 RefPtr
<nsROCSSPrimitiveValue
> valX
= new nsROCSSPrimitiveValue
;
1383 SetValueToLengthPercentage(valX
, aPosition
.horizontal
, false);
1384 aValueList
->AppendCSSValue(valX
.forget());
1386 RefPtr
<nsROCSSPrimitiveValue
> valY
= new nsROCSSPrimitiveValue
;
1387 SetValueToLengthPercentage(valY
, aPosition
.vertical
, false);
1388 aValueList
->AppendCSSValue(valY
.forget());
1391 enum class Brackets
{ No
, Yes
};
1393 static void AppendGridLineNames(nsACString
& aResult
,
1394 Span
<const StyleCustomIdent
> aLineNames
,
1395 Brackets aBrackets
) {
1396 if (aLineNames
.IsEmpty()) {
1397 if (aBrackets
== Brackets::Yes
) {
1398 aResult
.AppendLiteral("[]");
1402 uint32_t numLines
= aLineNames
.Length();
1403 if (aBrackets
== Brackets::Yes
) {
1404 aResult
.Append('[');
1406 for (uint32_t i
= 0;;) {
1407 // TODO: Maybe use servo to do this and avoid the silly utf16->utf8 dance?
1409 nsStyleUtil::AppendEscapedCSSIdent(
1410 nsDependentAtomString(aLineNames
[i
].AsAtom()), name
);
1411 AppendUTF16toUTF8(name
, aResult
);
1413 if (++i
== numLines
) {
1416 aResult
.Append(' ');
1418 if (aBrackets
== Brackets::Yes
) {
1419 aResult
.Append(']');
1423 static void AppendGridLineNames(nsDOMCSSValueList
* aValueList
,
1424 Span
<const StyleCustomIdent
> aLineNames
,
1425 bool aSuppressEmptyList
= true) {
1426 if (aLineNames
.IsEmpty() && aSuppressEmptyList
) {
1429 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1430 nsAutoCString lineNamesString
;
1431 AppendGridLineNames(lineNamesString
, aLineNames
, Brackets::Yes
);
1432 val
->SetString(lineNamesString
);
1433 aValueList
->AppendCSSValue(val
.forget());
1436 static void AppendGridLineNames(nsDOMCSSValueList
* aValueList
,
1437 Span
<const StyleCustomIdent
> aLineNames1
,
1438 Span
<const StyleCustomIdent
> aLineNames2
) {
1439 if (aLineNames1
.IsEmpty() && aLineNames2
.IsEmpty()) {
1442 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1443 nsAutoCString lineNamesString
;
1444 lineNamesString
.Assign('[');
1445 if (!aLineNames1
.IsEmpty()) {
1446 AppendGridLineNames(lineNamesString
, aLineNames1
, Brackets::No
);
1448 if (!aLineNames2
.IsEmpty()) {
1449 if (!aLineNames1
.IsEmpty()) {
1450 lineNamesString
.Append(' ');
1452 AppendGridLineNames(lineNamesString
, aLineNames2
, Brackets::No
);
1454 lineNamesString
.Append(']');
1455 val
->SetString(lineNamesString
);
1456 aValueList
->AppendCSSValue(val
.forget());
1459 void nsComputedDOMStyle::SetValueToTrackBreadth(
1460 nsROCSSPrimitiveValue
* aValue
, const StyleTrackBreadth
& aBreadth
) {
1461 using Tag
= StyleTrackBreadth::Tag
;
1462 switch (aBreadth
.tag
) {
1463 case Tag::MinContent
:
1464 return aValue
->SetString("min-content");
1465 case Tag::MaxContent
:
1466 return aValue
->SetString("max-content");
1468 return aValue
->SetString("auto");
1470 return SetValueToLengthPercentage(aValue
, aBreadth
.AsBreadth(), true);
1472 nsAutoString tmpStr
;
1473 nsStyleUtil::AppendCSSNumber(aBreadth
.AsFr(), tmpStr
);
1474 tmpStr
.AppendLiteral("fr");
1475 return aValue
->SetString(tmpStr
);
1478 MOZ_ASSERT_UNREACHABLE("Unknown breadth value");
1483 already_AddRefed
<nsROCSSPrimitiveValue
> nsComputedDOMStyle::GetGridTrackBreadth(
1484 const StyleTrackBreadth
& aBreadth
) {
1485 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1486 SetValueToTrackBreadth(val
, aBreadth
);
1487 return val
.forget();
1490 already_AddRefed
<nsROCSSPrimitiveValue
> nsComputedDOMStyle::GetGridTrackSize(
1491 const StyleTrackSize
& aTrackSize
) {
1492 if (aTrackSize
.IsFitContent()) {
1493 // A fit-content() function.
1494 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1495 MOZ_ASSERT(aTrackSize
.AsFitContent().IsBreadth(),
1496 "unexpected unit for fit-content() argument value");
1497 SetValueFromFitContentFunction(val
, aTrackSize
.AsFitContent().AsBreadth());
1498 return val
.forget();
1501 if (aTrackSize
.IsBreadth()) {
1502 return GetGridTrackBreadth(aTrackSize
.AsBreadth());
1505 MOZ_ASSERT(aTrackSize
.IsMinmax());
1506 const auto& min
= aTrackSize
.AsMinmax()._0
;
1507 const auto& max
= aTrackSize
.AsMinmax()._1
;
1509 return GetGridTrackBreadth(min
);
1512 // minmax(auto, <flex>) is equivalent to (and is our internal representation
1513 // of) <flex>, and both compute to <flex>
1514 if (min
.IsAuto() && max
.IsFr()) {
1515 return GetGridTrackBreadth(max
);
1518 nsAutoString argumentStr
, minmaxStr
;
1519 minmaxStr
.AppendLiteral("minmax(");
1522 RefPtr
<nsROCSSPrimitiveValue
> argValue
= GetGridTrackBreadth(min
);
1523 argValue
->GetCssText(argumentStr
);
1524 minmaxStr
.Append(argumentStr
);
1525 argumentStr
.Truncate();
1528 minmaxStr
.AppendLiteral(", ");
1531 RefPtr
<nsROCSSPrimitiveValue
> argValue
= GetGridTrackBreadth(max
);
1532 argValue
->GetCssText(argumentStr
);
1533 minmaxStr
.Append(argumentStr
);
1536 minmaxStr
.Append(char16_t(')'));
1537 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1538 val
->SetString(minmaxStr
);
1539 return val
.forget();
1542 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetGridTemplateColumnsRows(
1543 const StyleGridTemplateComponent
& aTrackList
,
1544 const ComputedGridTrackInfo
& aTrackInfo
) {
1545 if (aTrackInfo
.mIsMasonry
) {
1546 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1547 val
->SetString("masonry");
1548 return val
.forget();
1551 if (aTrackInfo
.mIsSubgrid
) {
1552 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(false);
1553 RefPtr
<nsROCSSPrimitiveValue
> subgridKeyword
= new nsROCSSPrimitiveValue
;
1554 subgridKeyword
->SetString("subgrid");
1555 valueList
->AppendCSSValue(subgridKeyword
.forget());
1556 for (const auto& lineNames
: aTrackInfo
.mResolvedLineNames
) {
1557 AppendGridLineNames(valueList
, lineNames
, /*aSuppressEmptyList*/ false);
1559 uint32_t line
= aTrackInfo
.mResolvedLineNames
.Length();
1560 uint32_t lastLine
= aTrackInfo
.mNumExplicitTracks
+ 1;
1561 const Span
<const StyleCustomIdent
> empty
;
1562 for (; line
< lastLine
; ++line
) {
1563 AppendGridLineNames(valueList
, empty
, /*aSuppressEmptyList*/ false);
1565 return valueList
.forget();
1568 const bool serializeImplicit
=
1569 StaticPrefs::layout_css_serialize_grid_implicit_tracks();
1571 const nsTArray
<nscoord
>& trackSizes
= aTrackInfo
.mSizes
;
1572 const uint32_t numExplicitTracks
= aTrackInfo
.mNumExplicitTracks
;
1573 const uint32_t numLeadingImplicitTracks
=
1574 aTrackInfo
.mNumLeadingImplicitTracks
;
1575 uint32_t numSizes
= trackSizes
.Length();
1576 MOZ_ASSERT(numSizes
>= numLeadingImplicitTracks
+ numExplicitTracks
);
1578 const bool hasTracksToSerialize
=
1579 serializeImplicit
? !!numSizes
: !!numExplicitTracks
;
1580 const bool hasRepeatAuto
= aTrackList
.HasRepeatAuto();
1581 if (!hasTracksToSerialize
&& !hasRepeatAuto
) {
1582 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1583 val
->SetString("none");
1584 return val
.forget();
1587 // We've done layout on the grid and have resolved the sizes of its tracks,
1588 // so we'll return those sizes here. The grid spec says we MAY use
1589 // repeat(<positive-integer>, Npx) here for consecutive tracks with the same
1590 // size, but that doesn't seem worth doing since even for repeat(auto-*)
1591 // the resolved size might differ for the repeated tracks.
1592 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(false);
1594 // Add any leading implicit tracks.
1595 if (serializeImplicit
) {
1596 for (uint32_t i
= 0; i
< numLeadingImplicitTracks
; ++i
) {
1597 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1598 val
->SetAppUnits(trackSizes
[i
]);
1599 valueList
->AppendCSSValue(val
.forget());
1603 if (hasRepeatAuto
) {
1604 const auto* const autoRepeatValue
= aTrackList
.GetRepeatAutoValue();
1605 const auto repeatLineNames
= autoRepeatValue
->line_names
.AsSpan();
1606 MOZ_ASSERT(repeatLineNames
.Length() >= 2);
1607 // Number of tracks inside the repeat, not including any repetitions.
1608 // Check that if we have truncated the number of tracks due to overflowing
1609 // the maximum track limit then we also truncate this repeat count.
1610 MOZ_ASSERT(repeatLineNames
.Length() ==
1611 autoRepeatValue
->track_sizes
.len
+ 1);
1612 // If we have truncated the first repetition of repeat tracks, then we
1613 // can't index using autoRepeatValue->track_sizes.len, and
1614 // aTrackInfo.mRemovedRepeatTracks.Length() will account for all repeat
1615 // tracks that haven't been truncated.
1616 const uint32_t numRepeatTracks
=
1617 std::min(aTrackInfo
.mRemovedRepeatTracks
.Length(),
1618 autoRepeatValue
->track_sizes
.len
);
1619 MOZ_ASSERT(repeatLineNames
.Length() >= numRepeatTracks
+ 1);
1620 // The total of all tracks in all repetitions of the repeat.
1621 const uint32_t totalNumRepeatTracks
=
1622 aTrackInfo
.mRemovedRepeatTracks
.Length();
1623 const uint32_t repeatStart
= aTrackInfo
.mRepeatFirstTrack
;
1624 // We need to skip over any track sizes which were resolved to 0 by
1625 // collapsed tracks. Keep track of the iteration separately.
1626 const auto explicitTrackSizeBegin
=
1627 trackSizes
.cbegin() + numLeadingImplicitTracks
;
1628 const auto explicitTrackSizeEnd
=
1629 explicitTrackSizeBegin
+ numExplicitTracks
;
1630 auto trackSizeIter
= explicitTrackSizeBegin
;
1631 // Write any leading explicit tracks before the repeat.
1632 for (uint32_t i
= 0; i
< repeatStart
; i
++) {
1633 AppendGridLineNames(valueList
, aTrackInfo
.mResolvedLineNames
[i
]);
1634 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1635 val
->SetAppUnits(*trackSizeIter
++);
1636 valueList
->AppendCSSValue(val
.forget());
1638 auto lineNameIter
= aTrackInfo
.mResolvedLineNames
.cbegin() + repeatStart
;
1639 // Write the track names at the start of the repeat, including the names
1640 // at the end of the last non-repeat track. Unlike all later repeat line
1641 // name lists, this one needs the resolved line name which includes both
1642 // the last non-repeat line names and the leading repeat line names.
1643 AppendGridLineNames(valueList
, *lineNameIter
++);
1645 // Write out the first repeat value, checking for size zero (removed
1647 const nscoord firstRepeatTrackSize
=
1648 (!aTrackInfo
.mRemovedRepeatTracks
[0]) ? *trackSizeIter
++ : 0;
1649 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1650 val
->SetAppUnits(firstRepeatTrackSize
);
1651 valueList
->AppendCSSValue(val
.forget());
1653 // Write the line names and track sizes inside the repeat, checking for
1654 // removed tracks (size 0).
1655 for (uint32_t i
= 1; i
< totalNumRepeatTracks
; i
++) {
1656 const uint32_t repeatIndex
= i
% numRepeatTracks
;
1657 // If we are rolling over from one repetition to the next, include track
1658 // names from both the end of the previous repeat and the start of the
1660 if (repeatIndex
== 0) {
1661 AppendGridLineNames(valueList
,
1662 repeatLineNames
[numRepeatTracks
].AsSpan(),
1663 repeatLineNames
[0].AsSpan());
1665 AppendGridLineNames(valueList
, repeatLineNames
[repeatIndex
].AsSpan());
1667 MOZ_ASSERT(aTrackInfo
.mRemovedRepeatTracks
[i
] ||
1668 trackSizeIter
!= explicitTrackSizeEnd
);
1669 const nscoord repeatTrackSize
=
1670 (!aTrackInfo
.mRemovedRepeatTracks
[i
]) ? *trackSizeIter
++ : 0;
1671 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1672 val
->SetAppUnits(repeatTrackSize
);
1673 valueList
->AppendCSSValue(val
.forget());
1675 // The resolved line names include a single repetition of the auto-repeat
1676 // line names. Skip over those.
1677 lineNameIter
+= numRepeatTracks
- 1;
1678 // Write out any more tracks after the repeat.
1679 while (trackSizeIter
!= explicitTrackSizeEnd
) {
1680 AppendGridLineNames(valueList
, *lineNameIter
++);
1681 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1682 val
->SetAppUnits(*trackSizeIter
++);
1683 valueList
->AppendCSSValue(val
.forget());
1685 // Write the final trailing line name.
1686 AppendGridLineNames(valueList
, *lineNameIter
++);
1687 } else if (numExplicitTracks
> 0) {
1688 // If there are explicit tracks but no repeat tracks, just serialize those.
1689 for (uint32_t i
= 0;; i
++) {
1690 AppendGridLineNames(valueList
, aTrackInfo
.mResolvedLineNames
[i
]);
1691 if (i
== numExplicitTracks
) {
1694 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1695 val
->SetAppUnits(trackSizes
[i
+ numLeadingImplicitTracks
]);
1696 valueList
->AppendCSSValue(val
.forget());
1699 // Add any trailing implicit tracks.
1700 if (serializeImplicit
) {
1701 for (uint32_t i
= numLeadingImplicitTracks
+ numExplicitTracks
;
1702 i
< numSizes
; ++i
) {
1703 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1704 val
->SetAppUnits(trackSizes
[i
]);
1705 valueList
->AppendCSSValue(val
.forget());
1709 return valueList
.forget();
1712 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetGridTemplateColumns() {
1713 nsGridContainerFrame
* gridFrame
=
1714 nsGridContainerFrame::GetGridFrameWithComputedInfo(mInnerFrame
);
1716 // The element doesn't have a box - return the computed value.
1717 // https://drafts.csswg.org/css-grid/#resolved-track-list
1718 nsAutoCString string
;
1719 mComputedStyle
->GetComputedPropertyValue(eCSSProperty_grid_template_columns
,
1721 RefPtr
<nsROCSSPrimitiveValue
> value
= new nsROCSSPrimitiveValue
;
1722 value
->SetString(string
);
1723 return value
.forget();
1726 // GetGridFrameWithComputedInfo() above ensures that this returns non-null:
1727 const ComputedGridTrackInfo
* info
= gridFrame
->GetComputedTemplateColumns();
1728 return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns
,
1732 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetGridTemplateRows() {
1733 nsGridContainerFrame
* gridFrame
=
1734 nsGridContainerFrame::GetGridFrameWithComputedInfo(mInnerFrame
);
1736 // The element doesn't have a box - return the computed value.
1737 // https://drafts.csswg.org/css-grid/#resolved-track-list
1738 nsAutoCString string
;
1739 mComputedStyle
->GetComputedPropertyValue(eCSSProperty_grid_template_rows
,
1741 RefPtr
<nsROCSSPrimitiveValue
> value
= new nsROCSSPrimitiveValue
;
1742 value
->SetString(string
);
1743 return value
.forget();
1746 // GetGridFrameWithComputedInfo() above ensures that this returns non-null:
1747 const ComputedGridTrackInfo
* info
= gridFrame
->GetComputedTemplateRows();
1748 return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows
, *info
);
1751 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetPaddingTop() {
1752 return GetPaddingWidthFor(eSideTop
);
1755 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetPaddingBottom() {
1756 return GetPaddingWidthFor(eSideBottom
);
1759 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetPaddingLeft() {
1760 return GetPaddingWidthFor(eSideLeft
);
1763 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetPaddingRight() {
1764 return GetPaddingWidthFor(eSideRight
);
1767 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBorderSpacing() {
1768 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(false);
1770 RefPtr
<nsROCSSPrimitiveValue
> xSpacing
= new nsROCSSPrimitiveValue
;
1771 RefPtr
<nsROCSSPrimitiveValue
> ySpacing
= new nsROCSSPrimitiveValue
;
1773 const nsStyleTableBorder
* border
= StyleTableBorder();
1774 xSpacing
->SetAppUnits(border
->mBorderSpacingCol
);
1775 ySpacing
->SetAppUnits(border
->mBorderSpacingRow
);
1777 valueList
->AppendCSSValue(xSpacing
.forget());
1778 valueList
->AppendCSSValue(ySpacing
.forget());
1780 return valueList
.forget();
1783 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBorderTopWidth() {
1784 return GetBorderWidthFor(eSideTop
);
1787 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBorderBottomWidth() {
1788 return GetBorderWidthFor(eSideBottom
);
1791 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBorderLeftWidth() {
1792 return GetBorderWidthFor(eSideLeft
);
1795 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBorderRightWidth() {
1796 return GetBorderWidthFor(eSideRight
);
1799 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMarginTop() {
1800 return GetMarginFor(eSideTop
);
1803 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMarginBottom() {
1804 return GetMarginFor(eSideBottom
);
1807 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMarginLeft() {
1808 return GetMarginFor(eSideLeft
);
1811 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMarginRight() {
1812 return GetMarginFor(eSideRight
);
1815 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetHeight() {
1816 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1818 if (mInnerFrame
&& !IsNonReplacedInline(mInnerFrame
)) {
1819 AssertFlushedPendingReflows();
1820 nsMargin adjustedValues
= GetAdjustedValuesForBoxSizing();
1821 val
->SetAppUnits(mInnerFrame
->GetContentRect().height
+
1822 adjustedValues
.TopBottom());
1824 SetValueToSize(val
, StylePosition()->mHeight
);
1827 return val
.forget();
1830 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetWidth() {
1831 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1833 if (mInnerFrame
&& !IsNonReplacedInline(mInnerFrame
)) {
1834 AssertFlushedPendingReflows();
1835 nsMargin adjustedValues
= GetAdjustedValuesForBoxSizing();
1836 val
->SetAppUnits(mInnerFrame
->GetContentRect().width
+
1837 adjustedValues
.LeftRight());
1839 SetValueToSize(val
, StylePosition()->mWidth
);
1842 return val
.forget();
1845 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMaxHeight() {
1846 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1847 SetValueToMaxSize(val
, StylePosition()->mMaxHeight
);
1848 return val
.forget();
1851 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMaxWidth() {
1852 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1853 SetValueToMaxSize(val
, StylePosition()->mMaxWidth
);
1854 return val
.forget();
1858 * This function indicates whether we should return "auto" as the
1859 * getComputedStyle() result for the (default) "min-width: auto" and
1860 * "min-height: auto" CSS values.
1862 * As of this writing, the CSS Sizing draft spec says this "auto" value
1863 * *always* computes to itself. However, for now, we only make it compute to
1864 * itself for grid and flex items (the containers where "auto" has special
1865 * significance), because those are the only areas where the CSSWG has actually
1866 * resolved on this "computes-to-itself" behavior. For elements in other sorts
1867 * of containers, this function returns false, which will make us resolve
1870 bool nsComputedDOMStyle::ShouldHonorMinSizeAutoInAxis(PhysicalAxis aAxis
) {
1871 return mOuterFrame
&& mOuterFrame
->IsFlexOrGridItem();
1874 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMinHeight() {
1875 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1876 StyleSize minHeight
= StylePosition()->mMinHeight
;
1878 if (minHeight
.IsAuto() && !ShouldHonorMinSizeAutoInAxis(eAxisVertical
)) {
1879 minHeight
= StyleSize::LengthPercentage(LengthPercentage::Zero());
1882 SetValueToSize(val
, minHeight
);
1883 return val
.forget();
1886 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMinWidth() {
1887 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1889 StyleSize minWidth
= StylePosition()->mMinWidth
;
1891 if (minWidth
.IsAuto() && !ShouldHonorMinSizeAutoInAxis(eAxisHorizontal
)) {
1892 minWidth
= StyleSize::LengthPercentage(LengthPercentage::Zero());
1895 SetValueToSize(val
, minWidth
);
1896 return val
.forget();
1899 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetLeft() {
1900 return GetOffsetWidthFor(eSideLeft
);
1903 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetRight() {
1904 return GetOffsetWidthFor(eSideRight
);
1907 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetTop() {
1908 return GetOffsetWidthFor(eSideTop
);
1911 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetOffsetWidthFor(
1912 mozilla::Side aSide
) {
1913 const nsStyleDisplay
* display
= StyleDisplay();
1915 mozilla::StylePositionProperty position
= display
->mPosition
;
1917 // GetNonStaticPositionOffset or GetAbsoluteOffset don't handle elements
1918 // without frames in any sensible way. GetStaticOffset, however, is perfect
1920 position
= StylePositionProperty::Static
;
1924 case StylePositionProperty::Static
:
1925 return GetStaticOffset(aSide
);
1926 case StylePositionProperty::Sticky
:
1927 return GetNonStaticPositionOffset(
1928 aSide
, false, &nsComputedDOMStyle::GetScrollFrameContentWidth
,
1929 &nsComputedDOMStyle::GetScrollFrameContentHeight
);
1930 case StylePositionProperty::Absolute
:
1931 case StylePositionProperty::Fixed
:
1932 return GetAbsoluteOffset(aSide
);
1933 case StylePositionProperty::Relative
:
1934 return GetNonStaticPositionOffset(
1935 aSide
, true, &nsComputedDOMStyle::GetCBContentWidth
,
1936 &nsComputedDOMStyle::GetCBContentHeight
);
1938 MOZ_ASSERT_UNREACHABLE("Invalid position");
1943 static_assert(eSideTop
== 0 && eSideRight
== 1 && eSideBottom
== 2 &&
1945 "box side constants not as expected for NS_OPPOSITE_SIDE");
1946 #define NS_OPPOSITE_SIDE(s_) mozilla::Side(((s_) + 2) & 3)
1948 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetNonStaticPositionOffset(
1949 mozilla::Side aSide
, bool aResolveAuto
, PercentageBaseGetter aWidthGetter
,
1950 PercentageBaseGetter aHeightGetter
) {
1951 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1953 const nsStylePosition
* positionData
= StylePosition();
1955 LengthPercentageOrAuto coord
= positionData
->mOffset
.Get(aSide
);
1957 if (coord
.IsAuto()) {
1958 if (!aResolveAuto
) {
1959 val
->SetString("auto");
1960 return val
.forget();
1962 coord
= positionData
->mOffset
.Get(NS_OPPOSITE_SIDE(aSide
));
1965 if (!coord
.IsLengthPercentage()) {
1966 val
->SetPixels(0.0f
);
1967 return val
.forget();
1970 auto& lp
= coord
.AsLengthPercentage();
1971 if (lp
.ConvertsToLength()) {
1972 val
->SetPixels(sign
* lp
.ToLengthInCSSPixels());
1973 return val
.forget();
1976 PercentageBaseGetter baseGetter
= (aSide
== eSideLeft
|| aSide
== eSideRight
)
1979 nscoord percentageBase
;
1980 if (!(this->*baseGetter
)(percentageBase
)) {
1981 val
->SetPixels(0.0f
);
1982 return val
.forget();
1984 nscoord result
= lp
.Resolve(percentageBase
);
1985 val
->SetAppUnits(sign
* result
);
1986 return val
.forget();
1989 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetAbsoluteOffset(
1990 mozilla::Side aSide
) {
1991 const auto& offset
= StylePosition()->mOffset
;
1992 const auto& coord
= offset
.Get(aSide
);
1993 const auto& oppositeCoord
= offset
.Get(NS_OPPOSITE_SIDE(aSide
));
1995 if (coord
.IsAuto() || oppositeCoord
.IsAuto()) {
1996 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1997 val
->SetAppUnits(GetUsedAbsoluteOffset(aSide
));
1998 return val
.forget();
2001 return GetNonStaticPositionOffset(
2002 aSide
, false, &nsComputedDOMStyle::GetCBPaddingRectWidth
,
2003 &nsComputedDOMStyle::GetCBPaddingRectHeight
);
2006 nscoord
nsComputedDOMStyle::GetUsedAbsoluteOffset(mozilla::Side aSide
) {
2007 MOZ_ASSERT(mOuterFrame
, "need a frame, so we can call GetContainingBlock()");
2009 nsIFrame
* container
= mOuterFrame
->GetContainingBlock();
2010 nsMargin margin
= mOuterFrame
->GetUsedMargin();
2011 nsMargin border
= container
->GetUsedBorder();
2012 nsMargin
scrollbarSizes(0, 0, 0, 0);
2013 nsRect rect
= mOuterFrame
->GetRect();
2014 nsRect containerRect
= container
->GetRect();
2016 if (container
->IsViewportFrame()) {
2017 // For absolutely positioned frames scrollbars are taken into
2018 // account by virtue of getting a containing block that does
2019 // _not_ include the scrollbars. For fixed positioned frames,
2020 // the containing block is the viewport, which _does_ include
2021 // scrollbars. We have to do some extra work.
2022 // the first child in the default frame list is what we want
2023 nsIFrame
* scrollingChild
= container
->PrincipalChildList().FirstChild();
2024 nsIScrollableFrame
* scrollFrame
= do_QueryFrame(scrollingChild
);
2026 scrollbarSizes
= scrollFrame
->GetActualScrollbarSizes();
2029 // The viewport size might have been expanded by the visual viewport or
2030 // the minimum-scale size.
2031 const ViewportFrame
* viewportFrame
= do_QueryFrame(container
);
2032 MOZ_ASSERT(viewportFrame
);
2033 containerRect
.SizeTo(
2034 viewportFrame
->AdjustViewportSizeForFixedPosition(containerRect
));
2035 } else if (container
->IsGridContainerFrame() &&
2036 mOuterFrame
->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
)) {
2037 containerRect
= nsGridContainerFrame::GridItemCB(mOuterFrame
);
2038 rect
.MoveBy(-containerRect
.x
, -containerRect
.y
);
2044 offset
= rect
.y
- margin
.top
- border
.top
- scrollbarSizes
.top
;
2048 offset
= containerRect
.width
- rect
.width
- rect
.x
- margin
.right
-
2049 border
.right
- scrollbarSizes
.right
;
2053 offset
= containerRect
.height
- rect
.height
- rect
.y
- margin
.bottom
-
2054 border
.bottom
- scrollbarSizes
.bottom
;
2058 offset
= rect
.x
- margin
.left
- border
.left
- scrollbarSizes
.left
;
2062 NS_ERROR("Invalid side");
2069 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetStaticOffset(
2070 mozilla::Side aSide
) {
2071 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2072 SetValueToLengthPercentageOrAuto(val
, StylePosition()->mOffset
.Get(aSide
),
2074 return val
.forget();
2077 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetPaddingWidthFor(
2078 mozilla::Side aSide
) {
2079 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2081 auto& padding
= StylePadding()->mPadding
.Get(aSide
);
2082 if (!mInnerFrame
|| !PaddingNeedsUsedValue(padding
, *mComputedStyle
)) {
2083 SetValueToLengthPercentage(val
, padding
, true);
2085 AssertFlushedPendingReflows();
2086 val
->SetAppUnits(mInnerFrame
->GetUsedPadding().Side(aSide
));
2089 return val
.forget();
2092 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetBorderWidthFor(
2093 mozilla::Side aSide
) {
2094 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2097 if (mInnerFrame
&& mComputedStyle
->StyleDisplay()->HasAppearance()) {
2098 AssertFlushedPendingReflows();
2099 width
= mInnerFrame
->GetUsedBorder().Side(aSide
);
2101 width
= StyleBorder()->GetComputedBorderWidth(aSide
);
2103 val
->SetAppUnits(width
);
2105 return val
.forget();
2108 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetMarginFor(Side aSide
) {
2109 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2111 auto& margin
= StyleMargin()->mMargin
.Get(aSide
);
2112 if (!mInnerFrame
|| margin
.ConvertsToLength()) {
2113 SetValueToLengthPercentageOrAuto(val
, margin
, false);
2115 AssertFlushedPendingReflows();
2117 // For tables, GetUsedMargin always returns an empty margin, so we
2118 // should read the margin from the table wrapper frame instead.
2119 val
->SetAppUnits(mOuterFrame
->GetUsedMargin().Side(aSide
));
2120 NS_ASSERTION(mOuterFrame
== mInnerFrame
||
2121 mInnerFrame
->GetUsedMargin() == nsMargin(0, 0, 0, 0),
2122 "Inner tables must have zero margins");
2125 return val
.forget();
2128 static void SetValueToExtremumLength(nsROCSSPrimitiveValue
* aValue
,
2129 nsIFrame::ExtremumLength aSize
) {
2131 case nsIFrame::ExtremumLength::MaxContent
:
2132 return aValue
->SetString("max-content");
2133 case nsIFrame::ExtremumLength::MinContent
:
2134 return aValue
->SetString("min-content");
2135 case nsIFrame::ExtremumLength::MozAvailable
:
2136 return aValue
->SetString("-moz-available");
2137 case nsIFrame::ExtremumLength::FitContent
:
2138 return aValue
->SetString("fit-content");
2139 case nsIFrame::ExtremumLength::FitContentFunction
:
2140 MOZ_ASSERT_UNREACHABLE("fit-content() should be handled separately");
2142 MOZ_ASSERT_UNREACHABLE("Unknown extremum length?");
2145 void nsComputedDOMStyle::SetValueFromFitContentFunction(
2146 nsROCSSPrimitiveValue
* aValue
, const LengthPercentage
& aLength
) {
2147 nsAutoString argumentStr
;
2148 SetValueToLengthPercentage(aValue
, aLength
, true);
2149 aValue
->GetCssText(argumentStr
);
2151 nsAutoString fitContentStr
;
2152 fitContentStr
.AppendLiteral("fit-content(");
2153 fitContentStr
.Append(argumentStr
);
2154 fitContentStr
.Append(u
')');
2155 aValue
->SetString(fitContentStr
);
2158 void nsComputedDOMStyle::SetValueToSize(nsROCSSPrimitiveValue
* aValue
,
2159 const StyleSize
& aSize
) {
2160 if (aSize
.IsAuto()) {
2161 return aValue
->SetString("auto");
2163 if (aSize
.IsFitContentFunction()) {
2164 return SetValueFromFitContentFunction(aValue
, aSize
.AsFitContentFunction());
2166 if (auto length
= nsIFrame::ToExtremumLength(aSize
)) {
2167 return SetValueToExtremumLength(aValue
, *length
);
2169 MOZ_ASSERT(aSize
.IsLengthPercentage());
2170 SetValueToLengthPercentage(aValue
, aSize
.AsLengthPercentage(), true);
2173 void nsComputedDOMStyle::SetValueToMaxSize(nsROCSSPrimitiveValue
* aValue
,
2174 const StyleMaxSize
& aSize
) {
2175 if (aSize
.IsNone()) {
2176 return aValue
->SetString("none");
2178 if (aSize
.IsFitContentFunction()) {
2179 return SetValueFromFitContentFunction(aValue
, aSize
.AsFitContentFunction());
2181 if (auto length
= nsIFrame::ToExtremumLength(aSize
)) {
2182 return SetValueToExtremumLength(aValue
, *length
);
2184 MOZ_ASSERT(aSize
.IsLengthPercentage());
2185 SetValueToLengthPercentage(aValue
, aSize
.AsLengthPercentage(), true);
2188 void nsComputedDOMStyle::SetValueToLengthPercentageOrAuto(
2189 nsROCSSPrimitiveValue
* aValue
, const LengthPercentageOrAuto
& aSize
,
2190 bool aClampNegativeCalc
) {
2191 if (aSize
.IsAuto()) {
2192 return aValue
->SetString("auto");
2194 SetValueToLengthPercentage(aValue
, aSize
.AsLengthPercentage(),
2195 aClampNegativeCalc
);
2198 void nsComputedDOMStyle::SetValueToLengthPercentage(
2199 nsROCSSPrimitiveValue
* aValue
, const mozilla::LengthPercentage
& aLength
,
2200 bool aClampNegativeCalc
) {
2201 if (aLength
.ConvertsToLength()) {
2202 CSSCoord length
= aLength
.ToLengthInCSSPixels();
2203 if (aClampNegativeCalc
) {
2204 length
= std::max(float(length
), 0.0f
);
2206 return aValue
->SetPixels(length
);
2208 if (aLength
.ConvertsToPercentage()) {
2209 float result
= aLength
.ToPercentage();
2210 if (aClampNegativeCalc
) {
2211 result
= std::max(result
, 0.0f
);
2213 return aValue
->SetPercent(result
);
2216 nsAutoCString result
;
2217 Servo_LengthPercentage_ToCss(&aLength
, &result
);
2218 aValue
->SetString(result
);
2221 bool nsComputedDOMStyle::GetCBContentWidth(nscoord
& aWidth
) {
2226 AssertFlushedPendingReflows();
2228 aWidth
= mOuterFrame
->GetContainingBlock()->GetContentRect().width
;
2232 bool nsComputedDOMStyle::GetCBContentHeight(nscoord
& aHeight
) {
2237 AssertFlushedPendingReflows();
2239 aHeight
= mOuterFrame
->GetContainingBlock()->GetContentRect().height
;
2243 bool nsComputedDOMStyle::GetCBPaddingRectWidth(nscoord
& aWidth
) {
2248 AssertFlushedPendingReflows();
2250 aWidth
= mOuterFrame
->GetContainingBlock()->GetPaddingRect().width
;
2254 bool nsComputedDOMStyle::GetCBPaddingRectHeight(nscoord
& aHeight
) {
2259 AssertFlushedPendingReflows();
2261 aHeight
= mOuterFrame
->GetContainingBlock()->GetPaddingRect().height
;
2265 bool nsComputedDOMStyle::GetScrollFrameContentWidth(nscoord
& aWidth
) {
2270 AssertFlushedPendingReflows();
2272 nsIScrollableFrame
* scrollableFrame
=
2273 nsLayoutUtils::GetNearestScrollableFrame(
2274 mOuterFrame
->GetParent(),
2275 nsLayoutUtils::SCROLLABLE_SAME_DOC
|
2276 nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN
);
2278 if (!scrollableFrame
) {
2282 scrollableFrame
->GetScrolledFrame()->GetContentRectRelativeToSelf().width
;
2286 bool nsComputedDOMStyle::GetScrollFrameContentHeight(nscoord
& aHeight
) {
2291 AssertFlushedPendingReflows();
2293 nsIScrollableFrame
* scrollableFrame
=
2294 nsLayoutUtils::GetNearestScrollableFrame(
2295 mOuterFrame
->GetParent(),
2296 nsLayoutUtils::SCROLLABLE_SAME_DOC
|
2297 nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN
);
2299 if (!scrollableFrame
) {
2302 aHeight
= scrollableFrame
->GetScrolledFrame()
2303 ->GetContentRectRelativeToSelf()
2308 bool nsComputedDOMStyle::GetFrameBorderRectWidth(nscoord
& aWidth
) {
2313 AssertFlushedPendingReflows();
2315 aWidth
= mInnerFrame
->GetSize().width
;
2319 bool nsComputedDOMStyle::GetFrameBorderRectHeight(nscoord
& aHeight
) {
2324 AssertFlushedPendingReflows();
2326 aHeight
= mInnerFrame
->GetSize().height
;
2330 /* If the property is "none", hand back "none" wrapped in a value.
2331 * Otherwise, compute the aggregate transform matrix and hands it back in a
2334 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetTransformValue(
2335 const StyleTransform
& aTransform
) {
2336 /* If there are no transforms, then we should construct a single-element
2337 * entry and hand it back.
2339 if (aTransform
.IsNone()) {
2340 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2341 val
->SetString("none");
2342 return val
.forget();
2345 /* Otherwise, we need to compute the current value of the transform matrix,
2346 * store it in a string, and hand it back to the caller.
2349 /* Use the inner frame for the reference box. If we don't have an inner
2350 * frame we use empty dimensions to allow us to continue (and percentage
2351 * values in the transform will simply give broken results).
2352 * TODO: There is no good way for us to represent the case where there's no
2353 * frame, which is problematic. The reason is that when we have percentage
2354 * transforms, there are a total of four stored matrix entries that influence
2355 * the transform based on the size of the element. However, this poses a
2356 * problem, because only two of these values can be explicitly referenced
2357 * using the named transforms. Until a real solution is found, we'll just
2358 * use this approach.
2360 nsStyleTransformMatrix::TransformReferenceBox
refBox(mInnerFrame
, nsRect());
2361 gfx::Matrix4x4 matrix
= nsStyleTransformMatrix::ReadTransforms(
2362 aTransform
, refBox
, float(mozilla::AppUnitsPerCSSPixel()));
2364 return MatrixToCSSValue(matrix
);
2367 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DummyGetter() {
2368 MOZ_CRASH("DummyGetter is not supposed to be invoked");
2371 static void MarkComputedStyleMapDirty(const char* aPref
, void* aMap
) {
2372 static_cast<ComputedStyleMap
*>(aMap
)->MarkDirty();
2375 void nsComputedDOMStyle::ParentChainChanged(nsIContent
* aContent
) {
2376 NS_ASSERTION(mElement
== aContent
, "didn't we register mElement?");
2377 NS_ASSERTION(mResolvedComputedStyle
,
2378 "should have only registered an observer when "
2379 "mResolvedComputedStyle is true");
2381 ClearComputedStyle();
2385 ComputedStyleMap
* nsComputedDOMStyle::GetComputedStyleMap() {
2386 static ComputedStyleMap map
{};
2390 static StaticAutoPtr
<nsTArray
<const char*>> gCallbackPrefs
;
2393 void nsComputedDOMStyle::RegisterPrefChangeCallbacks() {
2394 // Note that this will register callbacks for all properties with prefs, not
2395 // just those that are implemented on computed style objects, as it's not
2396 // easy to grab specific property data from ServoCSSPropList.h based on the
2397 // entries iterated in nsComputedDOMStylePropertyList.h.
2399 AutoTArray
<const char*, 64> prefs
;
2400 for (const auto* p
= nsCSSProps::kPropertyPrefTable
;
2401 p
->mPropID
!= eCSSProperty_UNKNOWN
; p
++) {
2402 // Many properties are controlled by the same preference, so de-duplicate
2403 // them before adding observers.
2405 // Note: This is done by pointer comparison, which works because the mPref
2406 // members are string literals from the same same translation unit, and are
2407 // therefore de-duplicated by the compiler. On the off chance that we wind
2408 // up with some duplicates with different pointers, though, it's not a bit
2410 if (!prefs
.ContainsSorted(p
->mPref
)) {
2411 prefs
.InsertElementSorted(p
->mPref
);
2415 prefs
.AppendElement(
2416 StaticPrefs::GetPrefName_layout_css_computed_style_shorthands());
2418 prefs
.AppendElement(nullptr);
2420 MOZ_ASSERT(!gCallbackPrefs
);
2421 gCallbackPrefs
= new nsTArray
<const char*>(std::move(prefs
));
2423 Preferences::RegisterCallbacks(MarkComputedStyleMapDirty
,
2424 gCallbackPrefs
->Elements(),
2425 GetComputedStyleMap());
2429 void nsComputedDOMStyle::UnregisterPrefChangeCallbacks() {
2430 if (!gCallbackPrefs
) {
2434 Preferences::UnregisterCallbacks(MarkComputedStyleMapDirty
,
2435 gCallbackPrefs
->Elements(),
2436 GetComputedStyleMap());
2437 gCallbackPrefs
= nullptr;