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/StaticPtr.h"
18 #include "mozilla/StaticPrefs_layout.h"
22 #include "nsIFrameInlines.h"
23 #include "mozilla/ComputedStyle.h"
24 #include "nsIScrollableFrame.h"
25 #include "nsContentUtils.h"
26 #include "nsDocShell.h"
27 #include "nsIContent.h"
28 #include "nsStyleConsts.h"
30 #include "nsDOMCSSValueList.h"
31 #include "nsFlexContainerFrame.h"
32 #include "nsGridContainerFrame.h"
33 #include "nsGkAtoms.h"
34 #include "mozilla/ReflowInput.h"
35 #include "nsStyleUtil.h"
36 #include "nsStyleStructInlines.h"
37 #include "nsROCSSPrimitiveValue.h"
39 #include "nsPresContext.h"
40 #include "mozilla/dom/Document.h"
42 #include "nsCSSProps.h"
43 #include "nsCSSPseudoElements.h"
44 #include "mozilla/EffectSet.h"
45 #include "mozilla/IntegerRange.h"
46 #include "mozilla/ServoStyleSet.h"
47 #include "mozilla/RestyleManager.h"
48 #include "mozilla/ViewportFrame.h"
49 #include "nsLayoutUtils.h"
50 #include "nsDisplayList.h"
51 #include "nsDOMCSSDeclaration.h"
52 #include "nsStyleTransformMatrix.h"
53 #include "mozilla/dom/Element.h"
54 #include "mozilla/dom/ElementInlines.h"
56 #include "nsWrapperCacheInlines.h"
57 #include "mozilla/AppUnits.h"
59 #include "mozilla/ComputedStyleInlines.h"
60 #include "nsPrintfCString.h"
62 using namespace mozilla
;
63 using namespace mozilla::dom
;
65 #if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
66 # define DEBUG_ComputedDOMStyle
70 * This is the implementation of the readonly CSSStyleDeclaration that is
71 * returned by the getComputedStyle() function.
74 already_AddRefed
<nsComputedDOMStyle
> NS_NewComputedDOMStyle(
75 dom::Element
* aElement
, const nsAString
& aPseudoElt
, Document
* aDocument
,
76 nsComputedDOMStyle::StyleType aStyleType
) {
77 RefPtr
<nsComputedDOMStyle
> computedStyle
=
78 new nsComputedDOMStyle(aElement
, aPseudoElt
, aDocument
, aStyleType
);
79 return computedStyle
.forget();
82 static nsDOMCSSValueList
* GetROCSSValueList(bool aCommaDelimited
) {
83 return new nsDOMCSSValueList(aCommaDelimited
);
86 // Whether aDocument needs to restyle for aElement
87 static bool ElementNeedsRestyle(Element
* aElement
, nsAtom
* aPseudo
,
88 bool aMayNeedToFlushLayout
) {
89 const Document
* doc
= aElement
->GetComposedDoc();
91 // If the element is out of the document we don't return styles for it, so
96 PresShell
* presShell
= doc
->GetPresShell();
98 // If there's no pres-shell we'll just either mint a new style from our
99 // caller document, or return no styles, so nothing to do (unless our owner
100 // element needs to get restyled, which could cause us to gain a pres shell,
101 // but the caller checks that).
105 // Unfortunately we don't know if the sheet change affects mElement or not, so
106 // just assume it will and that we need to flush normally.
107 ServoStyleSet
* styleSet
= presShell
->StyleSet();
108 if (styleSet
->StyleSheetsHaveChanged()) {
112 nsPresContext
* presContext
= presShell
->GetPresContext();
113 MOZ_ASSERT(presContext
);
115 // Pending media query updates can definitely change style on the element. For
116 // example, if you change the zoom factor and then call getComputedStyle, you
117 // should be able to observe the style with the new media queries.
119 // TODO(emilio): Does this need to also check the user font set? (it affects
121 if (presContext
->HasPendingMediaQueryUpdates()) {
126 // If the pseudo-element is animating, make sure to flush.
127 if (aElement
->MayHaveAnimations() && aPseudo
) {
128 if (aPseudo
== nsCSSPseudoElements::before()) {
129 if (EffectSet::GetEffectSet(aElement
, PseudoStyleType::before
)) {
132 } else if (aPseudo
== nsCSSPseudoElements::after()) {
133 if (EffectSet::GetEffectSet(aElement
, PseudoStyleType::after
)) {
136 } else if (aPseudo
== nsCSSPseudoElements::marker()) {
137 if (EffectSet::GetEffectSet(aElement
, PseudoStyleType::marker
)) {
143 // For Servo, we need to process the restyle-hint-invalidations first, to
144 // expand LaterSiblings hint, so that we can look whether ancestors need
146 RestyleManager
* restyleManager
= presContext
->RestyleManager();
147 restyleManager
->ProcessAllPendingAttributeAndStateInvalidations();
149 if (!presContext
->EffectCompositor()->HasPendingStyleUpdates() &&
150 !doc
->GetServoRestyleRoot()) {
154 // Then if there is a restyle root, we check if the root is an ancestor of
155 // this content. If it is not, then we don't need to restyle immediately.
156 // Note this is different from Gecko: we only check if any ancestor needs
157 // to restyle _itself_, not descendants, since dirty descendants can be
159 return Servo_HasPendingRestyleAncestor(aElement
, aMayNeedToFlushLayout
);
163 * An object that represents the ordered set of properties that are exposed on
164 * an nsComputedDOMStyle object and how their computed values can be obtained.
166 struct ComputedStyleMap
{
167 friend class nsComputedDOMStyle
;
170 // Create a pointer-to-member-function type.
171 typedef already_AddRefed
<CSSValue
> (nsComputedDOMStyle::*ComputeMethod
)();
173 nsCSSPropertyID mProperty
;
174 ComputeMethod mGetter
;
176 bool IsEnabled() const {
177 return nsCSSProps::IsEnabled(mProperty
, CSSEnabledState::ForAllContent
);
181 // This generated file includes definition of kEntries which is typed
182 // Entry[] and used below, so this #include has to be put here.
183 #include "nsComputedDOMStyleGenerated.inc"
186 * Returns the number of properties that should be exposed on an
187 * nsComputedDOMStyle, ecxluding any disabled properties.
191 return mExposedPropertyCount
;
195 * Returns the property at the given index in the list of properties
196 * that should be exposed on an nsComputedDOMStyle, excluding any
197 * disabled properties.
199 nsCSSPropertyID
PropertyAt(uint32_t aIndex
) {
201 return kEntries
[EntryIndex(aIndex
)].mProperty
;
205 * Searches for and returns the computed style map entry for the given
206 * property, or nullptr if the property is not exposed on nsComputedDOMStyle
207 * or is currently disabled.
209 const Entry
* FindEntryForProperty(nsCSSPropertyID aPropID
) {
211 for (uint32_t i
= 0; i
< mExposedPropertyCount
; i
++) {
212 const Entry
* entry
= &kEntries
[EntryIndex(i
)];
213 if (entry
->mProperty
== aPropID
) {
221 * Records that mIndexMap needs updating, due to prefs changing that could
222 * affect the set of properties exposed on an nsComputedDOMStyle.
224 void MarkDirty() { mExposedPropertyCount
= 0; }
226 // The member variables are public so that we can use an initializer in
227 // nsComputedDOMStyle::GetComputedStyleMap. Use the member functions
228 // above to get information from this object.
231 * The number of properties that should be exposed on an nsComputedDOMStyle.
232 * This will be less than eComputedStyleProperty_COUNT if some property
233 * prefs are disabled. A value of 0 indicates that it and mIndexMap are out
236 uint32_t mExposedPropertyCount
;
239 * A map of indexes on the nsComputedDOMStyle object to indexes into kEntries.
241 uint32_t mIndexMap
[ArrayLength(kEntries
)];
245 * Returns whether mExposedPropertyCount and mIndexMap are out of date.
247 bool IsDirty() { return mExposedPropertyCount
== 0; }
250 * Updates mExposedPropertyCount and mIndexMap to take into account properties
251 * whose prefs are currently disabled.
256 * Maps an nsComputedDOMStyle indexed getter index to an index into kEntries.
258 uint32_t EntryIndex(uint32_t aIndex
) const {
259 MOZ_ASSERT(aIndex
< mExposedPropertyCount
);
260 return mIndexMap
[aIndex
];
264 constexpr ComputedStyleMap::Entry
265 ComputedStyleMap::kEntries
[ArrayLength(kEntries
)];
267 void ComputedStyleMap::Update() {
273 for (uint32_t i
= 0; i
< ArrayLength(kEntries
); i
++) {
274 if (kEntries
[i
].IsEnabled()) {
275 mIndexMap
[index
++] = i
;
278 mExposedPropertyCount
= index
;
281 nsComputedDOMStyle::nsComputedDOMStyle(dom::Element
* aElement
,
282 const nsAString
& aPseudoElt
,
284 StyleType aStyleType
)
285 : mDocumentWeak(nullptr),
286 mOuterFrame(nullptr),
287 mInnerFrame(nullptr),
289 mStyleType(aStyleType
),
290 mExposeVisitedStyle(false),
291 mResolvedComputedStyle(false) {
292 MOZ_ASSERT(aElement
);
293 MOZ_ASSERT(aDocument
);
294 // TODO(emilio, bug 548397, https://github.com/w3c/csswg-drafts/issues/2403):
295 // Should use aElement->OwnerDoc() instead.
296 mDocumentWeak
= do_GetWeakReference(aDocument
);
298 mPseudo
= nsCSSPseudoElements::GetPseudoAtom(aPseudoElt
);
301 nsComputedDOMStyle::~nsComputedDOMStyle() {
302 MOZ_ASSERT(!mResolvedComputedStyle
,
303 "Should have called ClearComputedStyle() during last release.");
306 NS_IMPL_CYCLE_COLLECTION_CLASS(nsComputedDOMStyle
)
308 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsComputedDOMStyle
)
309 tmp
->ClearComputedStyle(); // remove observer before clearing mElement
310 NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement
)
311 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
312 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
314 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsComputedDOMStyle
)
315 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement
)
316 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
318 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsComputedDOMStyle
)
320 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle
)
321 return tmp
->HasKnownLiveWrapper();
322 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
324 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsComputedDOMStyle
)
325 return tmp
->HasKnownLiveWrapper();
326 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
328 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsComputedDOMStyle
)
329 return tmp
->HasKnownLiveWrapper();
330 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
332 // QueryInterface implementation for nsComputedDOMStyle
333 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsComputedDOMStyle
)
334 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
335 NS_INTERFACE_MAP_ENTRY(nsIMutationObserver
)
336 NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration
)
338 NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(nsComputedDOMStyle
)
339 NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(
340 nsComputedDOMStyle
, ClearComputedStyle())
342 nsresult
nsComputedDOMStyle::GetPropertyValue(const nsCSSPropertyID aPropID
,
344 // This is mostly to avoid code duplication with GetPropertyCSSValue(); if
345 // perf ever becomes an issue here (doubtful), we can look into changing
347 return GetPropertyValue(nsCSSProps::GetStringValue(aPropID
), aValue
);
350 void nsComputedDOMStyle::SetPropertyValue(const nsCSSPropertyID aPropID
,
351 const nsACString
& aValue
,
352 nsIPrincipal
* aSubjectPrincipal
,
354 aRv
.ThrowNoModificationAllowedError(nsPrintfCString(
355 "Can't set value for property '%s' in computed style",
356 PromiseFlatCString(nsCSSProps::GetStringValue(aPropID
)).get()));
359 void nsComputedDOMStyle::GetCssText(nsAString
& aCssText
) {
363 void nsComputedDOMStyle::SetCssText(const nsAString
& aCssText
,
364 nsIPrincipal
* aSubjectPrincipal
,
366 aRv
.ThrowNoModificationAllowedError("Can't set cssText on computed style");
369 uint32_t nsComputedDOMStyle::Length() {
370 // Make sure we have up to date style so that we can include custom
372 UpdateCurrentStyleSources(eCSSPropertyExtra_variable
);
373 if (!mComputedStyle
) {
377 uint32_t length
= GetComputedStyleMap()->Length() +
378 Servo_GetCustomPropertiesCount(mComputedStyle
);
380 ClearCurrentStyleSources();
385 css::Rule
* nsComputedDOMStyle::GetParentRule() { return nullptr; }
388 nsComputedDOMStyle::GetPropertyValue(const nsACString
& aPropertyName
,
389 nsAString
& aReturn
) {
392 nsCSSPropertyID prop
= nsCSSProps::LookupProperty(aPropertyName
);
394 const ComputedStyleMap::Entry
* entry
= nullptr;
395 if (prop
!= eCSSPropertyExtra_variable
) {
396 entry
= GetComputedStyleMap()->FindEntryForProperty(prop
);
402 UpdateCurrentStyleSources(prop
);
403 if (!mComputedStyle
) {
407 auto cleanup
= mozilla::MakeScopeExit([&] { ClearCurrentStyleSources(); });
410 MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName
));
411 const nsACString
& name
=
412 Substring(aPropertyName
, CSS_CUSTOM_NAME_PREFIX_LENGTH
);
413 Servo_GetCustomPropertyValue(mComputedStyle
, &name
, &aReturn
);
417 if (nsCSSProps::PropHasFlags(prop
, CSSPropFlags::IsLogical
)) {
419 MOZ_ASSERT(entry
->mGetter
== &nsComputedDOMStyle::DummyGetter
);
421 DebugOnly
<nsCSSPropertyID
> logicalProp
= prop
;
423 prop
= Servo_ResolveLogicalProperty(prop
, mComputedStyle
);
424 entry
= GetComputedStyleMap()->FindEntryForProperty(prop
);
426 MOZ_ASSERT(NeedsToFlushLayout(logicalProp
) == NeedsToFlushLayout(prop
),
427 "Logical and physical property don't agree on whether layout is "
431 if (!nsCSSProps::PropHasFlags(prop
, CSSPropFlags::SerializedByServo
)) {
432 if (RefPtr
<CSSValue
> value
= (this->*entry
->mGetter
)()) {
435 value
->GetCssText(text
, rv
);
436 aReturn
.Assign(text
);
437 return rv
.StealNSResult();
442 MOZ_ASSERT(entry
->mGetter
== &nsComputedDOMStyle::DummyGetter
);
443 mComputedStyle
->GetComputedPropertyValue(prop
, aReturn
);
448 already_AddRefed
<ComputedStyle
> nsComputedDOMStyle::GetComputedStyle(
449 Element
* aElement
, nsAtom
* aPseudo
, StyleType aStyleType
) {
450 if (Document
* doc
= aElement
->GetComposedDoc()) {
451 doc
->FlushPendingNotifications(FlushType::Style
);
453 return GetComputedStyleNoFlush(aElement
, aPseudo
, aStyleType
);
457 * The following function checks whether we need to explicitly resolve the style
458 * again, even though we have a style coming from the frame.
460 * This basically checks whether the style is or may be under a ::first-line or
461 * ::first-letter frame, in which case we can't return the frame style, and we
462 * need to resolve it. See bug 505515.
464 static bool MustReresolveStyle(const mozilla::ComputedStyle
* aStyle
) {
467 // TODO(emilio): We may want to avoid re-resolving pseudo-element styles
469 return aStyle
->HasPseudoElementData() && !aStyle
->IsPseudoElement();
472 static inline PseudoStyleType
GetPseudoType(nsAtom
* aPseudo
) {
474 return PseudoStyleType::NotPseudo
;
476 return nsCSSPseudoElements::GetPseudoType(aPseudo
,
477 CSSEnabledState::ForAllContent
);
480 already_AddRefed
<ComputedStyle
> nsComputedDOMStyle::DoGetComputedStyleNoFlush(
481 Element
* aElement
, nsAtom
* aPseudo
, PresShell
* aPresShell
,
482 StyleType aStyleType
) {
483 MOZ_ASSERT(aElement
, "NULL element");
485 // If the content has a pres shell, we must use it. Otherwise we'd
486 // potentially mix rule trees by using the wrong pres shell's style
487 // set. Using the pres shell from the content also means that any
488 // content that's actually *in* a document will get the style from the
490 PresShell
* presShell
= nsContentUtils::GetPresShellForContent(aElement
);
491 bool inDocWithShell
= true;
493 inDocWithShell
= false;
494 presShell
= aPresShell
;
500 PseudoStyleType pseudoType
= GetPseudoType(aPseudo
);
501 if (aPseudo
&& !PseudoStyle::IsPseudoElement(pseudoType
)) {
505 if (!aElement
->IsInComposedDoc()) {
506 // Don't return styles for disconnected elements, that makes no sense. This
507 // can only happen with a non-null presShell for cross-document calls.
509 // FIXME(emilio, bug 1483798): This should also not return styles for
510 // elements outside of the flat tree, not just outside of the document.
514 // XXX the !aElement->IsHTMLElement(nsGkAtoms::area)
515 // check is needed due to bug 135040 (to avoid using
516 // mPrimaryFrame). Remove it once that's fixed.
517 if (inDocWithShell
&& aStyleType
== eAll
&&
518 !aElement
->IsHTMLElement(nsGkAtoms::area
)) {
519 Element
* element
= nullptr;
520 if (aPseudo
== nsCSSPseudoElements::before()) {
521 element
= nsLayoutUtils::GetBeforePseudo(aElement
);
522 } else if (aPseudo
== nsCSSPseudoElements::after()) {
523 element
= nsLayoutUtils::GetAfterPseudo(aElement
);
524 } else if (aPseudo
== nsCSSPseudoElements::marker()) {
525 element
= nsLayoutUtils::GetMarkerPseudo(aElement
);
526 } else if (!aPseudo
) {
531 if (nsIFrame
* styleFrame
= nsLayoutUtils::GetStyleFrame(element
)) {
532 ComputedStyle
* result
= styleFrame
->Style();
533 // Don't use the style if it was influenced by pseudo-elements,
534 // since then it's not the primary style for this element / pseudo.
535 if (!MustReresolveStyle(result
)) {
536 RefPtr
<ComputedStyle
> ret
= result
;
543 // No frame has been created, or we have a pseudo, or we're looking
544 // for the default style, so resolve the style ourselves.
545 ServoStyleSet
* styleSet
= presShell
->StyleSet();
547 StyleRuleInclusion rules
= aStyleType
== eDefaultOnly
548 ? StyleRuleInclusion::DefaultOnly
549 : StyleRuleInclusion::All
;
550 RefPtr
<ComputedStyle
> result
=
551 styleSet
->ResolveStyleLazily(*aElement
, pseudoType
, rules
);
552 return result
.forget();
555 already_AddRefed
<ComputedStyle
>
556 nsComputedDOMStyle::GetUnanimatedComputedStyleNoFlush(Element
* aElement
,
558 RefPtr
<ComputedStyle
> style
= GetComputedStyleNoFlush(aElement
, aPseudo
);
563 PseudoStyleType pseudoType
= GetPseudoType(aPseudo
);
564 PresShell
* presShell
= aElement
->OwnerDoc()->GetPresShell();
565 MOZ_ASSERT(presShell
,
566 "How in the world did we get a style a few lines above?");
568 Element
* elementOrPseudoElement
=
569 EffectCompositor::GetElementToRestyle(aElement
, pseudoType
);
570 if (!elementOrPseudoElement
) {
574 return presShell
->StyleSet()->GetBaseContextForElement(elementOrPseudoElement
,
578 nsMargin
nsComputedDOMStyle::GetAdjustedValuesForBoxSizing() {
579 // We want the width/height of whatever parts 'width' or 'height' controls,
580 // which can be different depending on the value of the 'box-sizing' property.
581 const nsStylePosition
* stylePos
= StylePosition();
584 if (stylePos
->mBoxSizing
== StyleBoxSizing::Border
) {
585 adjustment
= mInnerFrame
->GetUsedBorderAndPadding();
591 static void AddImageURL(nsIURI
& aURI
, nsTArray
<nsCString
>& aURLs
) {
593 nsresult rv
= aURI
.GetSpec(spec
);
598 aURLs
.AppendElement(std::move(spec
));
601 static void AddImageURL(const StyleComputedUrl
& aURL
,
602 nsTArray
<nsCString
>& aURLs
) {
603 if (aURL
.IsLocalRef()) {
607 if (nsIURI
* uri
= aURL
.GetURI()) {
608 AddImageURL(*uri
, aURLs
);
612 static void AddImageURL(const StyleImage
& aImage
, nsTArray
<nsCString
>& aURLs
) {
613 if (auto* urlValue
= aImage
.GetImageRequestURLValue()) {
614 AddImageURL(*urlValue
, aURLs
);
618 static void AddImageURL(const StyleShapeOutside
& aShapeOutside
,
619 nsTArray
<nsCString
>& aURLs
) {
620 if (aShapeOutside
.IsImage()) {
621 AddImageURL(aShapeOutside
.AsImage(), aURLs
);
625 static void AddImageURL(const StyleClipPath
& aClipPath
,
626 nsTArray
<nsCString
>& aURLs
) {
627 if (aClipPath
.IsUrl()) {
628 AddImageURL(aClipPath
.AsUrl(), aURLs
);
632 static void AddImageURLs(const nsStyleImageLayers
& aLayers
,
633 nsTArray
<nsCString
>& aURLs
) {
634 for (auto i
: IntegerRange(aLayers
.mLayers
.Length())) {
635 AddImageURL(aLayers
.mLayers
[i
].mImage
, aURLs
);
639 static void CollectImageURLsForProperty(nsCSSPropertyID aProp
,
640 const ComputedStyle
& aStyle
,
641 nsTArray
<nsCString
>& aURLs
) {
642 if (nsCSSProps::IsShorthand(aProp
)) {
643 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aProp
,
644 CSSEnabledState::ForAllContent
) {
645 CollectImageURLsForProperty(*p
, aStyle
, aURLs
);
651 case eCSSProperty_cursor
:
652 for (auto& image
: aStyle
.StyleUI()->mCursor
.images
.AsSpan()) {
653 AddImageURL(image
.url
, aURLs
);
656 case eCSSProperty_background_image
:
657 AddImageURLs(aStyle
.StyleBackground()->mImage
, aURLs
);
659 case eCSSProperty_mask_clip
:
660 AddImageURLs(aStyle
.StyleSVGReset()->mMask
, aURLs
);
662 case eCSSProperty_list_style_image
: {
663 const auto& image
= aStyle
.StyleList()->mListStyleImage
;
665 AddImageURL(image
.AsUrl(), aURLs
);
669 case eCSSProperty_border_image_source
:
670 AddImageURL(aStyle
.StyleBorder()->mBorderImageSource
, aURLs
);
672 case eCSSProperty_clip_path
:
673 AddImageURL(aStyle
.StyleSVGReset()->mClipPath
, aURLs
);
675 case eCSSProperty_shape_outside
:
676 AddImageURL(aStyle
.StyleDisplay()->mShapeOutside
, aURLs
);
683 void nsComputedDOMStyle::GetCSSImageURLs(const nsACString
& aPropertyName
,
684 nsTArray
<nsCString
>& aImageURLs
,
685 mozilla::ErrorResult
& aRv
) {
686 nsCSSPropertyID prop
= nsCSSProps::LookupProperty(aPropertyName
);
687 if (prop
== eCSSProperty_UNKNOWN
) {
688 // Note: not using nsPrintfCString here in case aPropertyName contains
690 aRv
.ThrowSyntaxError(NS_LITERAL_CSTRING("Invalid property name '") +
691 aPropertyName
+ NS_LITERAL_CSTRING("'"));
695 UpdateCurrentStyleSources(prop
);
697 if (!mComputedStyle
) {
701 CollectImageURLsForProperty(prop
, *mComputedStyle
, aImageURLs
);
702 ClearCurrentStyleSources();
705 // nsDOMCSSDeclaration abstract methods which should never be called
706 // on a nsComputedDOMStyle object, but must be defined to avoid
708 DeclarationBlock
* nsComputedDOMStyle::GetOrCreateCSSDeclaration(
709 Operation aOperation
, DeclarationBlock
** aCreated
) {
710 MOZ_CRASH("called nsComputedDOMStyle::GetCSSDeclaration");
713 nsresult
nsComputedDOMStyle::SetCSSDeclaration(DeclarationBlock
*,
714 MutationClosureData
*) {
715 MOZ_CRASH("called nsComputedDOMStyle::SetCSSDeclaration");
718 Document
* nsComputedDOMStyle::DocToUpdate() {
719 MOZ_CRASH("called nsComputedDOMStyle::DocToUpdate");
722 nsDOMCSSDeclaration::ParsingEnvironment
723 nsComputedDOMStyle::GetParsingEnvironment(
724 nsIPrincipal
* aSubjectPrincipal
) const {
725 MOZ_CRASH("called nsComputedDOMStyle::GetParsingEnvironment");
728 void nsComputedDOMStyle::ClearComputedStyle() {
729 if (mResolvedComputedStyle
) {
730 mResolvedComputedStyle
= false;
731 mElement
->RemoveMutationObserver(this);
733 mComputedStyle
= nullptr;
736 void nsComputedDOMStyle::SetResolvedComputedStyle(
737 RefPtr
<ComputedStyle
>&& aContext
, uint64_t aGeneration
) {
738 if (!mResolvedComputedStyle
) {
739 mResolvedComputedStyle
= true;
740 mElement
->AddMutationObserver(this);
742 mComputedStyle
= aContext
;
743 mComputedStyleGeneration
= aGeneration
;
744 mPresShellId
= mPresShell
->GetPresShellId();
747 void nsComputedDOMStyle::SetFrameComputedStyle(mozilla::ComputedStyle
* aStyle
,
748 uint64_t aGeneration
) {
749 ClearComputedStyle();
750 mComputedStyle
= aStyle
;
751 mComputedStyleGeneration
= aGeneration
;
752 mPresShellId
= mPresShell
->GetPresShellId();
755 static bool MayNeedToFlushLayout(nsCSSPropertyID aPropID
) {
757 case eCSSProperty_width
:
758 case eCSSProperty_height
:
759 case eCSSProperty_block_size
:
760 case eCSSProperty_inline_size
:
761 case eCSSProperty_line_height
:
762 case eCSSProperty_grid_template_rows
:
763 case eCSSProperty_grid_template_columns
:
764 case eCSSProperty_perspective_origin
:
765 case eCSSProperty_transform_origin
:
766 case eCSSProperty_transform
:
767 case eCSSProperty_border_top_width
:
768 case eCSSProperty_border_bottom_width
:
769 case eCSSProperty_border_left_width
:
770 case eCSSProperty_border_right_width
:
771 case eCSSProperty_border_block_start_width
:
772 case eCSSProperty_border_block_end_width
:
773 case eCSSProperty_border_inline_start_width
:
774 case eCSSProperty_border_inline_end_width
:
775 case eCSSProperty_top
:
776 case eCSSProperty_right
:
777 case eCSSProperty_bottom
:
778 case eCSSProperty_left
:
779 case eCSSProperty_inset_block_start
:
780 case eCSSProperty_inset_block_end
:
781 case eCSSProperty_inset_inline_start
:
782 case eCSSProperty_inset_inline_end
:
783 case eCSSProperty_padding_top
:
784 case eCSSProperty_padding_right
:
785 case eCSSProperty_padding_bottom
:
786 case eCSSProperty_padding_left
:
787 case eCSSProperty_padding_block_start
:
788 case eCSSProperty_padding_block_end
:
789 case eCSSProperty_padding_inline_start
:
790 case eCSSProperty_padding_inline_end
:
791 case eCSSProperty_margin_top
:
792 case eCSSProperty_margin_right
:
793 case eCSSProperty_margin_bottom
:
794 case eCSSProperty_margin_left
:
795 case eCSSProperty_margin_block_start
:
796 case eCSSProperty_margin_block_end
:
797 case eCSSProperty_margin_inline_start
:
798 case eCSSProperty_margin_inline_end
:
805 bool nsComputedDOMStyle::NeedsToFlushStyle(nsCSSPropertyID aPropID
) const {
806 bool mayNeedToFlushLayout
= MayNeedToFlushLayout(aPropID
);
808 // We always compute styles from the element's owner document.
809 if (ElementNeedsRestyle(mElement
, mPseudo
, mayNeedToFlushLayout
)) {
813 Document
* doc
= mElement
->OwnerDoc();
814 // If parent document is there, also needs to check if there is some change
815 // that needs to flush this document (e.g. size change for iframe).
816 while (doc
->StyleOrLayoutObservablyDependsOnParentDocumentLayout()) {
817 Document
* parentDocument
= doc
->GetInProcessParentDocument();
818 Element
* element
= parentDocument
->FindContentForSubDocument(doc
);
819 if (ElementNeedsRestyle(element
, nullptr, mayNeedToFlushLayout
)) {
822 doc
= parentDocument
;
828 static nsIFrame
* StyleFrame(nsIFrame
* aOuterFrame
) {
829 MOZ_ASSERT(aOuterFrame
);
830 if (!aOuterFrame
->IsTableWrapperFrame()) {
833 // If the frame is a table wrapper frame then we should get the style from the
834 // inner table frame.
835 nsIFrame
* inner
= aOuterFrame
->PrincipalChildList().FirstChild();
836 NS_ASSERTION(inner
, "table wrapper must have an inner");
837 NS_ASSERTION(!inner
->GetNextSibling(),
838 "table wrapper frames should have just one child, the inner "
843 static bool IsNonReplacedInline(nsIFrame
* aFrame
) {
844 // FIXME: this should be IsInlineInsideStyle() since width/height
845 // doesn't apply to ruby boxes.
846 return aFrame
->StyleDisplay()->IsInlineFlow() &&
847 !aFrame
->IsFrameOfType(nsIFrame::eReplaced
);
850 static Side
SideForPaddingOrMarginOrInsetProperty(nsCSSPropertyID aPropID
) {
852 case eCSSProperty_top
:
853 case eCSSProperty_margin_top
:
854 case eCSSProperty_padding_top
:
856 case eCSSProperty_right
:
857 case eCSSProperty_margin_right
:
858 case eCSSProperty_padding_right
:
860 case eCSSProperty_bottom
:
861 case eCSSProperty_margin_bottom
:
862 case eCSSProperty_padding_bottom
:
864 case eCSSProperty_left
:
865 case eCSSProperty_margin_left
:
866 case eCSSProperty_padding_left
:
869 MOZ_ASSERT_UNREACHABLE("Unexpected property");
874 static bool PaddingNeedsUsedValue(const LengthPercentage
& aValue
,
875 const ComputedStyle
& aStyle
) {
876 return !aValue
.ConvertsToLength() || aStyle
.StyleDisplay()->HasAppearance();
879 bool nsComputedDOMStyle::NeedsToFlushLayout(nsCSSPropertyID aPropID
) const {
880 MOZ_ASSERT(aPropID
!= eCSSProperty_UNKNOWN
);
881 if (aPropID
== eCSSPropertyExtra_variable
) {
884 nsIFrame
* outerFrame
= GetOuterFrame();
888 nsIFrame
* frame
= StyleFrame(outerFrame
);
889 auto* style
= frame
->Style();
890 if (nsCSSProps::PropHasFlags(aPropID
, CSSPropFlags::IsLogical
)) {
891 aPropID
= Servo_ResolveLogicalProperty(aPropID
, style
);
895 case eCSSProperty_width
:
896 case eCSSProperty_height
:
897 return !IsNonReplacedInline(frame
);
898 case eCSSProperty_line_height
:
899 return frame
->StyleText()->mLineHeight
.IsMozBlockHeight();
900 case eCSSProperty_grid_template_rows
:
901 case eCSSProperty_grid_template_columns
:
902 return !!nsGridContainerFrame::GetGridContainerFrame(frame
);
903 case eCSSProperty_perspective_origin
:
904 return style
->StyleDisplay()->mPerspectiveOrigin
.HasPercent();
905 case eCSSProperty_transform_origin
:
906 return style
->StyleDisplay()->mTransformOrigin
.HasPercent();
907 case eCSSProperty_transform
:
908 return style
->StyleDisplay()->mTransform
.HasPercent();
909 case eCSSProperty_border_top_width
:
910 case eCSSProperty_border_bottom_width
:
911 case eCSSProperty_border_left_width
:
912 case eCSSProperty_border_right_width
:
913 // FIXME(emilio): This should return false per spec (bug 1551000), but
914 // themed borders don't make that easy, so for now flush for that case.
916 // TODO(emilio): If we make GetUsedBorder() stop returning 0 for an
917 // unreflowed frame, or something of that sort, then we can stop flushing
918 // layout for themed frames.
919 return style
->StyleDisplay()->HasAppearance();
920 case eCSSProperty_top
:
921 case eCSSProperty_right
:
922 case eCSSProperty_bottom
:
923 case eCSSProperty_left
:
924 // Doing better than this is actually hard.
925 return style
->StyleDisplay()->mPosition
!= StylePositionProperty::Static
;
926 case eCSSProperty_padding_top
:
927 case eCSSProperty_padding_right
:
928 case eCSSProperty_padding_bottom
:
929 case eCSSProperty_padding_left
: {
930 Side side
= SideForPaddingOrMarginOrInsetProperty(aPropID
);
931 // Theming can override used padding, sigh.
933 // TODO(emilio): If we make GetUsedPadding() stop returning 0 for an
934 // unreflowed frame, or something of that sort, then we can stop flushing
935 // layout for themed frames.
936 return PaddingNeedsUsedValue(style
->StylePadding()->mPadding
.Get(side
),
939 case eCSSProperty_margin_top
:
940 case eCSSProperty_margin_right
:
941 case eCSSProperty_margin_bottom
:
942 case eCSSProperty_margin_left
: {
943 // NOTE(emilio): This is dubious, but matches other browsers.
944 // See https://github.com/w3c/csswg-drafts/issues/2328
945 Side side
= SideForPaddingOrMarginOrInsetProperty(aPropID
);
946 return !style
->StyleMargin()->mMargin
.Get(side
).ConvertsToLength();
953 void nsComputedDOMStyle::Flush(Document
& aDocument
, FlushType aFlushType
) {
954 MOZ_ASSERT(mElement
->IsInComposedDoc());
958 nsCOMPtr
<Document
> document
= do_QueryReferent(mDocumentWeak
);
959 MOZ_ASSERT(document
== &aDocument
);
963 aDocument
.FlushPendingNotifications(aFlushType
);
964 if (MOZ_UNLIKELY(&aDocument
!= mElement
->OwnerDoc())) {
965 mElement
->OwnerDoc()->FlushPendingNotifications(aFlushType
);
969 nsIFrame
* nsComputedDOMStyle::GetOuterFrame() const {
971 return mElement
->GetPrimaryFrame();
973 nsAtom
* property
= nullptr;
974 if (mPseudo
== nsCSSPseudoElements::before()) {
975 property
= nsGkAtoms::beforePseudoProperty
;
976 } else if (mPseudo
== nsCSSPseudoElements::after()) {
977 property
= nsGkAtoms::afterPseudoProperty
;
978 } else if (mPseudo
== nsCSSPseudoElements::marker()) {
979 property
= nsGkAtoms::markerPseudoProperty
;
984 auto* pseudo
= static_cast<Element
*>(mElement
->GetProperty(property
));
985 return pseudo
? pseudo
->GetPrimaryFrame() : nullptr;
988 void nsComputedDOMStyle::UpdateCurrentStyleSources(nsCSSPropertyID aPropID
) {
989 nsCOMPtr
<Document
> document
= do_QueryReferent(mDocumentWeak
);
991 ClearComputedStyle();
995 // We don't return styles for disconnected elements anymore, so don't go
996 // through the trouble of flushing or what not.
998 // TODO(emilio): We may want to return earlier for elements outside of the
999 // flat tree too: https://github.com/w3c/csswg-drafts/issues/1964
1000 if (!mElement
->IsInComposedDoc()) {
1001 ClearComputedStyle();
1005 DebugOnly
<bool> didFlush
= false;
1006 if (NeedsToFlushStyle(aPropID
)) {
1008 // We look at the frame in NeedsToFlushLayout, so flush frames, not only
1010 Flush(*document
, FlushType::Frames
);
1013 if (NeedsToFlushLayout(aPropID
)) {
1014 MOZ_ASSERT(MayNeedToFlushLayout(aPropID
));
1016 Flush(*document
, FlushType::Layout
);
1018 mFlushedPendingReflows
= true;
1022 mFlushedPendingReflows
= false;
1026 mPresShell
= document
->GetPresShell();
1027 if (!mPresShell
|| !mPresShell
->GetPresContext()) {
1028 ClearComputedStyle();
1032 // We need to use GetUndisplayedRestyleGeneration instead of
1033 // GetRestyleGeneration, because the caching of mComputedStyle is an
1034 // optimization that is useful only for displayed elements.
1035 // For undisplayed elements we need to take into account any DOM changes that
1036 // might cause a restyle, because Servo will not increase the generation for
1037 // undisplayed elements.
1038 // As for Gecko, GetUndisplayedRestyleGeneration is effectively equal to
1039 // GetRestyleGeneration, since the generation is incremented whenever we
1040 // process restyles.
1041 uint64_t currentGeneration
=
1042 mPresShell
->GetPresContext()->GetUndisplayedRestyleGeneration();
1044 if (mComputedStyle
&& mComputedStyleGeneration
== currentGeneration
&&
1045 mPresShellId
== mPresShell
->GetPresShellId()) {
1046 // Our cached style is still valid.
1050 mComputedStyle
= nullptr;
1052 // XXX the !mElement->IsHTMLElement(nsGkAtoms::area)
1053 // check is needed due to bug 135040 (to avoid using
1054 // mPrimaryFrame). Remove it once that's fixed.
1055 if (mStyleType
== eAll
&& !mElement
->IsHTMLElement(nsGkAtoms::area
)) {
1056 mOuterFrame
= GetOuterFrame();
1057 mInnerFrame
= mOuterFrame
;
1059 mInnerFrame
= StyleFrame(mOuterFrame
);
1060 SetFrameComputedStyle(mInnerFrame
->Style(), currentGeneration
);
1061 NS_ASSERTION(mComputedStyle
, "Frame without style?");
1065 if (!mComputedStyle
|| MustReresolveStyle(mComputedStyle
)) {
1066 PresShell
* presShellForContent
= mElement
->OwnerDoc()->GetPresShell();
1067 // Need to resolve a style.
1068 RefPtr
<ComputedStyle
> resolvedComputedStyle
= DoGetComputedStyleNoFlush(
1070 presShellForContent
? presShellForContent
: mPresShell
, mStyleType
);
1071 if (!resolvedComputedStyle
) {
1072 ClearComputedStyle();
1076 // No need to re-get the generation, even though GetComputedStyle
1077 // will flush, since we flushed style at the top of this function.
1078 // We don't need to check this if we only flushed the parent.
1081 currentGeneration
==
1082 mPresShell
->GetPresContext()->GetUndisplayedRestyleGeneration(),
1083 "why should we have flushed style again?");
1085 SetResolvedComputedStyle(std::move(resolvedComputedStyle
),
1087 NS_ASSERTION(mPseudo
|| !mComputedStyle
->HasPseudoElementData(),
1088 "should not have pseudo-element data");
1091 // mExposeVisitedStyle is set to true only by testing APIs that
1092 // require chrome privilege.
1093 MOZ_ASSERT(!mExposeVisitedStyle
|| nsContentUtils::IsCallerChrome(),
1094 "mExposeVisitedStyle set incorrectly");
1095 if (mExposeVisitedStyle
&& mComputedStyle
->RelevantLinkVisited()) {
1096 if (ComputedStyle
* styleIfVisited
= mComputedStyle
->GetStyleIfVisited()) {
1097 mComputedStyle
= styleIfVisited
;
1102 void nsComputedDOMStyle::ClearCurrentStyleSources() {
1103 // Release the current style if we got it off the frame.
1105 // For a style we resolved, keep it around so that we can re-use it next time
1106 // this object is queried, but not if it-s a re-resolved style because we were
1107 // inside a pseudo-element.
1108 if (!mResolvedComputedStyle
|| mOuterFrame
) {
1109 ClearComputedStyle();
1112 mOuterFrame
= nullptr;
1113 mInnerFrame
= nullptr;
1114 mPresShell
= nullptr;
1117 void nsComputedDOMStyle::RemoveProperty(const nsACString
& aPropertyName
,
1118 nsAString
& aReturn
, ErrorResult
& aRv
) {
1119 // Note: not using nsPrintfCString here in case aPropertyName contains
1121 aRv
.ThrowNoModificationAllowedError(
1122 NS_LITERAL_CSTRING("Can't remove property '") + aPropertyName
+
1123 NS_LITERAL_CSTRING("' from computed style"));
1126 void nsComputedDOMStyle::GetPropertyPriority(const nsACString
& aPropertyName
,
1127 nsAString
& aReturn
) {
1131 void nsComputedDOMStyle::SetProperty(const nsACString
& aPropertyName
,
1132 const nsACString
& aValue
,
1133 const nsAString
& aPriority
,
1134 nsIPrincipal
* aSubjectPrincipal
,
1136 // Note: not using nsPrintfCString here in case aPropertyName contains
1138 aRv
.ThrowNoModificationAllowedError(
1139 NS_LITERAL_CSTRING("Can't set value for property '") + aPropertyName
+
1140 NS_LITERAL_CSTRING("' in computed style"));
1143 void nsComputedDOMStyle::IndexedGetter(uint32_t aIndex
, bool& aFound
,
1144 nsACString
& aPropName
) {
1145 ComputedStyleMap
* map
= GetComputedStyleMap();
1146 uint32_t length
= map
->Length();
1148 if (aIndex
< length
) {
1150 aPropName
.Assign(nsCSSProps::GetStringValue(map
->PropertyAt(aIndex
)));
1154 // Custom properties are exposed with indexed properties just after all
1155 // of the built-in properties.
1156 UpdateCurrentStyleSources(eCSSPropertyExtra_variable
);
1157 if (!mComputedStyle
) {
1162 uint32_t count
= Servo_GetCustomPropertiesCount(mComputedStyle
);
1164 const uint32_t index
= aIndex
- length
;
1165 if (index
< count
) {
1167 aPropName
.AssignLiteral("--");
1168 if (nsAtom
* atom
= Servo_GetCustomPropertyNameAt(mComputedStyle
, index
)) {
1169 aPropName
.Append(nsAtomCString(atom
));
1175 ClearCurrentStyleSources();
1178 // Property getters...
1180 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBottom() {
1181 return GetOffsetWidthFor(eSideBottom
);
1185 void nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue
* aValue
,
1187 nsAutoString string
;
1188 nsStyleUtil::GetSerializedColorValue(aColor
, string
);
1189 aValue
->SetString(string
);
1192 void nsComputedDOMStyle::SetValueFromComplexColor(
1193 nsROCSSPrimitiveValue
* aValue
, const mozilla::StyleColor
& aColor
) {
1194 SetToRGBAColor(aValue
, aColor
.CalcColor(*mComputedStyle
));
1197 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetColumnRuleWidth() {
1198 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1199 val
->SetAppUnits(StyleColumn()->GetComputedColumnRuleWidth());
1200 return val
.forget();
1203 static Position
MaybeResolvePositionForTransform(const LengthPercentage
& aX
,
1204 const LengthPercentage
& aY
,
1205 nsIFrame
* aInnerFrame
) {
1209 nsStyleTransformMatrix::TransformReferenceBox
refBox(aInnerFrame
);
1210 CSSPoint p
= nsStyleTransformMatrix::Convert2DPosition(aX
, aY
, refBox
);
1211 return {LengthPercentage::FromPixels(p
.x
), LengthPercentage::FromPixels(p
.y
)};
1214 /* Convert the stored representation into a list of two values and then hand
1217 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetTransformOrigin() {
1218 /* We need to build up a list of two values. We'll call them
1222 /* Store things as a value list */
1223 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(false);
1225 /* Now, get the values. */
1226 const auto& origin
= StyleDisplay()->mTransformOrigin
;
1228 RefPtr
<nsROCSSPrimitiveValue
> width
= new nsROCSSPrimitiveValue
;
1229 auto position
= MaybeResolvePositionForTransform(
1230 origin
.horizontal
, origin
.vertical
, mInnerFrame
);
1231 SetValueToPosition(position
, valueList
);
1232 if (!origin
.depth
.IsZero()) {
1233 RefPtr
<nsROCSSPrimitiveValue
> depth
= new nsROCSSPrimitiveValue
;
1234 depth
->SetAppUnits(origin
.depth
.ToAppUnits());
1235 valueList
->AppendCSSValue(depth
.forget());
1237 return valueList
.forget();
1240 /* Convert the stored representation into a list of two values and then hand
1243 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetPerspectiveOrigin() {
1244 /* We need to build up a list of two values. We'll call them
1248 /* Store things as a value list */
1249 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(false);
1251 /* Now, get the values. */
1252 const auto& origin
= StyleDisplay()->mPerspectiveOrigin
;
1254 auto position
= MaybeResolvePositionForTransform(
1255 origin
.horizontal
, origin
.vertical
, mInnerFrame
);
1256 SetValueToPosition(position
, valueList
);
1257 return valueList
.forget();
1260 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetTransform() {
1261 const nsStyleDisplay
* display
= StyleDisplay();
1262 return GetTransformValue(display
->mTransform
);
1266 already_AddRefed
<nsROCSSPrimitiveValue
> nsComputedDOMStyle::MatrixToCSSValue(
1267 const mozilla::gfx::Matrix4x4
& matrix
) {
1268 bool is3D
= !matrix
.Is2D();
1270 nsAutoString
resultString(NS_LITERAL_STRING("matrix"));
1272 resultString
.AppendLiteral("3d");
1275 resultString
.Append('(');
1276 resultString
.AppendFloat(matrix
._11
);
1277 resultString
.AppendLiteral(", ");
1278 resultString
.AppendFloat(matrix
._12
);
1279 resultString
.AppendLiteral(", ");
1281 resultString
.AppendFloat(matrix
._13
);
1282 resultString
.AppendLiteral(", ");
1283 resultString
.AppendFloat(matrix
._14
);
1284 resultString
.AppendLiteral(", ");
1286 resultString
.AppendFloat(matrix
._21
);
1287 resultString
.AppendLiteral(", ");
1288 resultString
.AppendFloat(matrix
._22
);
1289 resultString
.AppendLiteral(", ");
1291 resultString
.AppendFloat(matrix
._23
);
1292 resultString
.AppendLiteral(", ");
1293 resultString
.AppendFloat(matrix
._24
);
1294 resultString
.AppendLiteral(", ");
1295 resultString
.AppendFloat(matrix
._31
);
1296 resultString
.AppendLiteral(", ");
1297 resultString
.AppendFloat(matrix
._32
);
1298 resultString
.AppendLiteral(", ");
1299 resultString
.AppendFloat(matrix
._33
);
1300 resultString
.AppendLiteral(", ");
1301 resultString
.AppendFloat(matrix
._34
);
1302 resultString
.AppendLiteral(", ");
1304 resultString
.AppendFloat(matrix
._41
);
1305 resultString
.AppendLiteral(", ");
1306 resultString
.AppendFloat(matrix
._42
);
1308 resultString
.AppendLiteral(", ");
1309 resultString
.AppendFloat(matrix
._43
);
1310 resultString
.AppendLiteral(", ");
1311 resultString
.AppendFloat(matrix
._44
);
1313 resultString
.Append(')');
1315 /* Create a value to hold our result. */
1316 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1318 val
->SetString(resultString
);
1319 return val
.forget();
1322 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetOsxFontSmoothing() {
1323 if (nsContentUtils::ShouldResistFingerprinting(
1324 mPresShell
->GetPresContext()->GetDocShell())) {
1328 nsAutoString result
;
1329 mComputedStyle
->GetComputedPropertyValue(eCSSProperty__moz_osx_font_smoothing
,
1331 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1332 val
->SetString(result
);
1333 return val
.forget();
1336 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetImageLayerPosition(
1337 const nsStyleImageLayers
& aLayers
) {
1338 if (aLayers
.mPositionXCount
!= aLayers
.mPositionYCount
) {
1339 // No value to return. We can't express this combination of
1340 // values as a shorthand.
1344 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(true);
1345 for (uint32_t i
= 0, i_end
= aLayers
.mPositionXCount
; i
< i_end
; ++i
) {
1346 RefPtr
<nsDOMCSSValueList
> itemList
= GetROCSSValueList(false);
1348 SetValueToPosition(aLayers
.mLayers
[i
].mPosition
, itemList
);
1349 valueList
->AppendCSSValue(itemList
.forget());
1352 return valueList
.forget();
1355 void nsComputedDOMStyle::SetValueToPosition(const Position
& aPosition
,
1356 nsDOMCSSValueList
* aValueList
) {
1357 RefPtr
<nsROCSSPrimitiveValue
> valX
= new nsROCSSPrimitiveValue
;
1358 SetValueToLengthPercentage(valX
, aPosition
.horizontal
, false);
1359 aValueList
->AppendCSSValue(valX
.forget());
1361 RefPtr
<nsROCSSPrimitiveValue
> valY
= new nsROCSSPrimitiveValue
;
1362 SetValueToLengthPercentage(valY
, aPosition
.vertical
, false);
1363 aValueList
->AppendCSSValue(valY
.forget());
1366 void nsComputedDOMStyle::SetValueToURLValue(const StyleComputedUrl
* aURL
,
1367 nsROCSSPrimitiveValue
* aValue
) {
1369 aValue
->SetString("none");
1373 // If we have a usable nsIURI in the URLValue, and the url() wasn't
1374 // a fragment-only URL, serialize the nsIURI.
1375 if (!aURL
->IsLocalRef()) {
1376 if (nsIURI
* uri
= aURL
->GetURI()) {
1377 aValue
->SetURI(uri
);
1382 // Otherwise, serialize the specified URL value.
1383 NS_ConvertUTF8toUTF16
source(aURL
->SpecifiedSerialization());
1385 url
.AppendLiteral(u
"url(");
1386 nsStyleUtil::AppendEscapedCSSString(source
, url
, '"');
1388 aValue
->SetString(url
);
1391 enum class Brackets
{ No
, Yes
};
1393 static void AppendGridLineNames(nsAString
& 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 nsStyleUtil::AppendEscapedCSSIdent(
1408 nsDependentAtomString(aLineNames
[i
].AsAtom()), aResult
);
1409 if (++i
== numLines
) {
1412 aResult
.Append(' ');
1414 if (aBrackets
== Brackets::Yes
) {
1415 aResult
.Append(']');
1419 static void AppendGridLineNames(nsDOMCSSValueList
* aValueList
,
1420 Span
<const StyleCustomIdent
> aLineNames
,
1421 bool aSuppressEmptyList
= true) {
1422 if (aLineNames
.IsEmpty() && aSuppressEmptyList
) {
1425 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1426 nsAutoString lineNamesString
;
1427 AppendGridLineNames(lineNamesString
, aLineNames
, Brackets::Yes
);
1428 val
->SetString(lineNamesString
);
1429 aValueList
->AppendCSSValue(val
.forget());
1432 static void AppendGridLineNames(nsDOMCSSValueList
* aValueList
,
1433 Span
<const StyleCustomIdent
> aLineNames1
,
1434 Span
<const StyleCustomIdent
> aLineNames2
) {
1435 if (aLineNames1
.IsEmpty() && aLineNames2
.IsEmpty()) {
1438 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1439 nsAutoString lineNamesString
;
1440 lineNamesString
.Assign('[');
1441 if (!aLineNames1
.IsEmpty()) {
1442 AppendGridLineNames(lineNamesString
, aLineNames1
, Brackets::No
);
1444 if (!aLineNames2
.IsEmpty()) {
1445 if (!aLineNames1
.IsEmpty()) {
1446 lineNamesString
.Append(' ');
1448 AppendGridLineNames(lineNamesString
, aLineNames2
, Brackets::No
);
1450 lineNamesString
.Append(']');
1451 val
->SetString(lineNamesString
);
1452 aValueList
->AppendCSSValue(val
.forget());
1455 void nsComputedDOMStyle::SetValueToTrackBreadth(
1456 nsROCSSPrimitiveValue
* aValue
, const StyleTrackBreadth
& aBreadth
) {
1457 using Tag
= StyleTrackBreadth::Tag
;
1458 switch (aBreadth
.tag
) {
1459 case Tag::MinContent
:
1460 return aValue
->SetString("min-content");
1461 case Tag::MaxContent
:
1462 return aValue
->SetString("max-content");
1464 return aValue
->SetString("auto");
1466 return SetValueToLengthPercentage(aValue
, aBreadth
.AsBreadth(), true);
1468 nsAutoString tmpStr
;
1469 nsStyleUtil::AppendCSSNumber(aBreadth
.AsFr(), tmpStr
);
1470 tmpStr
.AppendLiteral("fr");
1471 return aValue
->SetString(tmpStr
);
1474 MOZ_ASSERT_UNREACHABLE("Unknown breadth value");
1479 already_AddRefed
<nsROCSSPrimitiveValue
> nsComputedDOMStyle::GetGridTrackBreadth(
1480 const StyleTrackBreadth
& aBreadth
) {
1481 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1482 SetValueToTrackBreadth(val
, aBreadth
);
1483 return val
.forget();
1486 already_AddRefed
<nsROCSSPrimitiveValue
> nsComputedDOMStyle::GetGridTrackSize(
1487 const StyleTrackSize
& aTrackSize
) {
1488 if (aTrackSize
.IsFitContent()) {
1489 // A fit-content() function.
1490 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1491 nsAutoString argumentStr
, fitContentStr
;
1492 fitContentStr
.AppendLiteral("fit-content(");
1493 MOZ_ASSERT(aTrackSize
.AsFitContent().IsBreadth(),
1494 "unexpected unit for fit-content() argument value");
1495 SetValueToLengthPercentage(val
, aTrackSize
.AsFitContent().AsBreadth(),
1497 val
->GetCssText(argumentStr
, IgnoreErrors());
1498 fitContentStr
.Append(argumentStr
);
1499 fitContentStr
.Append(char16_t(')'));
1500 val
->SetString(fitContentStr
);
1501 return val
.forget();
1504 if (aTrackSize
.IsBreadth()) {
1505 return GetGridTrackBreadth(aTrackSize
.AsBreadth());
1508 MOZ_ASSERT(aTrackSize
.IsMinmax());
1509 auto& min
= aTrackSize
.AsMinmax()._0
;
1510 auto& max
= aTrackSize
.AsMinmax()._1
;
1512 return GetGridTrackBreadth(min
);
1515 // minmax(auto, <flex>) is equivalent to (and is our internal representation
1516 // of) <flex>, and both compute to <flex>
1517 if (min
.IsAuto() && max
.IsFr()) {
1518 return GetGridTrackBreadth(max
);
1521 nsAutoString argumentStr
, minmaxStr
;
1522 minmaxStr
.AppendLiteral("minmax(");
1525 RefPtr
<nsROCSSPrimitiveValue
> argValue
= GetGridTrackBreadth(min
);
1526 argValue
->GetCssText(argumentStr
, IgnoreErrors());
1527 minmaxStr
.Append(argumentStr
);
1528 argumentStr
.Truncate();
1531 minmaxStr
.AppendLiteral(", ");
1534 RefPtr
<nsROCSSPrimitiveValue
> argValue
= GetGridTrackBreadth(max
);
1535 argValue
->GetCssText(argumentStr
, IgnoreErrors());
1536 minmaxStr
.Append(argumentStr
);
1539 minmaxStr
.Append(char16_t(')'));
1540 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1541 val
->SetString(minmaxStr
);
1542 return val
.forget();
1545 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetGridTemplateColumnsRows(
1546 const StyleGridTemplateComponent
& aTrackList
,
1547 const ComputedGridTrackInfo
& aTrackInfo
) {
1548 if (aTrackInfo
.mIsMasonry
) {
1549 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1550 val
->SetString("masonry");
1551 return val
.forget();
1554 if (aTrackInfo
.mIsSubgrid
) {
1555 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(false);
1556 RefPtr
<nsROCSSPrimitiveValue
> subgridKeyword
= new nsROCSSPrimitiveValue
;
1557 subgridKeyword
->SetString("subgrid");
1558 valueList
->AppendCSSValue(subgridKeyword
.forget());
1559 for (const auto& lineNames
: aTrackInfo
.mResolvedLineNames
) {
1560 AppendGridLineNames(valueList
, lineNames
, /*aSuppressEmptyList*/ false);
1562 uint32_t line
= aTrackInfo
.mResolvedLineNames
.Length();
1563 uint32_t lastLine
= aTrackInfo
.mNumExplicitTracks
+ 1;
1564 const Span
<const StyleCustomIdent
> empty
;
1565 for (; line
< lastLine
; ++line
) {
1566 AppendGridLineNames(valueList
, empty
, /*aSuppressEmptyList*/ false);
1568 return valueList
.forget();
1571 const bool serializeImplicit
=
1572 StaticPrefs::layout_css_serialize_grid_implicit_tracks();
1574 const nsTArray
<nscoord
>& trackSizes
= aTrackInfo
.mSizes
;
1575 const uint32_t numExplicitTracks
= aTrackInfo
.mNumExplicitTracks
;
1576 const uint32_t numLeadingImplicitTracks
=
1577 aTrackInfo
.mNumLeadingImplicitTracks
;
1578 uint32_t numSizes
= trackSizes
.Length();
1579 MOZ_ASSERT(numSizes
>= numLeadingImplicitTracks
+ numExplicitTracks
);
1581 const bool hasTracksToSerialize
=
1582 serializeImplicit
? !!numSizes
: !!numExplicitTracks
;
1583 const bool hasRepeatAuto
= aTrackList
.HasRepeatAuto();
1584 if (!hasTracksToSerialize
&& !hasRepeatAuto
) {
1585 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1586 val
->SetString("none");
1587 return val
.forget();
1590 // We've done layout on the grid and have resolved the sizes of its tracks,
1591 // so we'll return those sizes here. The grid spec says we MAY use
1592 // repeat(<positive-integer>, Npx) here for consecutive tracks with the same
1593 // size, but that doesn't seem worth doing since even for repeat(auto-*)
1594 // the resolved size might differ for the repeated tracks.
1595 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(false);
1597 // Add any leading implicit tracks.
1598 if (serializeImplicit
) {
1599 for (uint32_t i
= 0; i
< numLeadingImplicitTracks
; ++i
) {
1600 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1601 val
->SetAppUnits(trackSizes
[i
]);
1602 valueList
->AppendCSSValue(val
.forget());
1606 if (hasRepeatAuto
) {
1607 const auto* const autoRepeatValue
= aTrackList
.GetRepeatAutoValue();
1608 const auto repeatLineNames
= autoRepeatValue
->line_names
.AsSpan();
1609 MOZ_ASSERT(repeatLineNames
.Length() >= 2);
1610 // Number of tracks inside the repeat, not including any repetitions.
1611 const uint32_t numRepeatTracks
= autoRepeatValue
->track_sizes
.len
;
1612 MOZ_ASSERT(repeatLineNames
.Length() == numRepeatTracks
+ 1);
1613 // The total of all tracks in all repetitions of the repeat.
1614 const uint32_t totalNumRepeatTracks
=
1615 aTrackInfo
.mRemovedRepeatTracks
.Length();
1616 const uint32_t repeatStart
= aTrackInfo
.mRepeatFirstTrack
;
1617 // We need to skip over any track sizes which were resolved to 0 by
1618 // collapsed tracks. Keep track of the iteration separately.
1619 const auto explicitTrackSizeBegin
=
1620 trackSizes
.cbegin() + numLeadingImplicitTracks
;
1621 const auto explicitTrackSizeEnd
=
1622 explicitTrackSizeBegin
+ numExplicitTracks
;
1623 auto trackSizeIter
= explicitTrackSizeBegin
;
1624 // Write any leading explicit tracks before the repeat.
1625 for (uint32_t i
= 0; i
< repeatStart
; i
++) {
1626 AppendGridLineNames(valueList
, aTrackInfo
.mResolvedLineNames
[i
]);
1627 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1628 val
->SetAppUnits(*trackSizeIter
++);
1629 valueList
->AppendCSSValue(val
.forget());
1631 auto lineNameIter
= aTrackInfo
.mResolvedLineNames
.cbegin() + repeatStart
;
1632 // Write the track names at the start of the repeat, including the names
1633 // at the end of the last non-repeat track. Unlike all later repeat line
1634 // name lists, this one needs the resolved line name which includes both
1635 // the last non-repeat line names and the leading repeat line names.
1636 AppendGridLineNames(valueList
, *lineNameIter
++);
1638 // Write out the first repeat value, checking for size zero (removed
1640 const nscoord firstRepeatTrackSize
=
1641 (!aTrackInfo
.mRemovedRepeatTracks
[0]) ? *trackSizeIter
++ : 0;
1642 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1643 val
->SetAppUnits(firstRepeatTrackSize
);
1644 valueList
->AppendCSSValue(val
.forget());
1646 // Write the line names and track sizes inside the repeat, checking for
1647 // removed tracks (size 0).
1648 for (uint32_t i
= 1; i
< totalNumRepeatTracks
; i
++) {
1649 const uint32_t repeatIndex
= i
% numRepeatTracks
;
1650 // If we are rolling over from one repetition to the next, include track
1651 // names from both the end of the previous repeat and the start of the
1653 if (repeatIndex
== 0) {
1654 AppendGridLineNames(valueList
,
1655 repeatLineNames
[numRepeatTracks
].AsSpan(),
1656 repeatLineNames
[0].AsSpan());
1658 AppendGridLineNames(valueList
, repeatLineNames
[repeatIndex
].AsSpan());
1660 MOZ_ASSERT(aTrackInfo
.mRemovedRepeatTracks
[i
] ||
1661 trackSizeIter
!= explicitTrackSizeEnd
);
1662 const nscoord repeatTrackSize
=
1663 (!aTrackInfo
.mRemovedRepeatTracks
[i
]) ? *trackSizeIter
++ : 0;
1664 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1665 val
->SetAppUnits(repeatTrackSize
);
1666 valueList
->AppendCSSValue(val
.forget());
1668 // The resolved line names include a single repetition of the auto-repeat
1669 // line names. Skip over those.
1670 lineNameIter
+= numRepeatTracks
- 1;
1671 // Write out any more tracks after the repeat.
1672 while (trackSizeIter
!= explicitTrackSizeEnd
) {
1673 AppendGridLineNames(valueList
, *lineNameIter
++);
1674 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1675 val
->SetAppUnits(*trackSizeIter
++);
1676 valueList
->AppendCSSValue(val
.forget());
1678 // Write the final trailing line name.
1679 AppendGridLineNames(valueList
, *lineNameIter
++);
1680 } else if (numExplicitTracks
> 0) {
1681 // If there are explicit tracks but no repeat tracks, just serialize those.
1682 for (uint32_t i
= 0;; i
++) {
1683 AppendGridLineNames(valueList
, aTrackInfo
.mResolvedLineNames
[i
]);
1684 if (i
== numExplicitTracks
) {
1687 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1688 val
->SetAppUnits(trackSizes
[i
+ numLeadingImplicitTracks
]);
1689 valueList
->AppendCSSValue(val
.forget());
1692 // Add any trailing implicit tracks.
1693 if (serializeImplicit
) {
1694 for (uint32_t i
= numLeadingImplicitTracks
+ numExplicitTracks
;
1695 i
< numSizes
; ++i
) {
1696 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1697 val
->SetAppUnits(trackSizes
[i
]);
1698 valueList
->AppendCSSValue(val
.forget());
1702 return valueList
.forget();
1705 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetGridTemplateColumns() {
1706 nsGridContainerFrame
* gridFrame
=
1707 nsGridContainerFrame::GetGridFrameWithComputedInfo(mInnerFrame
);
1709 // The element doesn't have a box - return the computed value.
1710 // https://drafts.csswg.org/css-grid/#resolved-track-list
1711 nsAutoString string
;
1712 mComputedStyle
->GetComputedPropertyValue(eCSSProperty_grid_template_columns
,
1714 RefPtr
<nsROCSSPrimitiveValue
> value
= new nsROCSSPrimitiveValue
;
1715 value
->SetString(string
);
1716 return value
.forget();
1719 // GetGridFrameWithComputedInfo() above ensures that this returns non-null:
1720 const ComputedGridTrackInfo
* info
= gridFrame
->GetComputedTemplateColumns();
1721 return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns
,
1725 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetGridTemplateRows() {
1726 nsGridContainerFrame
* gridFrame
=
1727 nsGridContainerFrame::GetGridFrameWithComputedInfo(mInnerFrame
);
1729 // The element doesn't have a box - return the computed value.
1730 // https://drafts.csswg.org/css-grid/#resolved-track-list
1731 nsAutoString string
;
1732 mComputedStyle
->GetComputedPropertyValue(eCSSProperty_grid_template_rows
,
1734 RefPtr
<nsROCSSPrimitiveValue
> value
= new nsROCSSPrimitiveValue
;
1735 value
->SetString(string
);
1736 return value
.forget();
1739 // GetGridFrameWithComputedInfo() above ensures that this returns non-null:
1740 const ComputedGridTrackInfo
* info
= gridFrame
->GetComputedTemplateRows();
1741 return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows
, *info
);
1744 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetPaddingTop() {
1745 return GetPaddingWidthFor(eSideTop
);
1748 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetPaddingBottom() {
1749 return GetPaddingWidthFor(eSideBottom
);
1752 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetPaddingLeft() {
1753 return GetPaddingWidthFor(eSideLeft
);
1756 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetPaddingRight() {
1757 return GetPaddingWidthFor(eSideRight
);
1760 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBorderSpacing() {
1761 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(false);
1763 RefPtr
<nsROCSSPrimitiveValue
> xSpacing
= new nsROCSSPrimitiveValue
;
1764 RefPtr
<nsROCSSPrimitiveValue
> ySpacing
= new nsROCSSPrimitiveValue
;
1766 const nsStyleTableBorder
* border
= StyleTableBorder();
1767 xSpacing
->SetAppUnits(border
->mBorderSpacingCol
);
1768 ySpacing
->SetAppUnits(border
->mBorderSpacingRow
);
1770 valueList
->AppendCSSValue(xSpacing
.forget());
1771 valueList
->AppendCSSValue(ySpacing
.forget());
1773 return valueList
.forget();
1776 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBorderTopWidth() {
1777 return GetBorderWidthFor(eSideTop
);
1780 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBorderBottomWidth() {
1781 return GetBorderWidthFor(eSideBottom
);
1784 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBorderLeftWidth() {
1785 return GetBorderWidthFor(eSideLeft
);
1788 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetBorderRightWidth() {
1789 return GetBorderWidthFor(eSideRight
);
1792 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMarginTopWidth() {
1793 return GetMarginWidthFor(eSideTop
);
1796 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMarginBottomWidth() {
1797 return GetMarginWidthFor(eSideBottom
);
1800 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMarginLeftWidth() {
1801 return GetMarginWidthFor(eSideLeft
);
1804 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMarginRightWidth() {
1805 return GetMarginWidthFor(eSideRight
);
1808 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetLineHeight() {
1809 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1813 if (GetLineHeightCoord(lineHeight
)) {
1814 val
->SetAppUnits(lineHeight
);
1815 return val
.forget();
1819 auto& lh
= StyleText()->mLineHeight
;
1820 if (lh
.IsLength()) {
1821 val
->SetAppUnits(lh
.AsLength().ToAppUnits());
1822 } else if (lh
.IsNumber()) {
1823 val
->SetNumber(lh
.AsNumber());
1824 } else if (lh
.IsMozBlockHeight()) {
1825 val
->SetString("-moz-block-height");
1827 MOZ_ASSERT(lh
.IsNormal());
1828 val
->SetString("normal");
1830 return val
.forget();
1833 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetTextDecoration() {
1834 auto getPropertyValue
= [&](nsCSSPropertyID aID
) {
1835 RefPtr
<nsROCSSPrimitiveValue
> value
= new nsROCSSPrimitiveValue
;
1836 nsAutoString string
;
1837 mComputedStyle
->GetComputedPropertyValue(aID
, string
);
1838 value
->SetString(string
);
1839 return value
.forget();
1842 const nsStyleTextReset
* textReset
= StyleTextReset();
1843 RefPtr
<nsDOMCSSValueList
> valueList
= GetROCSSValueList(false);
1845 if (textReset
->mTextDecorationLine
!= StyleTextDecorationLine::NONE
) {
1846 valueList
->AppendCSSValue(
1847 getPropertyValue(eCSSProperty_text_decoration_line
));
1850 if (textReset
->mTextDecorationStyle
!= NS_STYLE_TEXT_DECORATION_STYLE_SOLID
) {
1851 valueList
->AppendCSSValue(
1852 getPropertyValue(eCSSProperty_text_decoration_style
));
1855 // The resolved color shouldn't be currentColor, so we always serialize it.
1856 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1857 SetValueFromComplexColor(val
, StyleTextReset()->mTextDecorationColor
);
1858 valueList
->AppendCSSValue(val
.forget());
1860 if (!textReset
->mTextDecorationThickness
.IsAuto()) {
1861 valueList
->AppendCSSValue(
1862 getPropertyValue(eCSSProperty_text_decoration_thickness
));
1865 return valueList
.forget();
1868 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetHeight() {
1869 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1871 if (mInnerFrame
&& !IsNonReplacedInline(mInnerFrame
)) {
1872 AssertFlushedPendingReflows();
1873 nsMargin adjustedValues
= GetAdjustedValuesForBoxSizing();
1874 val
->SetAppUnits(mInnerFrame
->GetContentRect().height
+
1875 adjustedValues
.TopBottom());
1877 SetValueToSize(val
, StylePosition()->mHeight
);
1880 return val
.forget();
1883 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetWidth() {
1884 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1886 if (mInnerFrame
&& !IsNonReplacedInline(mInnerFrame
)) {
1887 AssertFlushedPendingReflows();
1888 nsMargin adjustedValues
= GetAdjustedValuesForBoxSizing();
1889 val
->SetAppUnits(mInnerFrame
->GetContentRect().width
+
1890 adjustedValues
.LeftRight());
1892 SetValueToSize(val
, StylePosition()->mWidth
);
1895 return val
.forget();
1898 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMaxHeight() {
1899 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1900 SetValueToMaxSize(val
, StylePosition()->mMaxHeight
);
1901 return val
.forget();
1904 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMaxWidth() {
1905 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1906 SetValueToMaxSize(val
, StylePosition()->mMaxWidth
);
1907 return val
.forget();
1911 * This function indicates whether we should return "auto" as the
1912 * getComputedStyle() result for the (default) "min-width: auto" and
1913 * "min-height: auto" CSS values.
1915 * As of this writing, the CSS Sizing draft spec says this "auto" value
1916 * *always* computes to itself. However, for now, we only make it compute to
1917 * itself for grid and flex items (the containers where "auto" has special
1918 * significance), because those are the only areas where the CSSWG has actually
1919 * resolved on this "computes-to-itself" behavior. For elements in other sorts
1920 * of containers, this function returns false, which will make us resolve
1923 bool nsComputedDOMStyle::ShouldHonorMinSizeAutoInAxis(PhysicalAxis aAxis
) {
1924 return mOuterFrame
&& mOuterFrame
->IsFlexOrGridItem();
1927 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMinHeight() {
1928 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1929 StyleSize minHeight
= StylePosition()->mMinHeight
;
1931 if (minHeight
.IsAuto() && !ShouldHonorMinSizeAutoInAxis(eAxisVertical
)) {
1932 minHeight
= StyleSize::LengthPercentage(LengthPercentage::Zero());
1935 SetValueToSize(val
, minHeight
);
1936 return val
.forget();
1939 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMinWidth() {
1940 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
1942 StyleSize minWidth
= StylePosition()->mMinWidth
;
1944 if (minWidth
.IsAuto() && !ShouldHonorMinSizeAutoInAxis(eAxisHorizontal
)) {
1945 minWidth
= StyleSize::LengthPercentage(LengthPercentage::Zero());
1948 SetValueToSize(val
, minWidth
);
1949 return val
.forget();
1952 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetLeft() {
1953 return GetOffsetWidthFor(eSideLeft
);
1956 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetRight() {
1957 return GetOffsetWidthFor(eSideRight
);
1960 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetTop() {
1961 return GetOffsetWidthFor(eSideTop
);
1964 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetOffsetWidthFor(
1965 mozilla::Side aSide
) {
1966 const nsStyleDisplay
* display
= StyleDisplay();
1968 mozilla::StylePositionProperty position
= display
->mPosition
;
1970 // GetNonStaticPositionOffset or GetAbsoluteOffset don't handle elements
1971 // without frames in any sensible way. GetStaticOffset, however, is perfect
1973 position
= StylePositionProperty::Static
;
1977 case StylePositionProperty::Static
:
1978 return GetStaticOffset(aSide
);
1979 case StylePositionProperty::Sticky
:
1980 return GetNonStaticPositionOffset(
1981 aSide
, false, &nsComputedDOMStyle::GetScrollFrameContentWidth
,
1982 &nsComputedDOMStyle::GetScrollFrameContentHeight
);
1983 case StylePositionProperty::Absolute
:
1984 case StylePositionProperty::Fixed
:
1985 return GetAbsoluteOffset(aSide
);
1986 case StylePositionProperty::Relative
:
1987 return GetNonStaticPositionOffset(
1988 aSide
, true, &nsComputedDOMStyle::GetCBContentWidth
,
1989 &nsComputedDOMStyle::GetCBContentHeight
);
1991 MOZ_ASSERT_UNREACHABLE("Invalid position");
1996 static_assert(eSideTop
== 0 && eSideRight
== 1 && eSideBottom
== 2 &&
1998 "box side constants not as expected for NS_OPPOSITE_SIDE");
1999 #define NS_OPPOSITE_SIDE(s_) mozilla::Side(((s_) + 2) & 3)
2001 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetNonStaticPositionOffset(
2002 mozilla::Side aSide
, bool aResolveAuto
, PercentageBaseGetter aWidthGetter
,
2003 PercentageBaseGetter aHeightGetter
) {
2004 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2006 const nsStylePosition
* positionData
= StylePosition();
2008 LengthPercentageOrAuto coord
= positionData
->mOffset
.Get(aSide
);
2010 if (coord
.IsAuto()) {
2011 if (!aResolveAuto
) {
2012 val
->SetString("auto");
2013 return val
.forget();
2015 coord
= positionData
->mOffset
.Get(NS_OPPOSITE_SIDE(aSide
));
2019 PercentageBaseGetter baseGetter
= (aSide
== eSideLeft
|| aSide
== eSideRight
)
2023 val
->SetAppUnits(sign
* StyleCoordToNSCoord(coord
, baseGetter
, 0, false));
2024 return val
.forget();
2027 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetAbsoluteOffset(
2028 mozilla::Side aSide
) {
2029 const auto& offset
= StylePosition()->mOffset
;
2030 const auto& coord
= offset
.Get(aSide
);
2031 const auto& oppositeCoord
= offset
.Get(NS_OPPOSITE_SIDE(aSide
));
2033 if (coord
.IsAuto() || oppositeCoord
.IsAuto()) {
2034 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2035 val
->SetAppUnits(GetUsedAbsoluteOffset(aSide
));
2036 return val
.forget();
2039 return GetNonStaticPositionOffset(
2040 aSide
, false, &nsComputedDOMStyle::GetCBPaddingRectWidth
,
2041 &nsComputedDOMStyle::GetCBPaddingRectHeight
);
2044 nscoord
nsComputedDOMStyle::GetUsedAbsoluteOffset(mozilla::Side aSide
) {
2045 MOZ_ASSERT(mOuterFrame
, "need a frame, so we can call GetContainingBlock()");
2047 nsIFrame
* container
= mOuterFrame
->GetContainingBlock();
2048 nsMargin margin
= mOuterFrame
->GetUsedMargin();
2049 nsMargin border
= container
->GetUsedBorder();
2050 nsMargin
scrollbarSizes(0, 0, 0, 0);
2051 nsRect rect
= mOuterFrame
->GetRect();
2052 nsRect containerRect
= container
->GetRect();
2054 if (container
->IsViewportFrame()) {
2055 // For absolutely positioned frames scrollbars are taken into
2056 // account by virtue of getting a containing block that does
2057 // _not_ include the scrollbars. For fixed positioned frames,
2058 // the containing block is the viewport, which _does_ include
2059 // scrollbars. We have to do some extra work.
2060 // the first child in the default frame list is what we want
2061 nsIFrame
* scrollingChild
= container
->PrincipalChildList().FirstChild();
2062 nsIScrollableFrame
* scrollFrame
= do_QueryFrame(scrollingChild
);
2064 scrollbarSizes
= scrollFrame
->GetActualScrollbarSizes();
2067 // The viewport size might have been expanded by the visual viewport or
2068 // the minimum-scale size.
2069 const ViewportFrame
* viewportFrame
= do_QueryFrame(container
);
2070 MOZ_ASSERT(viewportFrame
);
2071 containerRect
.SizeTo(
2072 viewportFrame
->AdjustViewportSizeForFixedPosition(containerRect
));
2073 } else if (container
->IsGridContainerFrame() &&
2074 (mOuterFrame
->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
))) {
2075 containerRect
= nsGridContainerFrame::GridItemCB(mOuterFrame
);
2076 rect
.MoveBy(-containerRect
.x
, -containerRect
.y
);
2082 offset
= rect
.y
- margin
.top
- border
.top
- scrollbarSizes
.top
;
2086 offset
= containerRect
.width
- rect
.width
- rect
.x
- margin
.right
-
2087 border
.right
- scrollbarSizes
.right
;
2091 offset
= containerRect
.height
- rect
.height
- rect
.y
- margin
.bottom
-
2092 border
.bottom
- scrollbarSizes
.bottom
;
2096 offset
= rect
.x
- margin
.left
- border
.left
- scrollbarSizes
.left
;
2100 NS_ERROR("Invalid side");
2107 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetStaticOffset(
2108 mozilla::Side aSide
) {
2109 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2110 SetValueToLengthPercentageOrAuto(val
, StylePosition()->mOffset
.Get(aSide
),
2112 return val
.forget();
2115 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetPaddingWidthFor(
2116 mozilla::Side aSide
) {
2117 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2119 auto& padding
= StylePadding()->mPadding
.Get(aSide
);
2120 if (!mInnerFrame
|| !PaddingNeedsUsedValue(padding
, *mComputedStyle
)) {
2121 SetValueToLengthPercentage(val
, padding
, true);
2123 AssertFlushedPendingReflows();
2124 val
->SetAppUnits(mInnerFrame
->GetUsedPadding().Side(aSide
));
2127 return val
.forget();
2130 bool nsComputedDOMStyle::GetLineHeightCoord(nscoord
& aCoord
) {
2131 nscoord blockHeight
= NS_UNCONSTRAINEDSIZE
;
2132 const auto& lh
= StyleText()->mLineHeight
;
2134 if (lh
.IsNormal() &&
2135 StaticPrefs::layout_css_line_height_normal_as_resolved_value_enabled()) {
2139 if (lh
.IsMozBlockHeight()) {
2140 AssertFlushedPendingReflows();
2146 if (nsLayoutUtils::IsNonWrapperBlock(mInnerFrame
)) {
2147 blockHeight
= mInnerFrame
->GetContentRect().height
;
2149 GetCBContentHeight(blockHeight
);
2153 nsPresContext
* presContext
= mPresShell
->GetPresContext();
2155 // lie about font size inflation since we lie about font size (since
2156 // the inflation only applies to text)
2157 aCoord
= ReflowInput::CalcLineHeight(mElement
, mComputedStyle
, presContext
,
2160 // CalcLineHeight uses font->mFont.size, but we want to use
2161 // font->mSize as the font size. Adjust for that. Also adjust for
2162 // the text zoom, if any.
2163 const nsStyleFont
* font
= StyleFont();
2164 float fCoord
= float(aCoord
);
2165 if (font
->mAllowZoomAndMinSize
) {
2166 fCoord
/= presContext
->EffectiveTextZoom();
2168 if (font
->mFont
.size
!= font
->mSize
) {
2169 fCoord
= fCoord
* (float(font
->mSize
) / float(font
->mFont
.size
));
2171 aCoord
= NSToCoordRound(fCoord
);
2176 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetBorderWidthFor(
2177 mozilla::Side aSide
) {
2178 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2181 if (mInnerFrame
&& mComputedStyle
->StyleDisplay()->HasAppearance()) {
2182 AssertFlushedPendingReflows();
2183 width
= mInnerFrame
->GetUsedBorder().Side(aSide
);
2185 width
= StyleBorder()->GetComputedBorderWidth(aSide
);
2187 val
->SetAppUnits(width
);
2189 return val
.forget();
2192 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetMarginWidthFor(
2193 mozilla::Side aSide
) {
2194 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2196 auto& margin
= StyleMargin()->mMargin
.Get(aSide
);
2197 if (!mInnerFrame
|| margin
.ConvertsToLength()) {
2198 SetValueToLengthPercentageOrAuto(val
, margin
, false);
2200 AssertFlushedPendingReflows();
2202 // For tables, GetUsedMargin always returns an empty margin, so we
2203 // should read the margin from the table wrapper frame instead.
2204 val
->SetAppUnits(mOuterFrame
->GetUsedMargin().Side(aSide
));
2205 NS_ASSERTION(mOuterFrame
== mInnerFrame
||
2206 mInnerFrame
->GetUsedMargin() == nsMargin(0, 0, 0, 0),
2207 "Inner tables must have zero margins");
2210 return val
.forget();
2213 void nsComputedDOMStyle::SetValueToExtremumLength(nsROCSSPrimitiveValue
* aValue
,
2214 StyleExtremumLength aSize
) {
2216 case StyleExtremumLength::MaxContent
:
2217 return aValue
->SetString("max-content");
2218 case StyleExtremumLength::MinContent
:
2219 return aValue
->SetString("min-content");
2220 case StyleExtremumLength::MozAvailable
:
2221 return aValue
->SetString("-moz-available");
2222 case StyleExtremumLength::MozFitContent
:
2223 return aValue
->SetString("-moz-fit-content");
2225 MOZ_ASSERT_UNREACHABLE("Unknown extremum length?");
2228 void nsComputedDOMStyle::SetValueToSize(nsROCSSPrimitiveValue
* aValue
,
2229 const StyleSize
& aSize
) {
2230 if (aSize
.IsAuto()) {
2231 return aValue
->SetString("auto");
2233 if (aSize
.IsExtremumLength()) {
2234 return SetValueToExtremumLength(aValue
, aSize
.AsExtremumLength());
2236 MOZ_ASSERT(aSize
.IsLengthPercentage());
2237 SetValueToLengthPercentage(aValue
, aSize
.AsLengthPercentage(), true);
2240 void nsComputedDOMStyle::SetValueToMaxSize(nsROCSSPrimitiveValue
* aValue
,
2241 const StyleMaxSize
& aSize
) {
2242 if (aSize
.IsNone()) {
2243 return aValue
->SetString("none");
2245 if (aSize
.IsExtremumLength()) {
2246 return SetValueToExtremumLength(aValue
, aSize
.AsExtremumLength());
2248 MOZ_ASSERT(aSize
.IsLengthPercentage());
2249 SetValueToLengthPercentage(aValue
, aSize
.AsLengthPercentage(), true);
2252 void nsComputedDOMStyle::SetValueToLengthPercentageOrAuto(
2253 nsROCSSPrimitiveValue
* aValue
, const LengthPercentageOrAuto
& aSize
,
2254 bool aClampNegativeCalc
) {
2255 if (aSize
.IsAuto()) {
2256 return aValue
->SetString("auto");
2258 SetValueToLengthPercentage(aValue
, aSize
.AsLengthPercentage(),
2259 aClampNegativeCalc
);
2262 void nsComputedDOMStyle::SetValueToLengthPercentage(
2263 nsROCSSPrimitiveValue
* aValue
, const mozilla::LengthPercentage
& aLength
,
2264 bool aClampNegativeCalc
) {
2265 if (aLength
.ConvertsToLength()) {
2266 nscoord result
= aLength
.ToLength();
2267 if (aClampNegativeCalc
) {
2268 result
= std::max(result
, 0);
2270 return aValue
->SetAppUnits(result
);
2272 if (aLength
.ConvertsToPercentage()) {
2273 float result
= aLength
.ToPercentage();
2274 if (aClampNegativeCalc
) {
2275 result
= std::max(result
, 0.0f
);
2277 return aValue
->SetPercent(result
);
2280 nsAutoString result
;
2281 Servo_LengthPercentage_ToCss(&aLength
, &result
);
2282 aValue
->SetString(result
);
2285 nscoord
nsComputedDOMStyle::StyleCoordToNSCoord(
2286 const LengthPercentage
& aCoord
, PercentageBaseGetter aPercentageBaseGetter
,
2287 nscoord aDefaultValue
, bool aClampNegativeCalc
) {
2288 MOZ_ASSERT(aPercentageBaseGetter
, "Must have a percentage base getter");
2289 if (aCoord
.ConvertsToLength()) {
2290 return aCoord
.ToLength();
2292 nscoord percentageBase
;
2293 if ((this->*aPercentageBaseGetter
)(percentageBase
)) {
2294 nscoord result
= aCoord
.Resolve(percentageBase
);
2295 if (aClampNegativeCalc
&& result
< 0) {
2296 // It's expected that we can get a negative value here with calc().
2297 // We can also get a negative value with a percentage value if
2298 // percentageBase is negative; this isn't expected, but can happen
2299 // when large length values overflow.
2300 NS_WARNING_ASSERTION(percentageBase
>= 0,
2301 "percentage base value overflowed to become "
2302 "negative for a property "
2303 "that disallows negative values");
2309 return aDefaultValue
;
2312 bool nsComputedDOMStyle::GetCBContentWidth(nscoord
& aWidth
) {
2317 AssertFlushedPendingReflows();
2319 aWidth
= mOuterFrame
->GetContainingBlock()->GetContentRect().width
;
2323 bool nsComputedDOMStyle::GetCBContentHeight(nscoord
& aHeight
) {
2328 AssertFlushedPendingReflows();
2330 aHeight
= mOuterFrame
->GetContainingBlock()->GetContentRect().height
;
2334 bool nsComputedDOMStyle::GetCBPaddingRectWidth(nscoord
& aWidth
) {
2339 AssertFlushedPendingReflows();
2341 aWidth
= mOuterFrame
->GetContainingBlock()->GetPaddingRect().width
;
2345 bool nsComputedDOMStyle::GetCBPaddingRectHeight(nscoord
& aHeight
) {
2350 AssertFlushedPendingReflows();
2352 aHeight
= mOuterFrame
->GetContainingBlock()->GetPaddingRect().height
;
2356 bool nsComputedDOMStyle::GetScrollFrameContentWidth(nscoord
& aWidth
) {
2361 AssertFlushedPendingReflows();
2363 nsIScrollableFrame
* scrollableFrame
=
2364 nsLayoutUtils::GetNearestScrollableFrame(
2365 mOuterFrame
->GetParent(),
2366 nsLayoutUtils::SCROLLABLE_SAME_DOC
|
2367 nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN
);
2369 if (!scrollableFrame
) {
2373 scrollableFrame
->GetScrolledFrame()->GetContentRectRelativeToSelf().width
;
2377 bool nsComputedDOMStyle::GetScrollFrameContentHeight(nscoord
& aHeight
) {
2382 AssertFlushedPendingReflows();
2384 nsIScrollableFrame
* scrollableFrame
=
2385 nsLayoutUtils::GetNearestScrollableFrame(
2386 mOuterFrame
->GetParent(),
2387 nsLayoutUtils::SCROLLABLE_SAME_DOC
|
2388 nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN
);
2390 if (!scrollableFrame
) {
2393 aHeight
= scrollableFrame
->GetScrolledFrame()
2394 ->GetContentRectRelativeToSelf()
2399 bool nsComputedDOMStyle::GetFrameBorderRectWidth(nscoord
& aWidth
) {
2404 AssertFlushedPendingReflows();
2406 aWidth
= mInnerFrame
->GetSize().width
;
2410 bool nsComputedDOMStyle::GetFrameBorderRectHeight(nscoord
& aHeight
) {
2415 AssertFlushedPendingReflows();
2417 aHeight
= mInnerFrame
->GetSize().height
;
2421 /* If the property is "none", hand back "none" wrapped in a value.
2422 * Otherwise, compute the aggregate transform matrix and hands it back in a
2425 already_AddRefed
<CSSValue
> nsComputedDOMStyle::GetTransformValue(
2426 const StyleTransform
& aTransform
) {
2427 /* If there are no transforms, then we should construct a single-element
2428 * entry and hand it back.
2430 if (aTransform
.IsNone()) {
2431 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2432 val
->SetString("none");
2433 return val
.forget();
2436 /* Otherwise, we need to compute the current value of the transform matrix,
2437 * store it in a string, and hand it back to the caller.
2440 /* Use the inner frame for the reference box. If we don't have an inner
2441 * frame we use empty dimensions to allow us to continue (and percentage
2442 * values in the transform will simply give broken results).
2443 * TODO: There is no good way for us to represent the case where there's no
2444 * frame, which is problematic. The reason is that when we have percentage
2445 * transforms, there are a total of four stored matrix entries that influence
2446 * the transform based on the size of the element. However, this poses a
2447 * problem, because only two of these values can be explicitly referenced
2448 * using the named transforms. Until a real solution is found, we'll just
2449 * use this approach.
2451 nsStyleTransformMatrix::TransformReferenceBox
refBox(mInnerFrame
, nsRect());
2452 gfx::Matrix4x4 matrix
= nsStyleTransformMatrix::ReadTransforms(
2453 aTransform
, refBox
, float(mozilla::AppUnitsPerCSSPixel()));
2455 return MatrixToCSSValue(matrix
);
2458 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DoGetMask() {
2459 const nsStyleSVGReset
* svg
= StyleSVGReset();
2460 const nsStyleImageLayers::Layer
& firstLayer
= svg
->mMask
.mLayers
[0];
2462 // Mask is now a shorthand, but it used to be a longhand, so that we
2463 // need to support computed style for the cases where it used to be
2465 if (svg
->mMask
.mImageCount
> 1 ||
2466 firstLayer
.mClip
!= StyleGeometryBox::BorderBox
||
2467 firstLayer
.mOrigin
!= StyleGeometryBox::BorderBox
||
2468 firstLayer
.mComposite
!= StyleMaskComposite::Add
||
2469 firstLayer
.mMaskMode
!= StyleMaskMode::MatchSource
||
2470 firstLayer
.mPosition
!= Position::FromPercentage(0.0f
) ||
2471 !firstLayer
.mRepeat
.IsInitialValue() ||
2472 !firstLayer
.mSize
.IsInitialValue() ||
2473 !(firstLayer
.mImage
.IsNone() || firstLayer
.mImage
.IsUrl())) {
2477 RefPtr
<nsROCSSPrimitiveValue
> val
= new nsROCSSPrimitiveValue
;
2479 SetValueToURLValue(firstLayer
.mImage
.GetImageRequestURLValue(), val
);
2481 return val
.forget();
2484 already_AddRefed
<CSSValue
> nsComputedDOMStyle::DummyGetter() {
2485 MOZ_CRASH("DummyGetter is not supposed to be invoked");
2488 static void MarkComputedStyleMapDirty(const char* aPref
, void* aMap
) {
2489 static_cast<ComputedStyleMap
*>(aMap
)->MarkDirty();
2492 void nsComputedDOMStyle::ParentChainChanged(nsIContent
* aContent
) {
2493 NS_ASSERTION(mElement
== aContent
, "didn't we register mElement?");
2494 NS_ASSERTION(mResolvedComputedStyle
,
2495 "should have only registered an observer when "
2496 "mResolvedComputedStyle is true");
2498 ClearComputedStyle();
2502 ComputedStyleMap
* nsComputedDOMStyle::GetComputedStyleMap() {
2503 static ComputedStyleMap map
{};
2507 static StaticAutoPtr
<nsTArray
<const char*>> gCallbackPrefs
;
2510 void nsComputedDOMStyle::RegisterPrefChangeCallbacks() {
2511 // Note that this will register callbacks for all properties with prefs, not
2512 // just those that are implemented on computed style objects, as it's not
2513 // easy to grab specific property data from ServoCSSPropList.h based on the
2514 // entries iterated in nsComputedDOMStylePropertyList.h.
2516 AutoTArray
<const char*, 64> prefs
;
2517 for (const auto* p
= nsCSSProps::kPropertyPrefTable
;
2518 p
->mPropID
!= eCSSProperty_UNKNOWN
; p
++) {
2519 // Many properties are controlled by the same preference, so de-duplicate
2520 // them before adding observers.
2522 // Note: This is done by pointer comparison, which works because the mPref
2523 // members are string literals from the same same translation unit, and are
2524 // therefore de-duplicated by the compiler. On the off chance that we wind
2525 // up with some duplicates with different pointers, though, it's not a bit
2527 if (!prefs
.ContainsSorted(p
->mPref
)) {
2528 prefs
.InsertElementSorted(p
->mPref
);
2531 prefs
.AppendElement(nullptr);
2533 MOZ_ASSERT(!gCallbackPrefs
);
2534 gCallbackPrefs
= new nsTArray
<const char*>(std::move(prefs
));
2536 Preferences::RegisterCallbacks(MarkComputedStyleMapDirty
,
2537 gCallbackPrefs
->Elements(),
2538 GetComputedStyleMap());
2542 void nsComputedDOMStyle::UnregisterPrefChangeCallbacks() {
2543 if (!gCallbackPrefs
) {
2547 Preferences::UnregisterCallbacks(MarkComputedStyleMapDirty
,
2548 gCallbackPrefs
->Elements(),
2549 GetComputedStyleMap());
2550 gCallbackPrefs
= nullptr;