Bumping manifests a=b2g-bump
[gecko.git] / layout / style / nsComputedDOMStyle.cpp
blob9e07a00b2bc2c4986797a36454b9c7d8c4577759
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set tw=78 expandtab softtabstop=2 ts=2 sw=2: */
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/Preferences.h"
14 #include "nsError.h"
15 #include "nsDOMString.h"
16 #include "nsIDOMCSSPrimitiveValue.h"
17 #include "nsIFrame.h"
18 #include "nsIFrameInlines.h"
19 #include "nsStyleContext.h"
20 #include "nsIScrollableFrame.h"
21 #include "nsContentUtils.h"
22 #include "nsIContent.h"
24 #include "nsDOMCSSRect.h"
25 #include "nsDOMCSSRGBColor.h"
26 #include "nsDOMCSSValueList.h"
27 #include "nsFlexContainerFrame.h"
28 #include "nsGkAtoms.h"
29 #include "nsHTMLReflowState.h"
30 #include "nsStyleUtil.h"
31 #include "nsStyleStructInlines.h"
32 #include "nsROCSSPrimitiveValue.h"
34 #include "nsPresContext.h"
35 #include "nsIDocument.h"
37 #include "nsCSSPseudoElements.h"
38 #include "nsStyleSet.h"
39 #include "imgIRequest.h"
40 #include "nsLayoutUtils.h"
41 #include "nsCSSKeywords.h"
42 #include "nsStyleCoord.h"
43 #include "nsDisplayList.h"
44 #include "nsDOMCSSDeclaration.h"
45 #include "nsStyleTransformMatrix.h"
46 #include "mozilla/dom/Element.h"
47 #include "prtime.h"
48 #include "nsWrapperCacheInlines.h"
49 #include "mozilla/AppUnits.h"
50 #include <algorithm>
52 using namespace mozilla;
53 using namespace mozilla::dom;
54 typedef const nsStyleBackground::Position Position;
55 typedef const nsStyleBackground::Position::PositionCoord PositionCoord;
57 #if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
58 #define DEBUG_ComputedDOMStyle
59 #endif
62 * This is the implementation of the readonly CSSStyleDeclaration that is
63 * returned by the getComputedStyle() function.
66 already_AddRefed<nsComputedDOMStyle>
67 NS_NewComputedDOMStyle(dom::Element* aElement, const nsAString& aPseudoElt,
68 nsIPresShell* aPresShell,
69 nsComputedDOMStyle::StyleType aStyleType)
71 nsRefPtr<nsComputedDOMStyle> computedStyle;
72 computedStyle = new nsComputedDOMStyle(aElement, aPseudoElt, aPresShell,
73 aStyleType);
74 return computedStyle.forget();
77 /**
78 * An object that represents the ordered set of properties that are exposed on
79 * an nsComputedDOMStyle object and how their computed values can be obtained.
81 struct nsComputedStyleMap
83 friend class nsComputedDOMStyle;
85 struct Entry
87 // Create a pointer-to-member-function type.
88 typedef mozilla::dom::CSSValue* (nsComputedDOMStyle::*ComputeMethod)();
90 nsCSSProperty mProperty;
91 ComputeMethod mGetter;
93 bool IsLayoutFlushNeeded() const
95 return nsCSSProps::PropHasFlags(mProperty,
96 CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH);
99 bool IsEnabled() const
101 return nsCSSProps::IsEnabled(mProperty);
105 // We define this enum just to count the total number of properties that can
106 // be exposed on an nsComputedDOMStyle, including properties that may be
107 // disabled.
108 enum {
109 #define COMPUTED_STYLE_PROP(prop_, method_) \
110 eComputedStyleProperty_##prop_,
111 #include "nsComputedDOMStylePropertyList.h"
112 #undef COMPUTED_STYLE_PROP
113 eComputedStyleProperty_COUNT
117 * Returns the number of properties that should be exposed on an
118 * nsComputedDOMStyle, ecxluding any disabled properties.
120 uint32_t Length()
122 Update();
123 return mExposedPropertyCount;
127 * Returns the property at the given index in the list of properties
128 * that should be exposed on an nsComputedDOMStyle, excluding any
129 * disabled properties.
131 nsCSSProperty PropertyAt(uint32_t aIndex)
133 Update();
134 return kEntries[EntryIndex(aIndex)].mProperty;
138 * Searches for and returns the computed style map entry for the given
139 * property, or nullptr if the property is not exposed on nsComputedDOMStyle
140 * or is currently disabled.
142 const Entry* FindEntryForProperty(nsCSSProperty aPropID)
144 Update();
145 for (uint32_t i = 0; i < mExposedPropertyCount; i++) {
146 const Entry* entry = &kEntries[EntryIndex(i)];
147 if (entry->mProperty == aPropID) {
148 return entry;
151 return nullptr;
155 * Records that mIndexMap needs updating, due to prefs changing that could
156 * affect the set of properties exposed on an nsComputedDOMStyle.
158 void MarkDirty() { mExposedPropertyCount = 0; }
160 // The member variables are public so that we can use an initializer in
161 // nsComputedDOMStyle::GetComputedStyleMap. Use the member functions
162 // above to get information from this object.
165 * An entry for each property that can be exposed on an nsComputedDOMStyle.
167 const Entry kEntries[eComputedStyleProperty_COUNT];
170 * The number of properties that should be exposed on an nsComputedDOMStyle.
171 * This will be less than eComputedStyleProperty_COUNT if some property
172 * prefs are disabled. A value of 0 indicates that it and mIndexMap are out
173 * of date.
175 uint32_t mExposedPropertyCount;
178 * A map of indexes on the nsComputedDOMStyle object to indexes into kEntries.
180 uint32_t mIndexMap[eComputedStyleProperty_COUNT];
182 private:
184 * Returns whether mExposedPropertyCount and mIndexMap are out of date.
186 bool IsDirty() { return mExposedPropertyCount == 0; }
189 * Updates mExposedPropertyCount and mIndexMap to take into account properties
190 * whose prefs are currently disabled.
192 void Update();
195 * Maps an nsComputedDOMStyle indexed getter index to an index into kEntries.
197 uint32_t EntryIndex(uint32_t aIndex) const
199 MOZ_ASSERT(aIndex < mExposedPropertyCount);
200 return mIndexMap[aIndex];
204 void
205 nsComputedStyleMap::Update()
207 if (!IsDirty()) {
208 return;
211 uint32_t index = 0;
212 for (uint32_t i = 0; i < eComputedStyleProperty_COUNT; i++) {
213 if (kEntries[i].IsEnabled()) {
214 mIndexMap[index++] = i;
217 mExposedPropertyCount = index;
220 nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement,
221 const nsAString& aPseudoElt,
222 nsIPresShell* aPresShell,
223 StyleType aStyleType)
224 : mDocumentWeak(nullptr), mOuterFrame(nullptr),
225 mInnerFrame(nullptr), mPresShell(nullptr),
226 mStyleType(aStyleType),
227 mExposeVisitedStyle(false)
229 MOZ_ASSERT(aElement && aPresShell);
231 mDocumentWeak = do_GetWeakReference(aPresShell->GetDocument());
233 mContent = aElement;
235 if (!DOMStringIsNull(aPseudoElt) && !aPseudoElt.IsEmpty() &&
236 aPseudoElt.First() == char16_t(':')) {
237 // deal with two-colon forms of aPseudoElt
238 nsAString::const_iterator start, end;
239 aPseudoElt.BeginReading(start);
240 aPseudoElt.EndReading(end);
241 NS_ASSERTION(start != end, "aPseudoElt is not empty!");
242 ++start;
243 bool haveTwoColons = true;
244 if (start == end || *start != char16_t(':')) {
245 --start;
246 haveTwoColons = false;
248 mPseudo = do_GetAtom(Substring(start, end));
249 MOZ_ASSERT(mPseudo);
251 // There aren't any non-CSS2 pseudo-elements with a single ':'
252 if (!haveTwoColons &&
253 (!nsCSSPseudoElements::IsPseudoElement(mPseudo) ||
254 !nsCSSPseudoElements::IsCSS2PseudoElement(mPseudo))) {
255 // XXXbz I'd really rather we threw an exception or something, but
256 // the DOM spec sucks.
257 mPseudo = nullptr;
261 MOZ_ASSERT(aPresShell->GetPresContext());
265 nsComputedDOMStyle::~nsComputedDOMStyle()
269 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsComputedDOMStyle, mContent)
271 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle)
272 return tmp->IsBlack();
273 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
275 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsComputedDOMStyle)
276 return tmp->IsBlack();
277 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
279 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsComputedDOMStyle)
280 return tmp->IsBlack();
281 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
283 // QueryInterface implementation for nsComputedDOMStyle
284 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsComputedDOMStyle)
285 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
286 NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
289 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsComputedDOMStyle)
290 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsComputedDOMStyle)
292 NS_IMETHODIMP
293 nsComputedDOMStyle::GetPropertyValue(const nsCSSProperty aPropID,
294 nsAString& aValue)
296 // This is mostly to avoid code duplication with GetPropertyCSSValue(); if
297 // perf ever becomes an issue here (doubtful), we can look into changing
298 // this.
299 return GetPropertyValue(
300 NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(aPropID)),
301 aValue);
304 NS_IMETHODIMP
305 nsComputedDOMStyle::SetPropertyValue(const nsCSSProperty aPropID,
306 const nsAString& aValue)
308 return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
312 NS_IMETHODIMP
313 nsComputedDOMStyle::GetCssText(nsAString& aCssText)
315 aCssText.Truncate();
317 return NS_OK;
321 NS_IMETHODIMP
322 nsComputedDOMStyle::SetCssText(const nsAString& aCssText)
324 return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
328 NS_IMETHODIMP
329 nsComputedDOMStyle::GetLength(uint32_t* aLength)
331 NS_PRECONDITION(aLength, "Null aLength! Prepare to die!");
333 uint32_t length = GetComputedStyleMap()->Length();
335 // Make sure we have up to date style so that we can include custom
336 // properties.
337 UpdateCurrentStyleSources(false);
338 if (mStyleContextHolder) {
339 length += StyleVariables()->mVariables.Count();
342 *aLength = length;
344 ClearCurrentStyleSources();
346 return NS_OK;
350 NS_IMETHODIMP
351 nsComputedDOMStyle::GetParentRule(nsIDOMCSSRule** aParentRule)
353 *aParentRule = nullptr;
355 return NS_OK;
359 NS_IMETHODIMP
360 nsComputedDOMStyle::GetPropertyValue(const nsAString& aPropertyName,
361 nsAString& aReturn)
363 aReturn.Truncate();
365 ErrorResult error;
366 nsRefPtr<CSSValue> val = GetPropertyCSSValue(aPropertyName, error);
367 if (error.Failed()) {
368 return error.ErrorCode();
371 if (val) {
372 nsString text;
373 val->GetCssText(text, error);
374 aReturn.Assign(text);
375 return error.ErrorCode();
378 return NS_OK;
381 NS_IMETHODIMP
382 nsComputedDOMStyle::GetAuthoredPropertyValue(const nsAString& aPropertyName,
383 nsAString& aReturn)
385 // Authored style doesn't make sense to return from computed DOM style,
386 // so just return whatever GetPropertyValue() returns.
387 return GetPropertyValue(aPropertyName, aReturn);
390 /* static */
391 already_AddRefed<nsStyleContext>
392 nsComputedDOMStyle::GetStyleContextForElement(Element* aElement,
393 nsIAtom* aPseudo,
394 nsIPresShell* aPresShell,
395 StyleType aStyleType)
397 // If the content has a pres shell, we must use it. Otherwise we'd
398 // potentially mix rule trees by using the wrong pres shell's style
399 // set. Using the pres shell from the content also means that any
400 // content that's actually *in* a document will get the style from the
401 // correct document.
402 nsCOMPtr<nsIPresShell> presShell = GetPresShellForContent(aElement);
403 if (!presShell) {
404 presShell = aPresShell;
405 if (!presShell)
406 return nullptr;
409 presShell->FlushPendingNotifications(Flush_Style);
411 return GetStyleContextForElementNoFlush(aElement, aPseudo, presShell,
412 aStyleType);
415 /* static */
416 already_AddRefed<nsStyleContext>
417 nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
418 nsIAtom* aPseudo,
419 nsIPresShell* aPresShell,
420 StyleType aStyleType)
422 NS_ABORT_IF_FALSE(aElement, "NULL element");
423 // If the content has a pres shell, we must use it. Otherwise we'd
424 // potentially mix rule trees by using the wrong pres shell's style
425 // set. Using the pres shell from the content also means that any
426 // content that's actually *in* a document will get the style from the
427 // correct document.
428 nsIPresShell *presShell = GetPresShellForContent(aElement);
429 if (!presShell) {
430 presShell = aPresShell;
431 if (!presShell)
432 return nullptr;
435 if (!aPseudo && aStyleType == eAll) {
436 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
437 if (frame) {
438 nsStyleContext* result = frame->StyleContext();
439 // Don't use the style context if it was influenced by
440 // pseudo-elements, since then it's not the primary style
441 // for this element.
442 if (!result->HasPseudoElementData()) {
443 // this function returns an addrefed style context
444 nsRefPtr<nsStyleContext> ret = result;
445 return ret.forget();
450 // No frame has been created, or we have a pseudo, or we're looking
451 // for the default style, so resolve the style ourselves.
452 nsRefPtr<nsStyleContext> parentContext;
453 nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
454 // Don't resolve parent context for document fragments.
455 if (parent && parent->IsElement())
456 parentContext = GetStyleContextForElementNoFlush(parent->AsElement(),
457 nullptr, presShell,
458 aStyleType);
460 nsPresContext *presContext = presShell->GetPresContext();
461 if (!presContext)
462 return nullptr;
464 nsStyleSet *styleSet = presShell->StyleSet();
466 nsRefPtr<nsStyleContext> sc;
467 if (aPseudo) {
468 nsCSSPseudoElements::Type type = nsCSSPseudoElements::GetPseudoType(aPseudo);
469 if (type >= nsCSSPseudoElements::ePseudo_PseudoElementCount) {
470 return nullptr;
472 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
473 Element* pseudoElement = frame ? frame->GetPseudoElement(type) : nullptr;
474 sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext,
475 pseudoElement);
476 } else {
477 sc = styleSet->ResolveStyleFor(aElement, parentContext);
480 if (aStyleType == eDefaultOnly) {
481 // We really only want the user and UA rules. Filter out the other ones.
482 nsTArray< nsCOMPtr<nsIStyleRule> > rules;
483 for (nsRuleNode* ruleNode = sc->RuleNode();
484 !ruleNode->IsRoot();
485 ruleNode = ruleNode->GetParent()) {
486 if (ruleNode->GetLevel() == nsStyleSet::eAgentSheet ||
487 ruleNode->GetLevel() == nsStyleSet::eUserSheet) {
488 rules.AppendElement(ruleNode->GetRule());
492 // We want to build a list of user/ua rules that is in order from least to
493 // most important, so we have to reverse the list.
494 // Integer division to get "stop" is purposeful here: if length is odd, we
495 // don't have to do anything with the middle element of the array.
496 for (uint32_t i = 0, length = rules.Length(), stop = length / 2;
497 i < stop; ++i) {
498 rules[i].swap(rules[length - i - 1]);
501 sc = styleSet->ResolveStyleForRules(parentContext, rules);
504 return sc.forget();
507 nsMargin
508 nsComputedDOMStyle::GetAdjustedValuesForBoxSizing()
510 // We want the width/height of whatever parts 'width' or 'height' controls,
511 // which can be different depending on the value of the 'box-sizing' property.
512 const nsStylePosition* stylePos = StylePosition();
514 nsMargin adjustment;
515 switch(stylePos->mBoxSizing) {
516 case NS_STYLE_BOX_SIZING_BORDER:
517 adjustment += mInnerFrame->GetUsedBorder();
518 // fall through
520 case NS_STYLE_BOX_SIZING_PADDING:
521 adjustment += mInnerFrame->GetUsedPadding();
524 return adjustment;
527 /* static */
528 nsIPresShell*
529 nsComputedDOMStyle::GetPresShellForContent(nsIContent* aContent)
531 nsIDocument* composedDoc = aContent->GetComposedDoc();
532 if (!composedDoc)
533 return nullptr;
535 return composedDoc->GetShell();
538 // nsDOMCSSDeclaration abstract methods which should never be called
539 // on a nsComputedDOMStyle object, but must be defined to avoid
540 // compile errors.
541 css::Declaration*
542 nsComputedDOMStyle::GetCSSDeclaration(bool)
544 NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSDeclaration");
545 return nullptr;
548 nsresult
549 nsComputedDOMStyle::SetCSSDeclaration(css::Declaration*)
551 NS_RUNTIMEABORT("called nsComputedDOMStyle::SetCSSDeclaration");
552 return NS_ERROR_FAILURE;
555 nsIDocument*
556 nsComputedDOMStyle::DocToUpdate()
558 NS_RUNTIMEABORT("called nsComputedDOMStyle::DocToUpdate");
559 return nullptr;
562 void
563 nsComputedDOMStyle::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
565 NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSParsingEnvironment");
566 // Just in case NS_RUNTIMEABORT ever stops killing us for some reason
567 aCSSParseEnv.mPrincipal = nullptr;
570 void
571 nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
573 MOZ_ASSERT(!mStyleContextHolder);
575 nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocumentWeak);
576 if (!document) {
577 return;
580 document->FlushPendingLinkUpdates();
582 // Flush _before_ getting the presshell, since that could create a new
583 // presshell. Also note that we want to flush the style on the document
584 // we're computing style in, not on the document mContent is in -- the two
585 // may be different.
586 document->FlushPendingNotifications(
587 aNeedsLayoutFlush ? Flush_Layout : Flush_Style);
588 #ifdef DEBUG
589 mFlushedPendingReflows = aNeedsLayoutFlush;
590 #endif
592 mPresShell = document->GetShell();
593 if (!mPresShell || !mPresShell->GetPresContext()) {
594 return;
597 if (!mPseudo && mStyleType == eAll) {
598 mOuterFrame = mContent->GetPrimaryFrame();
599 mInnerFrame = mOuterFrame;
600 if (mOuterFrame) {
601 nsIAtom* type = mOuterFrame->GetType();
602 if (type == nsGkAtoms::tableOuterFrame) {
603 // If the frame is an outer table frame then we should get the style
604 // from the inner table frame.
605 mInnerFrame = mOuterFrame->GetFirstPrincipalChild();
606 NS_ASSERTION(mInnerFrame, "Outer table must have an inner");
607 NS_ASSERTION(!mInnerFrame->GetNextSibling(),
608 "Outer table frames should have just one child, "
609 "the inner table");
612 mStyleContextHolder = mInnerFrame->StyleContext();
613 NS_ASSERTION(mStyleContextHolder, "Frame without style context?");
617 if (!mStyleContextHolder || mStyleContextHolder->HasPseudoElementData()) {
618 #ifdef DEBUG
619 if (mStyleContextHolder) {
620 // We want to check that going through this path because of
621 // HasPseudoElementData is rare, because it slows us down a good
622 // bit. So check that we're really inside something associated
623 // with a pseudo-element that contains elements.
624 nsStyleContext *topWithPseudoElementData = mStyleContextHolder;
625 while (topWithPseudoElementData->GetParent()->HasPseudoElementData()) {
626 topWithPseudoElementData = topWithPseudoElementData->GetParent();
628 nsCSSPseudoElements::Type pseudo =
629 topWithPseudoElementData->GetPseudoType();
630 nsIAtom* pseudoAtom = nsCSSPseudoElements::GetPseudoAtom(pseudo);
631 nsAutoString assertMsg(
632 NS_LITERAL_STRING("we should be in a pseudo-element that is expected to contain elements ("));
633 assertMsg.Append(nsDependentString(pseudoAtom->GetUTF16String()));
634 assertMsg.Append(')');
635 NS_ASSERTION(nsCSSPseudoElements::PseudoElementContainsElements(pseudo),
636 NS_LossyConvertUTF16toASCII(assertMsg).get());
638 #endif
639 // Need to resolve a style context
640 mStyleContextHolder =
641 nsComputedDOMStyle::GetStyleContextForElement(mContent->AsElement(),
642 mPseudo,
643 mPresShell,
644 mStyleType);
645 if (!mStyleContextHolder) {
646 return;
649 NS_ASSERTION(mPseudo || !mStyleContextHolder->HasPseudoElementData(),
650 "should not have pseudo-element data");
653 // mExposeVisitedStyle is set to true only by testing APIs that
654 // require chrome privilege.
655 NS_ABORT_IF_FALSE(!mExposeVisitedStyle ||
656 nsContentUtils::IsCallerChrome(),
657 "mExposeVisitedStyle set incorrectly");
658 if (mExposeVisitedStyle && mStyleContextHolder->RelevantLinkVisited()) {
659 nsStyleContext *styleIfVisited = mStyleContextHolder->GetStyleIfVisited();
660 if (styleIfVisited) {
661 mStyleContextHolder = styleIfVisited;
666 void
667 nsComputedDOMStyle::ClearCurrentStyleSources()
669 mOuterFrame = nullptr;
670 mInnerFrame = nullptr;
671 mPresShell = nullptr;
673 // Release the current style context for it should be re-resolved
674 // whenever a frame is not available.
675 mStyleContextHolder = nullptr;
678 already_AddRefed<CSSValue>
679 nsComputedDOMStyle::GetPropertyCSSValue(const nsAString& aPropertyName, ErrorResult& aRv)
681 nsCSSProperty prop = nsCSSProps::LookupProperty(aPropertyName,
682 nsCSSProps::eEnabledForAllContent);
684 bool needsLayoutFlush;
685 nsComputedStyleMap::Entry::ComputeMethod getter;
687 if (prop == eCSSPropertyExtra_variable) {
688 needsLayoutFlush = false;
689 getter = nullptr;
690 } else {
691 // We don't (for now, anyway, though it may make sense to change it
692 // for all aliases, including those in nsCSSPropAliasList) want
693 // aliases to be enumerable (via GetLength and IndexedGetter), so
694 // handle them here rather than adding entries to
695 // GetQueryablePropertyMap.
696 if (prop != eCSSProperty_UNKNOWN &&
697 nsCSSProps::PropHasFlags(prop, CSS_PROPERTY_IS_ALIAS)) {
698 const nsCSSProperty* subprops = nsCSSProps::SubpropertyEntryFor(prop);
699 NS_ABORT_IF_FALSE(subprops[1] == eCSSProperty_UNKNOWN,
700 "must have list of length 1");
701 prop = subprops[0];
704 const nsComputedStyleMap::Entry* propEntry =
705 GetComputedStyleMap()->FindEntryForProperty(prop);
707 if (!propEntry) {
708 #ifdef DEBUG_ComputedDOMStyle
709 NS_WARNING(PromiseFlatCString(NS_ConvertUTF16toUTF8(aPropertyName) +
710 NS_LITERAL_CSTRING(" is not queryable!")).get());
711 #endif
713 // NOTE: For branches, we should flush here for compatibility!
714 return nullptr;
717 needsLayoutFlush = propEntry->IsLayoutFlushNeeded();
718 getter = propEntry->mGetter;
721 UpdateCurrentStyleSources(needsLayoutFlush);
722 if (!mStyleContextHolder) {
723 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
724 return nullptr;
727 nsRefPtr<CSSValue> val;
728 if (prop == eCSSPropertyExtra_variable) {
729 val = DoGetCustomProperty(aPropertyName);
730 } else {
731 // Call our pointer-to-member-function.
732 val = (this->*getter)();
735 ClearCurrentStyleSources();
737 return val.forget();
741 NS_IMETHODIMP
742 nsComputedDOMStyle::RemoveProperty(const nsAString& aPropertyName,
743 nsAString& aReturn)
745 return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
749 NS_IMETHODIMP
750 nsComputedDOMStyle::GetPropertyPriority(const nsAString& aPropertyName,
751 nsAString& aReturn)
753 aReturn.Truncate();
755 return NS_OK;
759 NS_IMETHODIMP
760 nsComputedDOMStyle::SetProperty(const nsAString& aPropertyName,
761 const nsAString& aValue,
762 const nsAString& aPriority)
764 return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
768 NS_IMETHODIMP
769 nsComputedDOMStyle::Item(uint32_t aIndex, nsAString& aReturn)
771 return nsDOMCSSDeclaration::Item(aIndex, aReturn);
774 void
775 nsComputedDOMStyle::IndexedGetter(uint32_t aIndex, bool& aFound,
776 nsAString& aPropName)
778 nsComputedStyleMap* map = GetComputedStyleMap();
779 uint32_t length = map->Length();
781 if (aIndex < length) {
782 aFound = true;
783 CopyASCIItoUTF16(nsCSSProps::GetStringValue(map->PropertyAt(aIndex)),
784 aPropName);
785 return;
788 // Custom properties are exposed with indexed properties just after all
789 // of the built-in properties.
790 UpdateCurrentStyleSources(false);
791 if (!mStyleContextHolder) {
792 aFound = false;
793 return;
796 const nsStyleVariables* variables = StyleVariables();
797 if (aIndex - length < variables->mVariables.Count()) {
798 aFound = true;
799 nsString varName;
800 variables->mVariables.GetVariableAt(aIndex - length, varName);
801 aPropName.AssignLiteral("--");
802 aPropName.Append(varName);
803 } else {
804 aFound = false;
807 ClearCurrentStyleSources();
810 // Property getters...
812 CSSValue*
813 nsComputedDOMStyle::DoGetBinding()
815 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
817 const nsStyleDisplay* display = StyleDisplay();
819 if (display->mBinding) {
820 val->SetURI(display->mBinding->GetURI());
821 } else {
822 val->SetIdent(eCSSKeyword_none);
825 return val;
828 CSSValue*
829 nsComputedDOMStyle::DoGetClear()
831 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
832 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakType,
833 nsCSSProps::kClearKTable));
834 return val;
837 CSSValue*
838 nsComputedDOMStyle::DoGetFloat()
840 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
841 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mFloats,
842 nsCSSProps::kFloatKTable));
843 return val;
846 CSSValue*
847 nsComputedDOMStyle::DoGetBottom()
849 return GetOffsetWidthFor(NS_SIDE_BOTTOM);
852 CSSValue*
853 nsComputedDOMStyle::DoGetStackSizing()
855 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
856 val->SetIdent(StyleXUL()->mStretchStack ? eCSSKeyword_stretch_to_fit :
857 eCSSKeyword_ignore);
858 return val;
861 void
862 nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue,
863 nscolor aColor)
865 if (NS_GET_A(aColor) == 0) {
866 aValue->SetIdent(eCSSKeyword_transparent);
867 return;
870 nsROCSSPrimitiveValue *red = new nsROCSSPrimitiveValue;
871 nsROCSSPrimitiveValue *green = new nsROCSSPrimitiveValue;
872 nsROCSSPrimitiveValue *blue = new nsROCSSPrimitiveValue;
873 nsROCSSPrimitiveValue *alpha = new nsROCSSPrimitiveValue;
875 uint8_t a = NS_GET_A(aColor);
876 nsDOMCSSRGBColor *rgbColor =
877 new nsDOMCSSRGBColor(red, green, blue, alpha, a < 255);
879 red->SetNumber(NS_GET_R(aColor));
880 green->SetNumber(NS_GET_G(aColor));
881 blue->SetNumber(NS_GET_B(aColor));
882 alpha->SetNumber(nsStyleUtil::ColorComponentToFloat(a));
884 aValue->SetColor(rgbColor);
887 CSSValue*
888 nsComputedDOMStyle::DoGetColor()
890 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
891 SetToRGBAColor(val, StyleColor()->mColor);
892 return val;
895 CSSValue*
896 nsComputedDOMStyle::DoGetOpacity()
898 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
899 val->SetNumber(StyleDisplay()->mOpacity);
900 return val;
903 CSSValue*
904 nsComputedDOMStyle::DoGetColumnCount()
906 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
908 const nsStyleColumn* column = StyleColumn();
910 if (column->mColumnCount == NS_STYLE_COLUMN_COUNT_AUTO) {
911 val->SetIdent(eCSSKeyword_auto);
912 } else {
913 val->SetNumber(column->mColumnCount);
916 return val;
919 CSSValue*
920 nsComputedDOMStyle::DoGetColumnWidth()
922 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
924 // XXX fix the auto case. When we actually have a column frame, I think
925 // we should return the computed column width.
926 SetValueToCoord(val, StyleColumn()->mColumnWidth, true);
927 return val;
930 CSSValue*
931 nsComputedDOMStyle::DoGetColumnGap()
933 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
935 const nsStyleColumn* column = StyleColumn();
936 if (column->mColumnGap.GetUnit() == eStyleUnit_Normal) {
937 val->SetAppUnits(StyleFont()->mFont.size);
938 } else {
939 SetValueToCoord(val, StyleColumn()->mColumnGap, true);
942 return val;
945 CSSValue*
946 nsComputedDOMStyle::DoGetColumnFill()
948 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
949 val->SetIdent(
950 nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnFill,
951 nsCSSProps::kColumnFillKTable));
952 return val;
955 CSSValue*
956 nsComputedDOMStyle::DoGetColumnRuleWidth()
958 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
959 val->SetAppUnits(StyleColumn()->GetComputedColumnRuleWidth());
960 return val;
963 CSSValue*
964 nsComputedDOMStyle::DoGetColumnRuleStyle()
966 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
967 val->SetIdent(
968 nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnRuleStyle,
969 nsCSSProps::kBorderStyleKTable));
970 return val;
973 CSSValue*
974 nsComputedDOMStyle::DoGetColumnRuleColor()
976 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
978 const nsStyleColumn* column = StyleColumn();
979 nscolor ruleColor;
980 if (column->mColumnRuleColorIsForeground) {
981 ruleColor = StyleColor()->mColor;
982 } else {
983 ruleColor = column->mColumnRuleColor;
986 SetToRGBAColor(val, ruleColor);
987 return val;
990 CSSValue*
991 nsComputedDOMStyle::DoGetContent()
993 const nsStyleContent *content = StyleContent();
995 if (content->ContentCount() == 0) {
996 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
997 val->SetIdent(eCSSKeyword_none);
998 return val;
1001 if (content->ContentCount() == 1 &&
1002 content->ContentAt(0).mType == eStyleContentType_AltContent) {
1003 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1004 val->SetIdent(eCSSKeyword__moz_alt_content);
1005 return val;
1008 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
1010 for (uint32_t i = 0, i_end = content->ContentCount(); i < i_end; ++i) {
1011 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1012 valueList->AppendCSSValue(val);
1014 const nsStyleContentData &data = content->ContentAt(i);
1015 switch (data.mType) {
1016 case eStyleContentType_String:
1018 nsString str;
1019 nsStyleUtil::AppendEscapedCSSString(
1020 nsDependentString(data.mContent.mString), str);
1021 val->SetString(str);
1023 break;
1024 case eStyleContentType_Image:
1026 nsCOMPtr<nsIURI> uri;
1027 if (data.mContent.mImage) {
1028 data.mContent.mImage->GetURI(getter_AddRefs(uri));
1030 val->SetURI(uri);
1032 break;
1033 case eStyleContentType_Attr:
1035 nsAutoString str;
1036 nsStyleUtil::AppendEscapedCSSIdent(
1037 nsDependentString(data.mContent.mString), str);
1038 val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_ATTR);
1040 break;
1041 case eStyleContentType_Counter:
1042 case eStyleContentType_Counters:
1044 /* FIXME: counters should really use an object */
1045 nsAutoString str;
1046 if (data.mType == eStyleContentType_Counter) {
1047 str.AppendLiteral("counter(");
1049 else {
1050 str.AppendLiteral("counters(");
1052 // WRITE ME
1053 nsCSSValue::Array *a = data.mContent.mCounters;
1055 nsStyleUtil::AppendEscapedCSSIdent(
1056 nsDependentString(a->Item(0).GetStringBufferValue()), str);
1057 int32_t typeItem = 1;
1058 if (data.mType == eStyleContentType_Counters) {
1059 typeItem = 2;
1060 str.AppendLiteral(", ");
1061 nsStyleUtil::AppendEscapedCSSString(
1062 nsDependentString(a->Item(1).GetStringBufferValue()), str);
1064 NS_ABORT_IF_FALSE(eCSSUnit_None != a->Item(typeItem).GetUnit(),
1065 "'none' should be handled as identifier value");
1066 nsString type;
1067 a->Item(typeItem).AppendToString(eCSSProperty_list_style_type,
1068 type, nsCSSValue::eNormalized);
1069 if (!type.LowerCaseEqualsLiteral("decimal")) {
1070 str.AppendLiteral(", ");
1071 str.Append(type);
1074 str.Append(char16_t(')'));
1075 val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_COUNTER);
1077 break;
1078 case eStyleContentType_OpenQuote:
1079 val->SetIdent(eCSSKeyword_open_quote);
1080 break;
1081 case eStyleContentType_CloseQuote:
1082 val->SetIdent(eCSSKeyword_close_quote);
1083 break;
1084 case eStyleContentType_NoOpenQuote:
1085 val->SetIdent(eCSSKeyword_no_open_quote);
1086 break;
1087 case eStyleContentType_NoCloseQuote:
1088 val->SetIdent(eCSSKeyword_no_close_quote);
1089 break;
1090 case eStyleContentType_AltContent:
1091 default:
1092 NS_NOTREACHED("unexpected type");
1093 break;
1097 return valueList;
1100 CSSValue*
1101 nsComputedDOMStyle::DoGetCounterIncrement()
1103 const nsStyleContent *content = StyleContent();
1105 if (content->CounterIncrementCount() == 0) {
1106 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1107 val->SetIdent(eCSSKeyword_none);
1108 return val;
1111 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
1113 for (uint32_t i = 0, i_end = content->CounterIncrementCount(); i < i_end; ++i) {
1114 nsROCSSPrimitiveValue* name = new nsROCSSPrimitiveValue;
1115 valueList->AppendCSSValue(name);
1117 nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
1118 valueList->AppendCSSValue(value);
1120 const nsStyleCounterData *data = content->GetCounterIncrementAt(i);
1121 nsAutoString escaped;
1122 nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
1123 name->SetString(escaped);
1124 value->SetNumber(data->mValue); // XXX This should really be integer
1127 return valueList;
1130 /* Convert the stored representation into a list of two values and then hand
1131 * it back.
1133 CSSValue*
1134 nsComputedDOMStyle::DoGetTransformOrigin()
1136 /* We need to build up a list of two values. We'll call them
1137 * width and height.
1140 /* Store things as a value list */
1141 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
1143 /* Now, get the values. */
1144 const nsStyleDisplay* display = StyleDisplay();
1146 nsROCSSPrimitiveValue* width = new nsROCSSPrimitiveValue;
1147 SetValueToCoord(width, display->mTransformOrigin[0], false,
1148 &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
1149 valueList->AppendCSSValue(width);
1151 nsROCSSPrimitiveValue* height = new nsROCSSPrimitiveValue;
1152 SetValueToCoord(height, display->mTransformOrigin[1], false,
1153 &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
1154 valueList->AppendCSSValue(height);
1156 if (display->mTransformOrigin[2].GetUnit() != eStyleUnit_Coord ||
1157 display->mTransformOrigin[2].GetCoordValue() != 0) {
1158 nsROCSSPrimitiveValue* depth = new nsROCSSPrimitiveValue;
1159 SetValueToCoord(depth, display->mTransformOrigin[2], false,
1160 nullptr);
1161 valueList->AppendCSSValue(depth);
1164 return valueList;
1167 /* Convert the stored representation into a list of two values and then hand
1168 * it back.
1170 CSSValue*
1171 nsComputedDOMStyle::DoGetPerspectiveOrigin()
1173 /* We need to build up a list of two values. We'll call them
1174 * width and height.
1177 /* Store things as a value list */
1178 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
1180 /* Now, get the values. */
1181 const nsStyleDisplay* display = StyleDisplay();
1183 nsROCSSPrimitiveValue* width = new nsROCSSPrimitiveValue;
1184 SetValueToCoord(width, display->mPerspectiveOrigin[0], false,
1185 &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
1186 valueList->AppendCSSValue(width);
1188 nsROCSSPrimitiveValue* height = new nsROCSSPrimitiveValue;
1189 SetValueToCoord(height, display->mPerspectiveOrigin[1], false,
1190 &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
1191 valueList->AppendCSSValue(height);
1193 return valueList;
1196 CSSValue*
1197 nsComputedDOMStyle::DoGetPerspective()
1199 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1200 SetValueToCoord(val, StyleDisplay()->mChildPerspective, false);
1201 return val;
1204 CSSValue*
1205 nsComputedDOMStyle::DoGetBackfaceVisibility()
1207 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1208 val->SetIdent(
1209 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBackfaceVisibility,
1210 nsCSSProps::kBackfaceVisibilityKTable));
1211 return val;
1214 CSSValue*
1215 nsComputedDOMStyle::DoGetTransformStyle()
1217 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1218 val->SetIdent(
1219 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mTransformStyle,
1220 nsCSSProps::kTransformStyleKTable));
1221 return val;
1224 /* If the property is "none", hand back "none" wrapped in a value.
1225 * Otherwise, compute the aggregate transform matrix and hands it back in a
1226 * "matrix" wrapper.
1228 CSSValue*
1229 nsComputedDOMStyle::DoGetTransform()
1231 /* First, get the display data. We'll need it. */
1232 const nsStyleDisplay* display = StyleDisplay();
1234 /* If there are no transforms, then we should construct a single-element
1235 * entry and hand it back.
1237 if (!display->mSpecifiedTransform) {
1238 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1240 /* Set it to "none." */
1241 val->SetIdent(eCSSKeyword_none);
1242 return val;
1245 /* Otherwise, we need to compute the current value of the transform matrix,
1246 * store it in a string, and hand it back to the caller.
1249 /* Use the inner frame for width and height. If we fail, assume zero.
1250 * TODO: There is no good way for us to represent the case where there's no
1251 * frame, which is problematic. The reason is that when we have percentage
1252 * transforms, there are a total of four stored matrix entries that influence
1253 * the transform based on the size of the element. However, this poses a
1254 * problem, because only two of these values can be explicitly referenced
1255 * using the named transforms. Until a real solution is found, we'll just
1256 * use this approach.
1258 nsRect bounds =
1259 (mInnerFrame ? nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame) :
1260 nsRect(0, 0, 0, 0));
1262 bool dummy;
1263 gfx3DMatrix matrix =
1264 nsStyleTransformMatrix::ReadTransforms(display->mSpecifiedTransform->mHead,
1265 mStyleContextHolder,
1266 mStyleContextHolder->PresContext(),
1267 dummy,
1268 bounds,
1269 float(mozilla::AppUnitsPerCSSPixel()));
1271 return MatrixToCSSValue(matrix);
1274 /* static */ nsROCSSPrimitiveValue*
1275 nsComputedDOMStyle::MatrixToCSSValue(gfx3DMatrix& matrix)
1277 bool is3D = !matrix.Is2D();
1279 nsAutoString resultString(NS_LITERAL_STRING("matrix"));
1280 if (is3D) {
1281 resultString.AppendLiteral("3d");
1284 resultString.Append('(');
1285 resultString.AppendFloat(matrix._11);
1286 resultString.AppendLiteral(", ");
1287 resultString.AppendFloat(matrix._12);
1288 resultString.AppendLiteral(", ");
1289 if (is3D) {
1290 resultString.AppendFloat(matrix._13);
1291 resultString.AppendLiteral(", ");
1292 resultString.AppendFloat(matrix._14);
1293 resultString.AppendLiteral(", ");
1295 resultString.AppendFloat(matrix._21);
1296 resultString.AppendLiteral(", ");
1297 resultString.AppendFloat(matrix._22);
1298 resultString.AppendLiteral(", ");
1299 if (is3D) {
1300 resultString.AppendFloat(matrix._23);
1301 resultString.AppendLiteral(", ");
1302 resultString.AppendFloat(matrix._24);
1303 resultString.AppendLiteral(", ");
1304 resultString.AppendFloat(matrix._31);
1305 resultString.AppendLiteral(", ");
1306 resultString.AppendFloat(matrix._32);
1307 resultString.AppendLiteral(", ");
1308 resultString.AppendFloat(matrix._33);
1309 resultString.AppendLiteral(", ");
1310 resultString.AppendFloat(matrix._34);
1311 resultString.AppendLiteral(", ");
1313 resultString.AppendFloat(matrix._41);
1314 resultString.AppendLiteral(", ");
1315 resultString.AppendFloat(matrix._42);
1316 if (is3D) {
1317 resultString.AppendLiteral(", ");
1318 resultString.AppendFloat(matrix._43);
1319 resultString.AppendLiteral(", ");
1320 resultString.AppendFloat(matrix._44);
1322 resultString.Append(')');
1324 /* Create a value to hold our result. */
1325 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1327 val->SetString(resultString);
1328 return val;
1331 CSSValue*
1332 nsComputedDOMStyle::DoGetCounterReset()
1334 const nsStyleContent *content = StyleContent();
1336 if (content->CounterResetCount() == 0) {
1337 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1338 val->SetIdent(eCSSKeyword_none);
1339 return val;
1342 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
1344 for (uint32_t i = 0, i_end = content->CounterResetCount(); i < i_end; ++i) {
1345 nsROCSSPrimitiveValue* name = new nsROCSSPrimitiveValue;
1346 valueList->AppendCSSValue(name);
1348 nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
1349 valueList->AppendCSSValue(value);
1351 const nsStyleCounterData *data = content->GetCounterResetAt(i);
1352 nsAutoString escaped;
1353 nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
1354 name->SetString(escaped);
1355 value->SetNumber(data->mValue); // XXX This should really be integer
1358 return valueList;
1361 CSSValue*
1362 nsComputedDOMStyle::DoGetQuotes()
1364 const nsStyleQuotes *quotes = StyleQuotes();
1366 if (quotes->QuotesCount() == 0) {
1367 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1368 val->SetIdent(eCSSKeyword_none);
1369 return val;
1372 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
1374 for (uint32_t i = 0, i_end = quotes->QuotesCount(); i < i_end; ++i) {
1375 nsROCSSPrimitiveValue* openVal = new nsROCSSPrimitiveValue;
1376 valueList->AppendCSSValue(openVal);
1378 nsROCSSPrimitiveValue* closeVal = new nsROCSSPrimitiveValue;
1379 valueList->AppendCSSValue(closeVal);
1381 nsString s;
1382 nsStyleUtil::AppendEscapedCSSString(*quotes->OpenQuoteAt(i), s);
1383 openVal->SetString(s);
1384 s.Truncate();
1385 nsStyleUtil::AppendEscapedCSSString(*quotes->CloseQuoteAt(i), s);
1386 closeVal->SetString(s);
1389 return valueList;
1392 CSSValue*
1393 nsComputedDOMStyle::DoGetFontFamily()
1395 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1397 const nsStyleFont* font = StyleFont();
1398 nsAutoString fontlistStr;
1399 nsStyleUtil::AppendEscapedCSSFontFamilyList(font->mFont.fontlist,
1400 fontlistStr);
1401 val->SetString(fontlistStr);
1402 return val;
1405 CSSValue*
1406 nsComputedDOMStyle::DoGetFontSize()
1408 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1410 // Note: StyleFont()->mSize is the 'computed size';
1411 // StyleFont()->mFont.size is the 'actual size'
1412 val->SetAppUnits(StyleFont()->mSize);
1413 return val;
1416 CSSValue*
1417 nsComputedDOMStyle::DoGetFontSizeAdjust()
1419 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1421 const nsStyleFont *font = StyleFont();
1423 if (font->mFont.sizeAdjust) {
1424 val->SetNumber(font->mFont.sizeAdjust);
1425 } else {
1426 val->SetIdent(eCSSKeyword_none);
1429 return val;
1432 CSSValue*
1433 nsComputedDOMStyle::DoGetOSXFontSmoothing()
1435 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1436 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.smoothing,
1437 nsCSSProps::kFontSmoothingKTable));
1438 return val;
1441 CSSValue*
1442 nsComputedDOMStyle::DoGetFontStretch()
1444 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1446 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.stretch,
1447 nsCSSProps::kFontStretchKTable));
1449 return val;
1452 CSSValue*
1453 nsComputedDOMStyle::DoGetFontStyle()
1455 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1456 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.style,
1457 nsCSSProps::kFontStyleKTable));
1458 return val;
1461 CSSValue*
1462 nsComputedDOMStyle::DoGetFontWeight()
1464 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1466 const nsStyleFont* font = StyleFont();
1468 uint16_t weight = font->mFont.weight;
1469 NS_ASSERTION(weight % 100 == 0, "unexpected value of font-weight");
1470 val->SetNumber(weight);
1472 return val;
1475 CSSValue*
1476 nsComputedDOMStyle::DoGetFontFeatureSettings()
1478 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1480 const nsStyleFont* font = StyleFont();
1481 if (font->mFont.fontFeatureSettings.IsEmpty()) {
1482 val->SetIdent(eCSSKeyword_normal);
1483 } else {
1484 nsAutoString result;
1485 nsStyleUtil::AppendFontFeatureSettings(font->mFont.fontFeatureSettings,
1486 result);
1487 val->SetString(result);
1489 return val;
1492 CSSValue*
1493 nsComputedDOMStyle::DoGetFontKerning()
1495 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1496 val->SetIdent(
1497 nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.kerning,
1498 nsCSSProps::kFontKerningKTable));
1499 return val;
1502 CSSValue*
1503 nsComputedDOMStyle::DoGetFontLanguageOverride()
1505 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1507 const nsStyleFont* font = StyleFont();
1508 if (font->mFont.languageOverride.IsEmpty()) {
1509 val->SetIdent(eCSSKeyword_normal);
1510 } else {
1511 nsString str;
1512 nsStyleUtil::AppendEscapedCSSString(font->mFont.languageOverride, str);
1513 val->SetString(str);
1515 return val;
1518 CSSValue*
1519 nsComputedDOMStyle::DoGetFontSynthesis()
1521 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1523 int32_t intValue = StyleFont()->mFont.synthesis;
1525 if (0 == intValue) {
1526 val->SetIdent(eCSSKeyword_none);
1527 } else {
1528 nsAutoString valueStr;
1530 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_synthesis,
1531 intValue, NS_FONT_SYNTHESIS_WEIGHT,
1532 NS_FONT_SYNTHESIS_STYLE, valueStr);
1533 val->SetString(valueStr);
1536 return val;
1539 // return a value *only* for valid longhand values from CSS 2.1, either
1540 // normal or small-caps only
1541 CSSValue*
1542 nsComputedDOMStyle::DoGetFontVariant()
1544 const nsFont& f = StyleFont()->mFont;
1546 // if any of the other font-variant subproperties other than
1547 // font-variant-caps are not normal then can't calculate a computed value
1548 if (f.variantAlternates || f.variantEastAsian || f.variantLigatures ||
1549 f.variantNumeric || f.variantPosition) {
1550 return nullptr;
1553 nsCSSKeyword keyword;
1554 switch (f.variantCaps) {
1555 case 0:
1556 keyword = eCSSKeyword_normal;
1557 break;
1558 case NS_FONT_VARIANT_CAPS_SMALLCAPS:
1559 keyword = eCSSKeyword_small_caps;
1560 break;
1561 default:
1562 return nullptr;
1565 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1566 val->SetIdent(keyword);
1567 return val;
1570 CSSValue*
1571 nsComputedDOMStyle::DoGetFontVariantAlternates()
1573 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1575 int32_t intValue = StyleFont()->mFont.variantAlternates;
1577 if (0 == intValue) {
1578 val->SetIdent(eCSSKeyword_normal);
1579 return val;
1582 // first, include enumerated values
1583 nsAutoString valueStr;
1585 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_alternates,
1586 intValue & NS_FONT_VARIANT_ALTERNATES_ENUMERATED_MASK,
1587 NS_FONT_VARIANT_ALTERNATES_HISTORICAL,
1588 NS_FONT_VARIANT_ALTERNATES_HISTORICAL, valueStr);
1590 // next, include functional values if present
1591 if (intValue & NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK) {
1592 nsStyleUtil::SerializeFunctionalAlternates(StyleFont()->mFont.alternateValues,
1593 valueStr);
1596 val->SetString(valueStr);
1597 return val;
1600 CSSValue*
1601 nsComputedDOMStyle::DoGetFontVariantCaps()
1603 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1605 int32_t intValue = StyleFont()->mFont.variantCaps;
1607 if (0 == intValue) {
1608 val->SetIdent(eCSSKeyword_normal);
1609 } else {
1610 val->SetIdent(
1611 nsCSSProps::ValueToKeywordEnum(intValue,
1612 nsCSSProps::kFontVariantCapsKTable));
1615 return val;
1618 CSSValue*
1619 nsComputedDOMStyle::DoGetFontVariantEastAsian()
1621 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1623 int32_t intValue = StyleFont()->mFont.variantEastAsian;
1625 if (0 == intValue) {
1626 val->SetIdent(eCSSKeyword_normal);
1627 } else {
1628 nsAutoString valueStr;
1630 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_east_asian,
1631 intValue, NS_FONT_VARIANT_EAST_ASIAN_JIS78,
1632 NS_FONT_VARIANT_EAST_ASIAN_RUBY, valueStr);
1633 val->SetString(valueStr);
1636 return val;
1639 CSSValue*
1640 nsComputedDOMStyle::DoGetFontVariantLigatures()
1642 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1644 int32_t intValue = StyleFont()->mFont.variantLigatures;
1646 if (0 == intValue) {
1647 val->SetIdent(eCSSKeyword_normal);
1648 } else if (NS_FONT_VARIANT_LIGATURES_NONE == intValue) {
1649 val->SetIdent(eCSSKeyword_none);
1650 } else {
1651 nsAutoString valueStr;
1653 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_ligatures,
1654 intValue, NS_FONT_VARIANT_LIGATURES_NONE,
1655 NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL, valueStr);
1656 val->SetString(valueStr);
1659 return val;
1662 CSSValue*
1663 nsComputedDOMStyle::DoGetFontVariantNumeric()
1665 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1667 int32_t intValue = StyleFont()->mFont.variantNumeric;
1669 if (0 == intValue) {
1670 val->SetIdent(eCSSKeyword_normal);
1671 } else {
1672 nsAutoString valueStr;
1674 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_numeric,
1675 intValue, NS_FONT_VARIANT_NUMERIC_LINING,
1676 NS_FONT_VARIANT_NUMERIC_ORDINAL, valueStr);
1677 val->SetString(valueStr);
1680 return val;
1683 CSSValue*
1684 nsComputedDOMStyle::DoGetFontVariantPosition()
1686 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1688 int32_t intValue = StyleFont()->mFont.variantPosition;
1690 if (0 == intValue) {
1691 val->SetIdent(eCSSKeyword_normal);
1692 } else {
1693 val->SetIdent(
1694 nsCSSProps::ValueToKeywordEnum(intValue,
1695 nsCSSProps::kFontVariantPositionKTable));
1698 return val;
1701 CSSValue*
1702 nsComputedDOMStyle::GetBackgroundList(uint8_t nsStyleBackground::Layer::* aMember,
1703 uint32_t nsStyleBackground::* aCount,
1704 const KTableValue aTable[])
1706 const nsStyleBackground* bg = StyleBackground();
1708 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
1710 for (uint32_t i = 0, i_end = bg->*aCount; i < i_end; ++i) {
1711 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
1712 valueList->AppendCSSValue(val);
1713 val->SetIdent(nsCSSProps::ValueToKeywordEnum(bg->mLayers[i].*aMember,
1714 aTable));
1717 return valueList;
1720 CSSValue*
1721 nsComputedDOMStyle::DoGetBackgroundAttachment()
1723 return GetBackgroundList(&nsStyleBackground::Layer::mAttachment,
1724 &nsStyleBackground::mAttachmentCount,
1725 nsCSSProps::kBackgroundAttachmentKTable);
1728 CSSValue*
1729 nsComputedDOMStyle::DoGetBackgroundClip()
1731 return GetBackgroundList(&nsStyleBackground::Layer::mClip,
1732 &nsStyleBackground::mClipCount,
1733 nsCSSProps::kBackgroundOriginKTable);
1736 CSSValue*
1737 nsComputedDOMStyle::DoGetBackgroundColor()
1739 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
1740 SetToRGBAColor(val, StyleBackground()->mBackgroundColor);
1741 return val;
1745 static void
1746 SetValueToCalc(const nsStyleCoord::CalcValue *aCalc, nsROCSSPrimitiveValue *aValue)
1748 nsRefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
1749 nsAutoString tmp, result;
1751 result.AppendLiteral("calc(");
1753 val->SetAppUnits(aCalc->mLength);
1754 val->GetCssText(tmp);
1755 result.Append(tmp);
1757 if (aCalc->mHasPercent) {
1758 result.AppendLiteral(" + ");
1760 val->SetPercent(aCalc->mPercent);
1761 val->GetCssText(tmp);
1762 result.Append(tmp);
1765 result.Append(')');
1767 aValue->SetString(result); // not really SetString
1770 static void
1771 AppendCSSGradientLength(const nsStyleCoord& aValue,
1772 nsROCSSPrimitiveValue* aPrimitive,
1773 nsAString& aString)
1775 nsAutoString tokenString;
1776 if (aValue.IsCalcUnit())
1777 SetValueToCalc(aValue.GetCalcValue(), aPrimitive);
1778 else if (aValue.GetUnit() == eStyleUnit_Coord)
1779 aPrimitive->SetAppUnits(aValue.GetCoordValue());
1780 else
1781 aPrimitive->SetPercent(aValue.GetPercentValue());
1782 aPrimitive->GetCssText(tokenString);
1783 aString.Append(tokenString);
1786 static void
1787 AppendCSSGradientToBoxPosition(const nsStyleGradient* aGradient,
1788 nsAString& aString,
1789 bool& aNeedSep)
1791 float xValue = aGradient->mBgPosX.GetPercentValue();
1792 float yValue = aGradient->mBgPosY.GetPercentValue();
1794 if (yValue == 1.0f && xValue == 0.5f) {
1795 // omit "to bottom"
1796 return;
1798 NS_ASSERTION(yValue != 0.5f || xValue != 0.5f, "invalid box position");
1800 aString.AppendLiteral("to");
1802 if (yValue == 0.0f) {
1803 aString.AppendLiteral(" top");
1804 } else if (yValue == 1.0f) {
1805 aString.AppendLiteral(" bottom");
1806 } else if (yValue != 0.5f) { // do not write "center" keyword
1807 NS_NOTREACHED("invalid box position");
1810 if (xValue == 0.0f) {
1811 aString.AppendLiteral(" left");
1812 } else if (xValue == 1.0f) {
1813 aString.AppendLiteral(" right");
1814 } else if (xValue != 0.5f) { // do not write "center" keyword
1815 NS_NOTREACHED("invalid box position");
1818 aNeedSep = true;
1821 void
1822 nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient,
1823 nsAString& aString)
1825 if (!aGradient->mLegacySyntax) {
1826 aString.Truncate();
1827 } else {
1828 aString.AssignLiteral("-moz-");
1830 if (aGradient->mRepeating) {
1831 aString.AppendLiteral("repeating-");
1833 bool isRadial = aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR;
1834 if (isRadial) {
1835 aString.AppendLiteral("radial-gradient(");
1836 } else {
1837 aString.AppendLiteral("linear-gradient(");
1840 bool needSep = false;
1841 nsAutoString tokenString;
1842 nsRefPtr<nsROCSSPrimitiveValue> tmpVal = new nsROCSSPrimitiveValue;
1844 if (isRadial && !aGradient->mLegacySyntax) {
1845 if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE) {
1846 if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
1847 aString.AppendLiteral("circle");
1848 needSep = true;
1850 if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) {
1851 if (needSep) {
1852 aString.Append(' ');
1854 AppendASCIItoUTF16(nsCSSProps::
1855 ValueToKeyword(aGradient->mSize,
1856 nsCSSProps::kRadialGradientSizeKTable),
1857 aString);
1858 needSep = true;
1860 } else {
1861 AppendCSSGradientLength(aGradient->mRadiusX, tmpVal, aString);
1862 if (aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
1863 aString.Append(' ');
1864 AppendCSSGradientLength(aGradient->mRadiusY, tmpVal, aString);
1866 needSep = true;
1869 if (aGradient->mBgPosX.GetUnit() != eStyleUnit_None) {
1870 MOZ_ASSERT(aGradient->mBgPosY.GetUnit() != eStyleUnit_None);
1871 if (!isRadial && !aGradient->mLegacySyntax) {
1872 AppendCSSGradientToBoxPosition(aGradient, aString, needSep);
1873 } else if (aGradient->mBgPosX.GetUnit() != eStyleUnit_Percent ||
1874 aGradient->mBgPosX.GetPercentValue() != 0.5f ||
1875 aGradient->mBgPosY.GetUnit() != eStyleUnit_Percent ||
1876 aGradient->mBgPosY.GetPercentValue() != (isRadial ? 0.5f : 1.0f)) {
1877 if (isRadial && !aGradient->mLegacySyntax) {
1878 if (needSep) {
1879 aString.Append(' ');
1881 aString.AppendLiteral("at ");
1882 needSep = false;
1884 AppendCSSGradientLength(aGradient->mBgPosX, tmpVal, aString);
1885 if (aGradient->mBgPosY.GetUnit() != eStyleUnit_None) {
1886 aString.Append(' ');
1887 AppendCSSGradientLength(aGradient->mBgPosY, tmpVal, aString);
1889 needSep = true;
1892 if (aGradient->mAngle.GetUnit() != eStyleUnit_None) {
1893 MOZ_ASSERT(!isRadial || aGradient->mLegacySyntax);
1894 if (needSep) {
1895 aString.Append(' ');
1897 nsStyleUtil::AppendAngleValue(aGradient->mAngle, aString);
1898 needSep = true;
1901 if (isRadial && aGradient->mLegacySyntax &&
1902 (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR ||
1903 aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)) {
1904 MOZ_ASSERT(aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE);
1905 if (needSep) {
1906 aString.AppendLiteral(", ");
1907 needSep = false;
1909 if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
1910 aString.AppendLiteral("circle");
1911 needSep = true;
1913 if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) {
1914 if (needSep) {
1915 aString.Append(' ');
1917 AppendASCIItoUTF16(nsCSSProps::
1918 ValueToKeyword(aGradient->mSize,
1919 nsCSSProps::kRadialGradientSizeKTable),
1920 aString);
1922 needSep = true;
1926 // color stops
1927 for (uint32_t i = 0; i < aGradient->mStops.Length(); ++i) {
1928 if (needSep) {
1929 aString.AppendLiteral(", ");
1932 const auto& stop = aGradient->mStops[i];
1933 if (!stop.mIsInterpolationHint) {
1934 SetToRGBAColor(tmpVal, stop.mColor);
1935 tmpVal->GetCssText(tokenString);
1936 aString.Append(tokenString);
1939 if (stop.mLocation.GetUnit() != eStyleUnit_None) {
1940 if (!stop.mIsInterpolationHint) {
1941 aString.Append(' ');
1943 AppendCSSGradientLength(stop.mLocation, tmpVal, aString);
1945 needSep = true;
1948 aString.Append(')');
1951 // -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
1952 void
1953 nsComputedDOMStyle::GetImageRectString(nsIURI* aURI,
1954 const nsStyleSides& aCropRect,
1955 nsString& aString)
1957 nsRefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
1959 // <uri>
1960 nsROCSSPrimitiveValue *valURI = new nsROCSSPrimitiveValue;
1961 valueList->AppendCSSValue(valURI);
1962 valURI->SetURI(aURI);
1964 // <top>, <right>, <bottom>, <left>
1965 NS_FOR_CSS_SIDES(side) {
1966 nsROCSSPrimitiveValue *valSide = new nsROCSSPrimitiveValue;
1967 valueList->AppendCSSValue(valSide);
1968 SetValueToCoord(valSide, aCropRect.Get(side), false);
1971 nsAutoString argumentString;
1972 valueList->GetCssText(argumentString);
1974 aString = NS_LITERAL_STRING("-moz-image-rect(") +
1975 argumentString +
1976 NS_LITERAL_STRING(")");
1979 void
1980 nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage,
1981 nsROCSSPrimitiveValue* aValue)
1983 switch (aStyleImage.GetType()) {
1984 case eStyleImageType_Image:
1986 imgIRequest *req = aStyleImage.GetImageData();
1987 nsCOMPtr<nsIURI> uri;
1988 req->GetURI(getter_AddRefs(uri));
1990 const nsStyleSides* cropRect = aStyleImage.GetCropRect();
1991 if (cropRect) {
1992 nsAutoString imageRectString;
1993 GetImageRectString(uri, *cropRect, imageRectString);
1994 aValue->SetString(imageRectString);
1995 } else {
1996 aValue->SetURI(uri);
1998 break;
2000 case eStyleImageType_Gradient:
2002 nsAutoString gradientString;
2003 GetCSSGradientString(aStyleImage.GetGradientData(),
2004 gradientString);
2005 aValue->SetString(gradientString);
2006 break;
2008 case eStyleImageType_Element:
2010 nsAutoString elementId;
2011 nsStyleUtil::AppendEscapedCSSIdent(
2012 nsDependentString(aStyleImage.GetElementId()), elementId);
2013 nsAutoString elementString = NS_LITERAL_STRING("-moz-element(#") +
2014 elementId +
2015 NS_LITERAL_STRING(")");
2016 aValue->SetString(elementString);
2017 break;
2019 case eStyleImageType_Null:
2020 aValue->SetIdent(eCSSKeyword_none);
2021 break;
2022 default:
2023 NS_NOTREACHED("unexpected image type");
2024 break;
2028 CSSValue*
2029 nsComputedDOMStyle::DoGetBackgroundImage()
2031 const nsStyleBackground* bg = StyleBackground();
2033 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
2035 for (uint32_t i = 0, i_end = bg->mImageCount; i < i_end; ++i) {
2036 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2037 valueList->AppendCSSValue(val);
2039 const nsStyleImage& image = bg->mLayers[i].mImage;
2040 SetValueToStyleImage(image, val);
2043 return valueList;
2046 CSSValue*
2047 nsComputedDOMStyle::DoGetBackgroundBlendMode()
2049 return GetBackgroundList(&nsStyleBackground::Layer::mBlendMode,
2050 &nsStyleBackground::mBlendModeCount,
2051 nsCSSProps::kBlendModeKTable);
2054 CSSValue*
2055 nsComputedDOMStyle::DoGetBackgroundOrigin()
2057 return GetBackgroundList(&nsStyleBackground::Layer::mOrigin,
2058 &nsStyleBackground::mOriginCount,
2059 nsCSSProps::kBackgroundOriginKTable);
2062 void
2063 nsComputedDOMStyle::SetValueToPositionCoord(const PositionCoord& aCoord,
2064 nsROCSSPrimitiveValue* aValue)
2066 if (!aCoord.mHasPercent) {
2067 NS_ABORT_IF_FALSE(aCoord.mPercent == 0.0f,
2068 "Shouldn't have mPercent!");
2069 aValue->SetAppUnits(aCoord.mLength);
2070 } else if (aCoord.mLength == 0) {
2071 aValue->SetPercent(aCoord.mPercent);
2072 } else {
2073 SetValueToCalc(&aCoord, aValue);
2077 void
2078 nsComputedDOMStyle::SetValueToPosition(const Position& aPosition,
2079 nsDOMCSSValueList* aValueList)
2081 nsROCSSPrimitiveValue* valX = new nsROCSSPrimitiveValue;
2082 aValueList->AppendCSSValue(valX);
2083 SetValueToPositionCoord(aPosition.mXPosition, valX);
2085 nsROCSSPrimitiveValue* valY = new nsROCSSPrimitiveValue;
2086 aValueList->AppendCSSValue(valY);
2087 SetValueToPositionCoord(aPosition.mYPosition, valY);
2090 CSSValue*
2091 nsComputedDOMStyle::DoGetBackgroundPosition()
2093 const nsStyleBackground* bg = StyleBackground();
2095 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
2097 for (uint32_t i = 0, i_end = bg->mPositionCount; i < i_end; ++i) {
2098 nsDOMCSSValueList *itemList = GetROCSSValueList(false);
2099 valueList->AppendCSSValue(itemList);
2101 SetValueToPosition(bg->mLayers[i].mPosition, itemList);
2104 return valueList;
2107 CSSValue*
2108 nsComputedDOMStyle::DoGetBackgroundRepeat()
2110 const nsStyleBackground* bg = StyleBackground();
2112 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
2114 for (uint32_t i = 0, i_end = bg->mRepeatCount; i < i_end; ++i) {
2115 nsDOMCSSValueList *itemList = GetROCSSValueList(false);
2116 valueList->AppendCSSValue(itemList);
2118 nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue;
2119 itemList->AppendCSSValue(valX);
2121 const uint8_t& xRepeat = bg->mLayers[i].mRepeat.mXRepeat;
2122 const uint8_t& yRepeat = bg->mLayers[i].mRepeat.mYRepeat;
2124 bool hasContraction = true;
2125 unsigned contraction;
2126 if (xRepeat == yRepeat) {
2127 contraction = xRepeat;
2128 } else if (xRepeat == NS_STYLE_BG_REPEAT_REPEAT &&
2129 yRepeat == NS_STYLE_BG_REPEAT_NO_REPEAT) {
2130 contraction = NS_STYLE_BG_REPEAT_REPEAT_X;
2131 } else if (xRepeat == NS_STYLE_BG_REPEAT_NO_REPEAT &&
2132 yRepeat == NS_STYLE_BG_REPEAT_REPEAT) {
2133 contraction = NS_STYLE_BG_REPEAT_REPEAT_Y;
2134 } else {
2135 hasContraction = false;
2138 if (hasContraction) {
2139 valX->SetIdent(nsCSSProps::ValueToKeywordEnum(contraction,
2140 nsCSSProps::kBackgroundRepeatKTable));
2141 } else {
2142 nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue;
2143 itemList->AppendCSSValue(valY);
2145 valX->SetIdent(nsCSSProps::ValueToKeywordEnum(xRepeat,
2146 nsCSSProps::kBackgroundRepeatKTable));
2147 valY->SetIdent(nsCSSProps::ValueToKeywordEnum(yRepeat,
2148 nsCSSProps::kBackgroundRepeatKTable));
2152 return valueList;
2155 CSSValue*
2156 nsComputedDOMStyle::DoGetBackgroundSize()
2158 const nsStyleBackground* bg = StyleBackground();
2160 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
2162 for (uint32_t i = 0, i_end = bg->mSizeCount; i < i_end; ++i) {
2163 const nsStyleBackground::Size &size = bg->mLayers[i].mSize;
2165 switch (size.mWidthType) {
2166 case nsStyleBackground::Size::eContain:
2167 case nsStyleBackground::Size::eCover: {
2168 NS_ABORT_IF_FALSE(size.mWidthType == size.mHeightType,
2169 "unsynced types");
2170 nsCSSKeyword keyword = size.mWidthType == nsStyleBackground::Size::eContain
2171 ? eCSSKeyword_contain
2172 : eCSSKeyword_cover;
2173 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2174 valueList->AppendCSSValue(val);
2175 val->SetIdent(keyword);
2176 break;
2178 default: {
2179 nsDOMCSSValueList *itemList = GetROCSSValueList(false);
2180 valueList->AppendCSSValue(itemList);
2182 nsROCSSPrimitiveValue* valX = new nsROCSSPrimitiveValue;
2183 itemList->AppendCSSValue(valX);
2184 nsROCSSPrimitiveValue* valY = new nsROCSSPrimitiveValue;
2185 itemList->AppendCSSValue(valY);
2187 if (size.mWidthType == nsStyleBackground::Size::eAuto) {
2188 valX->SetIdent(eCSSKeyword_auto);
2189 } else {
2190 NS_ABORT_IF_FALSE(size.mWidthType ==
2191 nsStyleBackground::Size::eLengthPercentage,
2192 "bad mWidthType");
2193 if (!size.mWidth.mHasPercent &&
2194 // negative values must have come from calc()
2195 size.mWidth.mLength >= 0) {
2196 NS_ABORT_IF_FALSE(size.mWidth.mPercent == 0.0f,
2197 "Shouldn't have mPercent");
2198 valX->SetAppUnits(size.mWidth.mLength);
2199 } else if (size.mWidth.mLength == 0 &&
2200 // negative values must have come from calc()
2201 size.mWidth.mPercent >= 0.0f) {
2202 valX->SetPercent(size.mWidth.mPercent);
2203 } else {
2204 SetValueToCalc(&size.mWidth, valX);
2208 if (size.mHeightType == nsStyleBackground::Size::eAuto) {
2209 valY->SetIdent(eCSSKeyword_auto);
2210 } else {
2211 NS_ABORT_IF_FALSE(size.mHeightType ==
2212 nsStyleBackground::Size::eLengthPercentage,
2213 "bad mHeightType");
2214 if (!size.mHeight.mHasPercent &&
2215 // negative values must have come from calc()
2216 size.mHeight.mLength >= 0) {
2217 NS_ABORT_IF_FALSE(size.mHeight.mPercent == 0.0f,
2218 "Shouldn't have mPercent");
2219 valY->SetAppUnits(size.mHeight.mLength);
2220 } else if (size.mHeight.mLength == 0 &&
2221 // negative values must have come from calc()
2222 size.mHeight.mPercent >= 0.0f) {
2223 valY->SetPercent(size.mHeight.mPercent);
2224 } else {
2225 SetValueToCalc(&size.mHeight, valY);
2228 break;
2233 return valueList;
2236 CSSValue*
2237 nsComputedDOMStyle::DoGetGridTemplateAreas()
2239 const css::GridTemplateAreasValue* areas =
2240 StylePosition()->mGridTemplateAreas;
2241 if (!areas) {
2242 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2243 val->SetIdent(eCSSKeyword_none);
2244 return val;
2247 MOZ_ASSERT(!areas->mTemplates.IsEmpty(),
2248 "Unexpected empty array in GridTemplateAreasValue");
2249 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
2250 for (uint32_t i = 0; i < areas->mTemplates.Length(); i++) {
2251 nsAutoString str;
2252 nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[i], str);
2253 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2254 val->SetString(str);
2255 valueList->AppendCSSValue(val);
2257 return valueList;
2260 // aLineNames must not be empty
2261 CSSValue*
2262 nsComputedDOMStyle::GetGridLineNames(const nsTArray<nsString>& aLineNames)
2264 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2265 nsAutoString lineNamesString;
2266 uint32_t i_end = aLineNames.Length();
2267 lineNamesString.Assign('(');
2268 if (i_end > 0) {
2269 for (uint32_t i = 0;;) {
2270 nsStyleUtil::AppendEscapedCSSIdent(aLineNames[i], lineNamesString);
2271 if (++i == i_end) {
2272 break;
2274 lineNamesString.Append(' ');
2277 lineNamesString.Append(')');
2278 val->SetString(lineNamesString);
2279 return val;
2282 CSSValue*
2283 nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue,
2284 const nsStyleCoord& aMaxValue)
2286 // FIXME bug 978212: for grid-template-columns and grid-template-rows
2287 // (not grid-auto-columns and grid-auto-rows), if we have frame,
2288 // every <track-size> should be resolved into 'px' here,
2289 // based on layout results.
2290 if (aMinValue == aMaxValue) {
2291 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2292 SetValueToCoord(val, aMinValue, true,
2293 nullptr, nsCSSProps::kGridTrackBreadthKTable);
2294 return val;
2297 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2298 nsAutoString argumentStr, minmaxStr;
2299 minmaxStr.AppendLiteral("minmax(");
2301 SetValueToCoord(val, aMinValue, true,
2302 nullptr, nsCSSProps::kGridTrackBreadthKTable);
2303 val->GetCssText(argumentStr);
2304 minmaxStr.Append(argumentStr);
2306 minmaxStr.AppendLiteral(", ");
2308 SetValueToCoord(val, aMaxValue, true,
2309 nullptr, nsCSSProps::kGridTrackBreadthKTable);
2310 val->GetCssText(argumentStr);
2311 minmaxStr.Append(argumentStr);
2313 minmaxStr.Append(char16_t(')'));
2314 val->SetString(minmaxStr);
2315 return val;
2318 CSSValue*
2319 nsComputedDOMStyle::GetGridTemplateColumnsRows(const nsStyleGridTemplate& aTrackList)
2321 if (aTrackList.mIsSubgrid) {
2322 NS_ASSERTION(aTrackList.mMinTrackSizingFunctions.IsEmpty() &&
2323 aTrackList.mMaxTrackSizingFunctions.IsEmpty(),
2324 "Unexpected sizing functions with subgrid");
2325 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
2327 nsROCSSPrimitiveValue* subgridKeyword = new nsROCSSPrimitiveValue;
2328 subgridKeyword->SetIdent(eCSSKeyword_subgrid);
2329 valueList->AppendCSSValue(subgridKeyword);
2331 for (uint32_t i = 0; i < aTrackList.mLineNameLists.Length(); i++) {
2332 valueList->AppendCSSValue(GetGridLineNames(aTrackList.mLineNameLists[i]));
2334 return valueList;
2337 uint32_t numSizes = aTrackList.mMinTrackSizingFunctions.Length();
2338 MOZ_ASSERT(aTrackList.mMaxTrackSizingFunctions.Length() == numSizes,
2339 "Different number of min and max track sizing functions");
2340 // An empty <track-list> is represented as "none" in syntax.
2341 if (numSizes == 0) {
2342 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2343 val->SetIdent(eCSSKeyword_none);
2344 return val;
2347 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
2348 // Delimiting N tracks requires N+1 lines:
2349 // one before each track, plus one at the very end.
2350 MOZ_ASSERT(aTrackList.mLineNameLists.Length() == numSizes + 1,
2351 "Unexpected number of line name lists");
2352 for (uint32_t i = 0;; i++) {
2353 const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[i];
2354 if (!lineNames.IsEmpty()) {
2355 valueList->AppendCSSValue(GetGridLineNames(lineNames));
2357 if (i == numSizes) {
2358 break;
2360 valueList->AppendCSSValue(GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i],
2361 aTrackList.mMaxTrackSizingFunctions[i]));
2364 return valueList;
2367 CSSValue*
2368 nsComputedDOMStyle::DoGetGridAutoFlow()
2370 nsAutoString str;
2371 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_grid_auto_flow,
2372 StylePosition()->mGridAutoFlow,
2373 NS_STYLE_GRID_AUTO_FLOW_ROW,
2374 NS_STYLE_GRID_AUTO_FLOW_DENSE,
2375 str);
2376 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2377 val->SetString(str);
2378 return val;
2381 CSSValue*
2382 nsComputedDOMStyle::DoGetGridAutoColumns()
2384 return GetGridTrackSize(StylePosition()->mGridAutoColumnsMin,
2385 StylePosition()->mGridAutoColumnsMax);
2388 CSSValue*
2389 nsComputedDOMStyle::DoGetGridAutoRows()
2391 return GetGridTrackSize(StylePosition()->mGridAutoRowsMin,
2392 StylePosition()->mGridAutoRowsMax);
2395 CSSValue*
2396 nsComputedDOMStyle::DoGetGridTemplateColumns()
2398 return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns);
2401 CSSValue*
2402 nsComputedDOMStyle::DoGetGridTemplateRows()
2404 return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows);
2407 CSSValue*
2408 nsComputedDOMStyle::GetGridLine(const nsStyleGridLine& aGridLine)
2410 if (aGridLine.IsAuto()) {
2411 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2412 val->SetIdent(eCSSKeyword_auto);
2413 return val;
2416 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
2418 if (aGridLine.mHasSpan) {
2419 nsROCSSPrimitiveValue* span = new nsROCSSPrimitiveValue;
2420 span->SetIdent(eCSSKeyword_span);
2421 valueList->AppendCSSValue(span);
2424 if (aGridLine.mInteger != 0) {
2425 nsROCSSPrimitiveValue* integer = new nsROCSSPrimitiveValue;
2426 integer->SetNumber(aGridLine.mInteger);
2427 valueList->AppendCSSValue(integer);
2430 if (!aGridLine.mLineName.IsEmpty()) {
2431 nsROCSSPrimitiveValue* lineName = new nsROCSSPrimitiveValue;
2432 nsString escapedLineName;
2433 nsStyleUtil::AppendEscapedCSSIdent(aGridLine.mLineName, escapedLineName);
2434 lineName->SetString(escapedLineName);
2435 valueList->AppendCSSValue(lineName);
2438 NS_ASSERTION(valueList->Length() > 0,
2439 "Should have appended at least one value");
2440 return valueList;
2443 CSSValue*
2444 nsComputedDOMStyle::DoGetGridColumnStart()
2446 return GetGridLine(StylePosition()->mGridColumnStart);
2449 CSSValue*
2450 nsComputedDOMStyle::DoGetGridColumnEnd()
2452 return GetGridLine(StylePosition()->mGridColumnEnd);
2455 CSSValue*
2456 nsComputedDOMStyle::DoGetGridRowStart()
2458 return GetGridLine(StylePosition()->mGridRowStart);
2461 CSSValue*
2462 nsComputedDOMStyle::DoGetGridRowEnd()
2464 return GetGridLine(StylePosition()->mGridRowEnd);
2467 CSSValue*
2468 nsComputedDOMStyle::DoGetPaddingTop()
2470 return GetPaddingWidthFor(NS_SIDE_TOP);
2473 CSSValue*
2474 nsComputedDOMStyle::DoGetPaddingBottom()
2476 return GetPaddingWidthFor(NS_SIDE_BOTTOM);
2479 CSSValue*
2480 nsComputedDOMStyle::DoGetPaddingLeft()
2482 return GetPaddingWidthFor(NS_SIDE_LEFT);
2485 CSSValue*
2486 nsComputedDOMStyle::DoGetPaddingRight()
2488 return GetPaddingWidthFor(NS_SIDE_RIGHT);
2491 CSSValue*
2492 nsComputedDOMStyle::DoGetBorderCollapse()
2494 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2495 val->SetIdent(
2496 nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mBorderCollapse,
2497 nsCSSProps::kBorderCollapseKTable));
2498 return val;
2501 CSSValue*
2502 nsComputedDOMStyle::DoGetBorderSpacing()
2504 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
2506 nsROCSSPrimitiveValue* xSpacing = new nsROCSSPrimitiveValue;
2507 valueList->AppendCSSValue(xSpacing);
2509 nsROCSSPrimitiveValue* ySpacing = new nsROCSSPrimitiveValue;
2510 valueList->AppendCSSValue(ySpacing);
2512 const nsStyleTableBorder *border = StyleTableBorder();
2513 xSpacing->SetAppUnits(border->mBorderSpacingX);
2514 ySpacing->SetAppUnits(border->mBorderSpacingY);
2516 return valueList;
2519 CSSValue*
2520 nsComputedDOMStyle::DoGetCaptionSide()
2522 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2523 val->SetIdent(
2524 nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mCaptionSide,
2525 nsCSSProps::kCaptionSideKTable));
2526 return val;
2529 CSSValue*
2530 nsComputedDOMStyle::DoGetEmptyCells()
2532 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2533 val->SetIdent(
2534 nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mEmptyCells,
2535 nsCSSProps::kEmptyCellsKTable));
2536 return val;
2539 CSSValue*
2540 nsComputedDOMStyle::DoGetTableLayout()
2542 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2543 val->SetIdent(
2544 nsCSSProps::ValueToKeywordEnum(StyleTable()->mLayoutStrategy,
2545 nsCSSProps::kTableLayoutKTable));
2546 return val;
2549 CSSValue*
2550 nsComputedDOMStyle::DoGetBorderTopStyle()
2552 return GetBorderStyleFor(NS_SIDE_TOP);
2555 CSSValue*
2556 nsComputedDOMStyle::DoGetBorderBottomStyle()
2558 return GetBorderStyleFor(NS_SIDE_BOTTOM);
2561 CSSValue*
2562 nsComputedDOMStyle::DoGetBorderLeftStyle()
2564 return GetBorderStyleFor(NS_SIDE_LEFT);
2567 CSSValue*
2568 nsComputedDOMStyle::DoGetBorderRightStyle()
2570 return GetBorderStyleFor(NS_SIDE_RIGHT);
2573 CSSValue*
2574 nsComputedDOMStyle::DoGetBorderBottomColors()
2576 return GetBorderColorsFor(NS_SIDE_BOTTOM);
2579 CSSValue*
2580 nsComputedDOMStyle::DoGetBorderLeftColors()
2582 return GetBorderColorsFor(NS_SIDE_LEFT);
2585 CSSValue*
2586 nsComputedDOMStyle::DoGetBorderRightColors()
2588 return GetBorderColorsFor(NS_SIDE_RIGHT);
2592 CSSValue*
2593 nsComputedDOMStyle::DoGetBorderTopColors()
2595 return GetBorderColorsFor(NS_SIDE_TOP);
2598 CSSValue*
2599 nsComputedDOMStyle::DoGetBorderBottomLeftRadius()
2601 return GetEllipseRadii(StyleBorder()->mBorderRadius,
2602 NS_CORNER_BOTTOM_LEFT, true);
2605 CSSValue*
2606 nsComputedDOMStyle::DoGetBorderBottomRightRadius()
2608 return GetEllipseRadii(StyleBorder()->mBorderRadius,
2609 NS_CORNER_BOTTOM_RIGHT, true);
2612 CSSValue*
2613 nsComputedDOMStyle::DoGetBorderTopLeftRadius()
2615 return GetEllipseRadii(StyleBorder()->mBorderRadius,
2616 NS_CORNER_TOP_LEFT, true);
2619 CSSValue*
2620 nsComputedDOMStyle::DoGetBorderTopRightRadius()
2622 return GetEllipseRadii(StyleBorder()->mBorderRadius,
2623 NS_CORNER_TOP_RIGHT, true);
2626 CSSValue*
2627 nsComputedDOMStyle::DoGetBorderTopWidth()
2629 return GetBorderWidthFor(NS_SIDE_TOP);
2632 CSSValue*
2633 nsComputedDOMStyle::DoGetBorderBottomWidth()
2635 return GetBorderWidthFor(NS_SIDE_BOTTOM);
2638 CSSValue*
2639 nsComputedDOMStyle::DoGetBorderLeftWidth()
2641 return GetBorderWidthFor(NS_SIDE_LEFT);
2644 CSSValue*
2645 nsComputedDOMStyle::DoGetBorderRightWidth()
2647 return GetBorderWidthFor(NS_SIDE_RIGHT);
2650 CSSValue*
2651 nsComputedDOMStyle::DoGetBorderTopColor()
2653 return GetBorderColorFor(NS_SIDE_TOP);
2656 CSSValue*
2657 nsComputedDOMStyle::DoGetBorderBottomColor()
2659 return GetBorderColorFor(NS_SIDE_BOTTOM);
2662 CSSValue*
2663 nsComputedDOMStyle::DoGetBorderLeftColor()
2665 return GetBorderColorFor(NS_SIDE_LEFT);
2668 CSSValue*
2669 nsComputedDOMStyle::DoGetBorderRightColor()
2671 return GetBorderColorFor(NS_SIDE_RIGHT);
2674 CSSValue*
2675 nsComputedDOMStyle::DoGetMarginTopWidth()
2677 return GetMarginWidthFor(NS_SIDE_TOP);
2680 CSSValue*
2681 nsComputedDOMStyle::DoGetMarginBottomWidth()
2683 return GetMarginWidthFor(NS_SIDE_BOTTOM);
2686 CSSValue*
2687 nsComputedDOMStyle::DoGetMarginLeftWidth()
2689 return GetMarginWidthFor(NS_SIDE_LEFT);
2692 CSSValue*
2693 nsComputedDOMStyle::DoGetMarginRightWidth()
2695 return GetMarginWidthFor(NS_SIDE_RIGHT);
2698 CSSValue*
2699 nsComputedDOMStyle::DoGetMarkerOffset()
2701 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2702 SetValueToCoord(val, StyleContent()->mMarkerOffset, false);
2703 return val;
2706 CSSValue*
2707 nsComputedDOMStyle::DoGetOrient()
2709 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2710 val->SetIdent(
2711 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOrient,
2712 nsCSSProps::kOrientKTable));
2713 return val;
2716 CSSValue*
2717 nsComputedDOMStyle::DoGetScrollBehavior()
2719 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2720 val->SetIdent(
2721 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollBehavior,
2722 nsCSSProps::kScrollBehaviorKTable));
2723 return val;
2726 CSSValue*
2727 nsComputedDOMStyle::DoGetOutlineWidth()
2729 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2731 const nsStyleOutline* outline = StyleOutline();
2733 nscoord width;
2734 if (outline->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) {
2735 NS_ASSERTION(outline->GetOutlineWidth(width) && width == 0,
2736 "unexpected width");
2737 width = 0;
2738 } else {
2739 #ifdef DEBUG
2740 bool res =
2741 #endif
2742 outline->GetOutlineWidth(width);
2743 NS_ASSERTION(res, "percent outline doesn't exist");
2745 val->SetAppUnits(width);
2747 return val;
2750 CSSValue*
2751 nsComputedDOMStyle::DoGetOutlineStyle()
2753 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2754 val->SetIdent(
2755 nsCSSProps::ValueToKeywordEnum(StyleOutline()->GetOutlineStyle(),
2756 nsCSSProps::kOutlineStyleKTable));
2757 return val;
2760 CSSValue*
2761 nsComputedDOMStyle::DoGetOutlineOffset()
2763 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2764 val->SetAppUnits(StyleOutline()->mOutlineOffset);
2765 return val;
2768 CSSValue*
2769 nsComputedDOMStyle::DoGetOutlineRadiusBottomLeft()
2771 return GetEllipseRadii(StyleOutline()->mOutlineRadius,
2772 NS_CORNER_BOTTOM_LEFT, false);
2775 CSSValue*
2776 nsComputedDOMStyle::DoGetOutlineRadiusBottomRight()
2778 return GetEllipseRadii(StyleOutline()->mOutlineRadius,
2779 NS_CORNER_BOTTOM_RIGHT, false);
2782 CSSValue*
2783 nsComputedDOMStyle::DoGetOutlineRadiusTopLeft()
2785 return GetEllipseRadii(StyleOutline()->mOutlineRadius,
2786 NS_CORNER_TOP_LEFT, false);
2789 CSSValue*
2790 nsComputedDOMStyle::DoGetOutlineRadiusTopRight()
2792 return GetEllipseRadii(StyleOutline()->mOutlineRadius,
2793 NS_CORNER_TOP_RIGHT, false);
2796 CSSValue*
2797 nsComputedDOMStyle::DoGetOutlineColor()
2799 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2801 nscolor color;
2802 if (!StyleOutline()->GetOutlineColor(color))
2803 color = StyleColor()->mColor;
2805 SetToRGBAColor(val, color);
2806 return val;
2809 CSSValue*
2810 nsComputedDOMStyle::GetEllipseRadii(const nsStyleCorners& aRadius,
2811 uint8_t aFullCorner,
2812 bool aIsBorder) // else outline
2814 nsStyleCoord radiusX, radiusY;
2815 if (mInnerFrame && aIsBorder) {
2816 nscoord radii[8];
2817 mInnerFrame->GetBorderRadii(radii);
2818 radiusX.SetCoordValue(radii[NS_FULL_TO_HALF_CORNER(aFullCorner, false)]);
2819 radiusY.SetCoordValue(radii[NS_FULL_TO_HALF_CORNER(aFullCorner, true)]);
2820 } else {
2821 radiusX = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, false));
2822 radiusY = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, true));
2824 if (mInnerFrame) {
2825 // We need to convert to absolute coordinates before doing the
2826 // equality check below.
2827 nscoord v;
2829 v = StyleCoordToNSCoord(radiusX,
2830 &nsComputedDOMStyle::GetFrameBorderRectWidth,
2831 0, true);
2832 radiusX.SetCoordValue(v);
2834 v = StyleCoordToNSCoord(radiusY,
2835 &nsComputedDOMStyle::GetFrameBorderRectHeight,
2836 0, true);
2837 radiusY.SetCoordValue(v);
2841 // for compatibility, return a single value if X and Y are equal
2842 if (radiusX == radiusY) {
2843 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2845 SetValueToCoord(val, radiusX, true);
2847 return val;
2850 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
2852 nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue;
2853 valueList->AppendCSSValue(valX);
2855 nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue;
2856 valueList->AppendCSSValue(valY);
2858 SetValueToCoord(valX, radiusX, true);
2859 SetValueToCoord(valY, radiusY, true);
2861 return valueList;
2864 CSSValue*
2865 nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray,
2866 const nscolor& aDefaultColor,
2867 bool aIsBoxShadow)
2869 if (!aArray) {
2870 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2871 val->SetIdent(eCSSKeyword_none);
2872 return val;
2875 static nscoord nsCSSShadowItem::* const shadowValuesNoSpread[] = {
2876 &nsCSSShadowItem::mXOffset,
2877 &nsCSSShadowItem::mYOffset,
2878 &nsCSSShadowItem::mRadius
2881 static nscoord nsCSSShadowItem::* const shadowValuesWithSpread[] = {
2882 &nsCSSShadowItem::mXOffset,
2883 &nsCSSShadowItem::mYOffset,
2884 &nsCSSShadowItem::mRadius,
2885 &nsCSSShadowItem::mSpread
2888 nscoord nsCSSShadowItem::* const * shadowValues;
2889 uint32_t shadowValuesLength;
2890 if (aIsBoxShadow) {
2891 shadowValues = shadowValuesWithSpread;
2892 shadowValuesLength = ArrayLength(shadowValuesWithSpread);
2893 } else {
2894 shadowValues = shadowValuesNoSpread;
2895 shadowValuesLength = ArrayLength(shadowValuesNoSpread);
2898 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
2900 for (nsCSSShadowItem *item = aArray->ShadowAt(0),
2901 *item_end = item + aArray->Length();
2902 item < item_end; ++item) {
2903 nsDOMCSSValueList *itemList = GetROCSSValueList(false);
2904 valueList->AppendCSSValue(itemList);
2906 // Color is either the specified shadow color or the foreground color
2907 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2908 itemList->AppendCSSValue(val);
2909 nscolor shadowColor;
2910 if (item->mHasColor) {
2911 shadowColor = item->mColor;
2912 } else {
2913 shadowColor = aDefaultColor;
2915 SetToRGBAColor(val, shadowColor);
2917 // Set the offsets, blur radius, and spread if available
2918 for (uint32_t i = 0; i < shadowValuesLength; ++i) {
2919 val = new nsROCSSPrimitiveValue;
2920 itemList->AppendCSSValue(val);
2921 val->SetAppUnits(item->*(shadowValues[i]));
2924 if (item->mInset && aIsBoxShadow) {
2925 // This is an inset box-shadow
2926 val = new nsROCSSPrimitiveValue;
2927 itemList->AppendCSSValue(val);
2928 val->SetIdent(
2929 nsCSSProps::ValueToKeywordEnum(NS_STYLE_BOX_SHADOW_INSET,
2930 nsCSSProps::kBoxShadowTypeKTable));
2934 return valueList;
2937 CSSValue*
2938 nsComputedDOMStyle::DoGetBoxDecorationBreak()
2940 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2941 val->SetIdent(
2942 nsCSSProps::ValueToKeywordEnum(StyleBorder()->mBoxDecorationBreak,
2943 nsCSSProps::kBoxDecorationBreakKTable));
2944 return val;
2947 CSSValue*
2948 nsComputedDOMStyle::DoGetBoxShadow()
2950 return GetCSSShadowArray(StyleBorder()->mBoxShadow,
2951 StyleColor()->mColor,
2952 true);
2955 CSSValue*
2956 nsComputedDOMStyle::DoGetZIndex()
2958 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2959 SetValueToCoord(val, StylePosition()->mZIndex, false);
2960 return val;
2963 CSSValue*
2964 nsComputedDOMStyle::DoGetListStyleImage()
2966 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
2968 const nsStyleList* list = StyleList();
2970 if (!list->GetListStyleImage()) {
2971 val->SetIdent(eCSSKeyword_none);
2972 } else {
2973 nsCOMPtr<nsIURI> uri;
2974 if (list->GetListStyleImage()) {
2975 list->GetListStyleImage()->GetURI(getter_AddRefs(uri));
2977 val->SetURI(uri);
2980 return val;
2983 CSSValue*
2984 nsComputedDOMStyle::DoGetListStylePosition()
2986 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2987 val->SetIdent(
2988 nsCSSProps::ValueToKeywordEnum(StyleList()->mListStylePosition,
2989 nsCSSProps::kListStylePositionKTable));
2990 return val;
2993 CSSValue*
2994 nsComputedDOMStyle::DoGetListStyleType()
2996 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
2997 CounterStyle* style = StyleList()->GetCounterStyle();
2998 AnonymousCounterStyle* anonymous = style->AsAnonymous();
2999 if (!anonymous) {
3000 // want SetIdent
3001 nsString type;
3002 StyleList()->GetListStyleType(type);
3003 nsString value;
3004 nsStyleUtil::AppendEscapedCSSIdent(type, value);
3005 val->SetString(value);
3006 } else {
3007 nsAutoString tmp;
3008 tmp.AppendLiteral("symbols(");
3010 uint8_t system = anonymous->GetSystem();
3011 NS_ASSERTION(system == NS_STYLE_COUNTER_SYSTEM_CYCLIC ||
3012 system == NS_STYLE_COUNTER_SYSTEM_NUMERIC ||
3013 system == NS_STYLE_COUNTER_SYSTEM_ALPHABETIC ||
3014 system == NS_STYLE_COUNTER_SYSTEM_SYMBOLIC ||
3015 system == NS_STYLE_COUNTER_SYSTEM_FIXED,
3016 "Invalid system for anonymous counter style.");
3017 if (system != NS_STYLE_COUNTER_SYSTEM_SYMBOLIC) {
3018 AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(
3019 system, nsCSSProps::kCounterSystemKTable), tmp);
3020 tmp.Append(' ');
3023 const nsTArray<nsString>& symbols = anonymous->GetSymbols();
3024 NS_ASSERTION(symbols.Length() > 0,
3025 "No symbols in the anonymous counter style");
3026 for (size_t i = 0, iend = symbols.Length(); i < iend; i++) {
3027 nsStyleUtil::AppendEscapedCSSString(symbols[i], tmp);
3028 tmp.Append(' ');
3030 tmp.Replace(tmp.Length() - 1, 1, char16_t(')'));
3031 val->SetString(tmp);
3033 return val;
3036 CSSValue*
3037 nsComputedDOMStyle::DoGetImageRegion()
3039 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3041 const nsStyleList* list = StyleList();
3043 if (list->mImageRegion.width <= 0 || list->mImageRegion.height <= 0) {
3044 val->SetIdent(eCSSKeyword_auto);
3045 } else {
3046 // create the cssvalues for the sides, stick them in the rect object
3047 nsROCSSPrimitiveValue *topVal = new nsROCSSPrimitiveValue;
3048 nsROCSSPrimitiveValue *rightVal = new nsROCSSPrimitiveValue;
3049 nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue;
3050 nsROCSSPrimitiveValue *leftVal = new nsROCSSPrimitiveValue;
3051 nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
3052 bottomVal, leftVal);
3053 topVal->SetAppUnits(list->mImageRegion.y);
3054 rightVal->SetAppUnits(list->mImageRegion.width + list->mImageRegion.x);
3055 bottomVal->SetAppUnits(list->mImageRegion.height + list->mImageRegion.y);
3056 leftVal->SetAppUnits(list->mImageRegion.x);
3057 val->SetRect(domRect);
3060 return val;
3063 CSSValue*
3064 nsComputedDOMStyle::DoGetLineHeight()
3066 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3068 nscoord lineHeight;
3069 if (GetLineHeightCoord(lineHeight)) {
3070 val->SetAppUnits(lineHeight);
3071 } else {
3072 SetValueToCoord(val, StyleText()->mLineHeight, true,
3073 nullptr, nsCSSProps::kLineHeightKTable);
3076 return val;
3079 CSSValue*
3080 nsComputedDOMStyle::DoGetRubyPosition()
3082 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3083 int32_t intValue = StyleText()->mRubyPosition;
3084 nsAutoString valueStr;
3085 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_ruby_position,
3086 intValue,
3087 NS_STYLE_RUBY_POSITION_OVER,
3088 NS_STYLE_RUBY_POSITION_LEFT, valueStr);
3089 val->SetString(valueStr);
3090 return val;
3093 CSSValue*
3094 nsComputedDOMStyle::DoGetVerticalAlign()
3096 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3097 SetValueToCoord(val, StyleTextReset()->mVerticalAlign, false,
3098 &nsComputedDOMStyle::GetLineHeightCoord,
3099 nsCSSProps::kVerticalAlignKTable);
3100 return val;
3103 CSSValue*
3104 nsComputedDOMStyle::CreateTextAlignValue(uint8_t aAlign, bool aAlignTrue,
3105 const KTableValue aTable[])
3107 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3108 val->SetIdent(nsCSSProps::ValueToKeywordEnum(aAlign, aTable));
3109 if (!aAlignTrue) {
3110 return val;
3113 nsROCSSPrimitiveValue* first = new nsROCSSPrimitiveValue;
3114 first->SetIdent(eCSSKeyword_true);
3116 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
3117 valueList->AppendCSSValue(first);
3118 valueList->AppendCSSValue(val);
3119 return valueList;
3122 CSSValue*
3123 nsComputedDOMStyle::DoGetTextAlign()
3125 const nsStyleText* style = StyleText();
3126 return CreateTextAlignValue(style->mTextAlign, style->mTextAlignTrue,
3127 nsCSSProps::kTextAlignKTable);
3130 CSSValue*
3131 nsComputedDOMStyle::DoGetTextAlignLast()
3133 const nsStyleText* style = StyleText();
3134 return CreateTextAlignValue(style->mTextAlignLast, style->mTextAlignLastTrue,
3135 nsCSSProps::kTextAlignLastKTable);
3138 CSSValue*
3139 nsComputedDOMStyle::DoGetTextCombineUpright()
3141 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3142 uint8_t tch = StyleText()->mTextCombineUpright;
3144 if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
3145 val->SetIdent(
3146 nsCSSProps::ValueToKeywordEnum(tch,
3147 nsCSSProps::kTextCombineUprightKTable));
3148 } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2) {
3149 val->SetString(NS_LITERAL_STRING("digits 2"));
3150 } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3) {
3151 val->SetString(NS_LITERAL_STRING("digits 3"));
3152 } else {
3153 val->SetString(NS_LITERAL_STRING("digits 4"));
3156 return val;
3159 CSSValue*
3160 nsComputedDOMStyle::DoGetTextDecoration()
3162 const nsStyleTextReset* textReset = StyleTextReset();
3164 bool isInitialStyle =
3165 textReset->GetDecorationStyle() == NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
3166 nscolor color;
3167 bool isForegroundColor;
3168 textReset->GetDecorationColor(color, isForegroundColor);
3170 if (isInitialStyle && isForegroundColor) {
3171 return DoGetTextDecorationLine();
3174 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
3176 valueList->AppendCSSValue(DoGetTextDecorationLine());
3177 if (!isInitialStyle) {
3178 valueList->AppendCSSValue(DoGetTextDecorationStyle());
3180 if (!isForegroundColor) {
3181 valueList->AppendCSSValue(DoGetTextDecorationColor());
3184 return valueList;
3187 CSSValue*
3188 nsComputedDOMStyle::DoGetTextDecorationColor()
3190 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3192 nscolor color;
3193 bool isForeground;
3194 StyleTextReset()->GetDecorationColor(color, isForeground);
3195 if (isForeground) {
3196 color = StyleColor()->mColor;
3199 SetToRGBAColor(val, color);
3201 return val;
3204 CSSValue*
3205 nsComputedDOMStyle::DoGetTextDecorationLine()
3207 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3209 int32_t intValue = StyleTextReset()->mTextDecorationLine;
3211 if (NS_STYLE_TEXT_DECORATION_LINE_NONE == intValue) {
3212 val->SetIdent(eCSSKeyword_none);
3213 } else {
3214 nsAutoString decorationLineString;
3215 // Clear the -moz-anchor-decoration bit and the OVERRIDE_ALL bits -- we
3216 // don't want these to appear in the computed style.
3217 intValue &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS |
3218 NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL);
3219 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
3220 intValue, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
3221 NS_STYLE_TEXT_DECORATION_LINE_BLINK, decorationLineString);
3222 val->SetString(decorationLineString);
3225 return val;
3228 CSSValue*
3229 nsComputedDOMStyle::DoGetTextDecorationStyle()
3231 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3233 val->SetIdent(
3234 nsCSSProps::ValueToKeywordEnum(StyleTextReset()->GetDecorationStyle(),
3235 nsCSSProps::kTextDecorationStyleKTable));
3237 return val;
3240 CSSValue*
3241 nsComputedDOMStyle::DoGetTextIndent()
3243 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3244 SetValueToCoord(val, StyleText()->mTextIndent, false,
3245 &nsComputedDOMStyle::GetCBContentWidth);
3246 return val;
3249 CSSValue*
3250 nsComputedDOMStyle::DoGetTextOrientation()
3252 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3253 val->SetIdent(
3254 nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mTextOrientation,
3255 nsCSSProps::kTextOrientationKTable));
3256 return val;
3259 CSSValue*
3260 nsComputedDOMStyle::DoGetTextOverflow()
3262 const nsStyleTextReset *style = StyleTextReset();
3263 nsROCSSPrimitiveValue *first = new nsROCSSPrimitiveValue;
3264 const nsStyleTextOverflowSide *side = style->mTextOverflow.GetFirstValue();
3265 if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
3266 nsString str;
3267 nsStyleUtil::AppendEscapedCSSString(side->mString, str);
3268 first->SetString(str);
3269 } else {
3270 first->SetIdent(
3271 nsCSSProps::ValueToKeywordEnum(side->mType,
3272 nsCSSProps::kTextOverflowKTable));
3274 side = style->mTextOverflow.GetSecondValue();
3275 if (!side) {
3276 return first;
3278 nsROCSSPrimitiveValue *second = new nsROCSSPrimitiveValue;
3279 if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
3280 nsString str;
3281 nsStyleUtil::AppendEscapedCSSString(side->mString, str);
3282 second->SetString(str);
3283 } else {
3284 second->SetIdent(
3285 nsCSSProps::ValueToKeywordEnum(side->mType,
3286 nsCSSProps::kTextOverflowKTable));
3289 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
3290 valueList->AppendCSSValue(first);
3291 valueList->AppendCSSValue(second);
3292 return valueList;
3295 CSSValue*
3296 nsComputedDOMStyle::DoGetTextShadow()
3298 return GetCSSShadowArray(StyleText()->mTextShadow,
3299 StyleColor()->mColor,
3300 false);
3303 CSSValue*
3304 nsComputedDOMStyle::DoGetTextTransform()
3306 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3307 val->SetIdent(
3308 nsCSSProps::ValueToKeywordEnum(StyleText()->mTextTransform,
3309 nsCSSProps::kTextTransformKTable));
3310 return val;
3313 CSSValue*
3314 nsComputedDOMStyle::DoGetTabSize()
3316 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3317 val->SetNumber(StyleText()->mTabSize);
3318 return val;
3321 CSSValue*
3322 nsComputedDOMStyle::DoGetLetterSpacing()
3324 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3325 SetValueToCoord(val, StyleText()->mLetterSpacing, false);
3326 return val;
3329 CSSValue*
3330 nsComputedDOMStyle::DoGetWordSpacing()
3332 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3333 val->SetAppUnits(StyleText()->mWordSpacing);
3334 return val;
3337 CSSValue*
3338 nsComputedDOMStyle::DoGetWhiteSpace()
3340 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3341 val->SetIdent(
3342 nsCSSProps::ValueToKeywordEnum(StyleText()->mWhiteSpace,
3343 nsCSSProps::kWhitespaceKTable));
3344 return val;
3347 CSSValue*
3348 nsComputedDOMStyle::DoGetWindowDragging()
3350 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3351 val->SetIdent(
3352 nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mWindowDragging,
3353 nsCSSProps::kWindowDraggingKTable));
3354 return val;
3357 CSSValue*
3358 nsComputedDOMStyle::DoGetWindowShadow()
3360 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3361 val->SetIdent(
3362 nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mWindowShadow,
3363 nsCSSProps::kWindowShadowKTable));
3364 return val;
3367 CSSValue*
3368 nsComputedDOMStyle::DoGetWordBreak()
3370 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3371 val->SetIdent(
3372 nsCSSProps::ValueToKeywordEnum(StyleText()->mWordBreak,
3373 nsCSSProps::kWordBreakKTable));
3374 return val;
3377 CSSValue*
3378 nsComputedDOMStyle::DoGetWordWrap()
3380 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3381 val->SetIdent(
3382 nsCSSProps::ValueToKeywordEnum(StyleText()->mWordWrap,
3383 nsCSSProps::kWordWrapKTable));
3384 return val;
3387 CSSValue*
3388 nsComputedDOMStyle::DoGetHyphens()
3390 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3391 val->SetIdent(
3392 nsCSSProps::ValueToKeywordEnum(StyleText()->mHyphens,
3393 nsCSSProps::kHyphensKTable));
3394 return val;
3397 CSSValue*
3398 nsComputedDOMStyle::DoGetTextSizeAdjust()
3400 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3401 switch (StyleText()->mTextSizeAdjust) {
3402 default:
3403 NS_NOTREACHED("unexpected value");
3404 // fall through
3405 case NS_STYLE_TEXT_SIZE_ADJUST_AUTO:
3406 val->SetIdent(eCSSKeyword_auto);
3407 break;
3408 case NS_STYLE_TEXT_SIZE_ADJUST_NONE:
3409 val->SetIdent(eCSSKeyword_none);
3410 break;
3412 return val;
3415 CSSValue*
3416 nsComputedDOMStyle::DoGetPointerEvents()
3418 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3419 val->SetIdent(
3420 nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mPointerEvents,
3421 nsCSSProps::kPointerEventsKTable));
3422 return val;
3425 CSSValue*
3426 nsComputedDOMStyle::DoGetVisibility()
3428 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3429 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mVisible,
3430 nsCSSProps::kVisibilityKTable));
3431 return val;
3434 CSSValue*
3435 nsComputedDOMStyle::DoGetWritingMode()
3437 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3438 val->SetIdent(
3439 nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mWritingMode,
3440 nsCSSProps::kWritingModeKTable));
3441 return val;
3444 CSSValue*
3445 nsComputedDOMStyle::DoGetDirection()
3447 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3448 val->SetIdent(
3449 nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mDirection,
3450 nsCSSProps::kDirectionKTable));
3451 return val;
3454 static_assert(NS_STYLE_UNICODE_BIDI_NORMAL == 0,
3455 "unicode-bidi style constants not as expected");
3457 CSSValue*
3458 nsComputedDOMStyle::DoGetUnicodeBidi()
3460 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3461 val->SetIdent(
3462 nsCSSProps::ValueToKeywordEnum(StyleTextReset()->mUnicodeBidi,
3463 nsCSSProps::kUnicodeBidiKTable));
3464 return val;
3467 CSSValue*
3468 nsComputedDOMStyle::DoGetCursor()
3470 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
3472 const nsStyleUserInterface *ui = StyleUserInterface();
3474 for (nsCursorImage *item = ui->mCursorArray,
3475 *item_end = ui->mCursorArray + ui->mCursorArrayLength;
3476 item < item_end; ++item) {
3477 nsDOMCSSValueList *itemList = GetROCSSValueList(false);
3478 valueList->AppendCSSValue(itemList);
3480 nsCOMPtr<nsIURI> uri;
3481 item->GetImage()->GetURI(getter_AddRefs(uri));
3483 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3484 itemList->AppendCSSValue(val);
3485 val->SetURI(uri);
3487 if (item->mHaveHotspot) {
3488 nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue;
3489 itemList->AppendCSSValue(valX);
3490 nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue;
3491 itemList->AppendCSSValue(valY);
3493 valX->SetNumber(item->mHotspotX);
3494 valY->SetNumber(item->mHotspotY);
3498 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3499 val->SetIdent(nsCSSProps::ValueToKeywordEnum(ui->mCursor,
3500 nsCSSProps::kCursorKTable));
3501 valueList->AppendCSSValue(val);
3502 return valueList;
3505 CSSValue*
3506 nsComputedDOMStyle::DoGetAppearance()
3508 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3509 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mAppearance,
3510 nsCSSProps::kAppearanceKTable));
3511 return val;
3515 CSSValue*
3516 nsComputedDOMStyle::DoGetBoxAlign()
3518 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3519 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxAlign,
3520 nsCSSProps::kBoxAlignKTable));
3521 return val;
3524 CSSValue*
3525 nsComputedDOMStyle::DoGetBoxDirection()
3527 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3528 val->SetIdent(
3529 nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxDirection,
3530 nsCSSProps::kBoxDirectionKTable));
3531 return val;
3534 CSSValue*
3535 nsComputedDOMStyle::DoGetBoxFlex()
3537 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3538 val->SetNumber(StyleXUL()->mBoxFlex);
3539 return val;
3542 CSSValue*
3543 nsComputedDOMStyle::DoGetBoxOrdinalGroup()
3545 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3546 val->SetNumber(StyleXUL()->mBoxOrdinal);
3547 return val;
3550 CSSValue*
3551 nsComputedDOMStyle::DoGetBoxOrient()
3553 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3554 val->SetIdent(
3555 nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxOrient,
3556 nsCSSProps::kBoxOrientKTable));
3557 return val;
3560 CSSValue*
3561 nsComputedDOMStyle::DoGetBoxPack()
3563 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3564 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxPack,
3565 nsCSSProps::kBoxPackKTable));
3566 return val;
3569 CSSValue*
3570 nsComputedDOMStyle::DoGetBoxSizing()
3572 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3573 val->SetIdent(
3574 nsCSSProps::ValueToKeywordEnum(StylePosition()->mBoxSizing,
3575 nsCSSProps::kBoxSizingKTable));
3576 return val;
3579 /* Border image properties */
3581 CSSValue*
3582 nsComputedDOMStyle::DoGetBorderImageSource()
3584 const nsStyleBorder* border = StyleBorder();
3586 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3587 const nsStyleImage& image = border->mBorderImageSource;
3588 SetValueToStyleImage(image, val);
3590 return val;
3593 CSSValue*
3594 nsComputedDOMStyle::DoGetBorderImageSlice()
3596 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
3598 const nsStyleBorder* border = StyleBorder();
3599 // Four slice numbers.
3600 NS_FOR_CSS_SIDES (side) {
3601 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3602 valueList->AppendCSSValue(val);
3603 SetValueToCoord(val, border->mBorderImageSlice.Get(side), true, nullptr);
3606 // Fill keyword.
3607 if (NS_STYLE_BORDER_IMAGE_SLICE_FILL == border->mBorderImageFill) {
3608 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3609 valueList->AppendCSSValue(val);
3610 val->SetIdent(eCSSKeyword_fill);
3613 return valueList;
3616 CSSValue*
3617 nsComputedDOMStyle::DoGetBorderImageWidth()
3619 const nsStyleBorder* border = StyleBorder();
3620 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
3621 NS_FOR_CSS_SIDES (side) {
3622 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3623 valueList->AppendCSSValue(val);
3624 SetValueToCoord(val, border->mBorderImageWidth.Get(side),
3625 true, nullptr);
3628 return valueList;
3631 CSSValue*
3632 nsComputedDOMStyle::DoGetBorderImageOutset()
3634 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
3636 const nsStyleBorder* border = StyleBorder();
3637 // four slice numbers
3638 NS_FOR_CSS_SIDES (side) {
3639 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3640 valueList->AppendCSSValue(val);
3641 SetValueToCoord(val, border->mBorderImageOutset.Get(side),
3642 true, nullptr);
3645 return valueList;
3648 CSSValue*
3649 nsComputedDOMStyle::DoGetBorderImageRepeat()
3651 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
3653 const nsStyleBorder* border = StyleBorder();
3655 // horizontal repeat
3656 nsROCSSPrimitiveValue* valX = new nsROCSSPrimitiveValue;
3657 valueList->AppendCSSValue(valX);
3658 valX->SetIdent(
3659 nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatH,
3660 nsCSSProps::kBorderImageRepeatKTable));
3662 // vertical repeat
3663 nsROCSSPrimitiveValue* valY = new nsROCSSPrimitiveValue;
3664 valueList->AppendCSSValue(valY);
3665 valY->SetIdent(
3666 nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatV,
3667 nsCSSProps::kBorderImageRepeatKTable));
3668 return valueList;
3671 CSSValue*
3672 nsComputedDOMStyle::DoGetAlignContent()
3674 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3675 val->SetIdent(
3676 nsCSSProps::ValueToKeywordEnum(StylePosition()->mAlignContent,
3677 nsCSSProps::kAlignContentKTable));
3678 return val;
3681 CSSValue*
3682 nsComputedDOMStyle::DoGetAlignItems()
3684 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3685 val->SetIdent(
3686 nsCSSProps::ValueToKeywordEnum(StylePosition()->mAlignItems,
3687 nsCSSProps::kAlignItemsKTable));
3688 return val;
3691 CSSValue*
3692 nsComputedDOMStyle::DoGetAlignSelf()
3694 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3695 uint8_t computedAlignSelf = StylePosition()->mAlignSelf;
3697 if (computedAlignSelf == NS_STYLE_ALIGN_SELF_AUTO) {
3698 // "align-self: auto" needs to compute to parent's align-items value.
3699 nsStyleContext* parentStyleContext = mStyleContextHolder->GetParent();
3700 if (parentStyleContext) {
3701 computedAlignSelf =
3702 parentStyleContext->StylePosition()->mAlignItems;
3703 } else {
3704 // No parent --> use default.
3705 computedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
3709 NS_ABORT_IF_FALSE(computedAlignSelf != NS_STYLE_ALIGN_SELF_AUTO,
3710 "Should have swapped out 'auto' for something non-auto");
3711 val->SetIdent(
3712 nsCSSProps::ValueToKeywordEnum(computedAlignSelf,
3713 nsCSSProps::kAlignSelfKTable));
3714 return val;
3717 CSSValue*
3718 nsComputedDOMStyle::DoGetFlexBasis()
3720 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3722 // XXXdholbert We could make this more automagic and resolve percentages
3723 // if we wanted, by passing in a PercentageBaseGetter instead of nullptr
3724 // below. Logic would go like this:
3725 // if (i'm a flex item) {
3726 // if (my flex container is horizontal) {
3727 // percentageBaseGetter = &nsComputedDOMStyle::GetCBContentWidth;
3728 // } else {
3729 // percentageBaseGetter = &nsComputedDOMStyle::GetCBContentHeight;
3730 // }
3731 // }
3733 SetValueToCoord(val, StylePosition()->mFlexBasis, true,
3734 nullptr, nsCSSProps::kWidthKTable);
3735 return val;
3738 CSSValue*
3739 nsComputedDOMStyle::DoGetFlexDirection()
3741 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3742 val->SetIdent(
3743 nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexDirection,
3744 nsCSSProps::kFlexDirectionKTable));
3745 return val;
3748 CSSValue*
3749 nsComputedDOMStyle::DoGetFlexGrow()
3751 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3752 val->SetNumber(StylePosition()->mFlexGrow);
3753 return val;
3756 CSSValue*
3757 nsComputedDOMStyle::DoGetFlexShrink()
3759 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3760 val->SetNumber(StylePosition()->mFlexShrink);
3761 return val;
3764 CSSValue*
3765 nsComputedDOMStyle::DoGetFlexWrap()
3767 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3768 val->SetIdent(
3769 nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexWrap,
3770 nsCSSProps::kFlexWrapKTable));
3771 return val;
3774 CSSValue*
3775 nsComputedDOMStyle::DoGetOrder()
3777 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3778 val->SetNumber(StylePosition()->mOrder);
3779 return val;
3782 CSSValue*
3783 nsComputedDOMStyle::DoGetJustifyContent()
3785 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3786 val->SetIdent(
3787 nsCSSProps::ValueToKeywordEnum(StylePosition()->mJustifyContent,
3788 nsCSSProps::kJustifyContentKTable));
3789 return val;
3792 CSSValue*
3793 nsComputedDOMStyle::DoGetFloatEdge()
3795 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3796 val->SetIdent(
3797 nsCSSProps::ValueToKeywordEnum(StyleBorder()->mFloatEdge,
3798 nsCSSProps::kFloatEdgeKTable));
3799 return val;
3802 CSSValue*
3803 nsComputedDOMStyle::DoGetForceBrokenImageIcon()
3805 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3806 val->SetNumber(StyleUIReset()->mForceBrokenImageIcon);
3807 return val;
3810 CSSValue*
3811 nsComputedDOMStyle::DoGetImageOrientation()
3813 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3814 nsAutoString string;
3815 nsStyleImageOrientation orientation = StyleVisibility()->mImageOrientation;
3817 if (orientation.IsFromImage()) {
3818 string.AppendLiteral("from-image");
3819 } else {
3820 nsStyleUtil::AppendAngleValue(orientation.AngleAsCoord(), string);
3822 if (orientation.IsFlipped()) {
3823 string.AppendLiteral(" flip");
3827 val->SetString(string);
3828 return val;
3831 CSSValue*
3832 nsComputedDOMStyle::DoGetIMEMode()
3834 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3835 val->SetIdent(
3836 nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mIMEMode,
3837 nsCSSProps::kIMEModeKTable));
3838 return val;
3841 CSSValue*
3842 nsComputedDOMStyle::DoGetUserFocus()
3844 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3845 val->SetIdent(
3846 nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserFocus,
3847 nsCSSProps::kUserFocusKTable));
3848 return val;
3851 CSSValue*
3852 nsComputedDOMStyle::DoGetUserInput()
3854 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3855 val->SetIdent(
3856 nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserInput,
3857 nsCSSProps::kUserInputKTable));
3858 return val;
3861 CSSValue*
3862 nsComputedDOMStyle::DoGetUserModify()
3864 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3865 val->SetIdent(
3866 nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserModify,
3867 nsCSSProps::kUserModifyKTable));
3868 return val;
3871 CSSValue*
3872 nsComputedDOMStyle::DoGetUserSelect()
3874 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3875 val->SetIdent(
3876 nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mUserSelect,
3877 nsCSSProps::kUserSelectKTable));
3878 return val;
3881 CSSValue*
3882 nsComputedDOMStyle::DoGetDisplay()
3884 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3885 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mDisplay,
3886 nsCSSProps::kDisplayKTable));
3887 return val;
3890 CSSValue*
3891 nsComputedDOMStyle::DoGetPosition()
3893 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3894 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mPosition,
3895 nsCSSProps::kPositionKTable));
3896 return val;
3899 CSSValue*
3900 nsComputedDOMStyle::DoGetClip()
3902 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3904 const nsStyleDisplay* display = StyleDisplay();
3906 if (display->mClipFlags == NS_STYLE_CLIP_AUTO) {
3907 val->SetIdent(eCSSKeyword_auto);
3908 } else {
3909 // create the cssvalues for the sides, stick them in the rect object
3910 nsROCSSPrimitiveValue *topVal = new nsROCSSPrimitiveValue;
3911 nsROCSSPrimitiveValue *rightVal = new nsROCSSPrimitiveValue;
3912 nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue;
3913 nsROCSSPrimitiveValue *leftVal = new nsROCSSPrimitiveValue;
3914 nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
3915 bottomVal, leftVal);
3916 if (display->mClipFlags & NS_STYLE_CLIP_TOP_AUTO) {
3917 topVal->SetIdent(eCSSKeyword_auto);
3918 } else {
3919 topVal->SetAppUnits(display->mClip.y);
3922 if (display->mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO) {
3923 rightVal->SetIdent(eCSSKeyword_auto);
3924 } else {
3925 rightVal->SetAppUnits(display->mClip.width + display->mClip.x);
3928 if (display->mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO) {
3929 bottomVal->SetIdent(eCSSKeyword_auto);
3930 } else {
3931 bottomVal->SetAppUnits(display->mClip.height + display->mClip.y);
3934 if (display->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) {
3935 leftVal->SetIdent(eCSSKeyword_auto);
3936 } else {
3937 leftVal->SetAppUnits(display->mClip.x);
3939 val->SetRect(domRect);
3942 return val;
3945 CSSValue*
3946 nsComputedDOMStyle::DoGetWillChange()
3948 const nsTArray<nsString>& willChange = StyleDisplay()->mWillChange;
3950 if (willChange.IsEmpty()) {
3951 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
3952 val->SetIdent(eCSSKeyword_auto);
3953 return val;
3956 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
3957 for (size_t i = 0; i < willChange.Length(); i++) {
3958 const nsString& willChangeIdentifier = willChange[i];
3959 nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue;
3960 valueList->AppendCSSValue(property);
3961 property->SetString(willChangeIdentifier);
3964 return valueList;
3967 CSSValue*
3968 nsComputedDOMStyle::DoGetOverflow()
3970 const nsStyleDisplay* display = StyleDisplay();
3972 if (display->mOverflowX != display->mOverflowY) {
3973 // No value to return. We can't express this combination of
3974 // values as a shorthand.
3975 return nullptr;
3978 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3979 val->SetIdent(nsCSSProps::ValueToKeywordEnum(display->mOverflowX,
3980 nsCSSProps::kOverflowKTable));
3981 return val;
3984 CSSValue*
3985 nsComputedDOMStyle::DoGetOverflowX()
3987 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3988 val->SetIdent(
3989 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowX,
3990 nsCSSProps::kOverflowSubKTable));
3991 return val;
3994 CSSValue*
3995 nsComputedDOMStyle::DoGetOverflowY()
3997 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
3998 val->SetIdent(
3999 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowY,
4000 nsCSSProps::kOverflowSubKTable));
4001 return val;
4004 CSSValue*
4005 nsComputedDOMStyle::DoGetOverflowClipBox()
4007 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4008 val->SetIdent(
4009 nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBox,
4010 nsCSSProps::kOverflowClipBoxKTable));
4011 return val;
4014 CSSValue*
4015 nsComputedDOMStyle::DoGetResize()
4017 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4018 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mResize,
4019 nsCSSProps::kResizeKTable));
4020 return val;
4024 CSSValue*
4025 nsComputedDOMStyle::DoGetPageBreakAfter()
4027 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4029 const nsStyleDisplay *display = StyleDisplay();
4031 if (display->mBreakAfter) {
4032 val->SetIdent(eCSSKeyword_always);
4033 } else {
4034 val->SetIdent(eCSSKeyword_auto);
4037 return val;
4040 CSSValue*
4041 nsComputedDOMStyle::DoGetPageBreakBefore()
4043 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4045 const nsStyleDisplay *display = StyleDisplay();
4047 if (display->mBreakBefore) {
4048 val->SetIdent(eCSSKeyword_always);
4049 } else {
4050 val->SetIdent(eCSSKeyword_auto);
4053 return val;
4056 CSSValue*
4057 nsComputedDOMStyle::DoGetPageBreakInside()
4059 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4060 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakInside,
4061 nsCSSProps::kPageBreakInsideKTable));
4062 return val;
4065 CSSValue*
4066 nsComputedDOMStyle::DoGetTouchAction()
4068 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4070 int32_t intValue = StyleDisplay()->mTouchAction;
4072 // None and Auto and Manipulation values aren't allowed
4073 // to be in conjunction with other values.
4074 // But there are all checks in CSSParserImpl::ParseTouchAction
4075 nsAutoString valueStr;
4076 nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_touch_action, intValue,
4077 NS_STYLE_TOUCH_ACTION_NONE, NS_STYLE_TOUCH_ACTION_MANIPULATION,
4078 valueStr);
4079 val->SetString(valueStr);
4080 return val;
4083 CSSValue*
4084 nsComputedDOMStyle::DoGetHeight()
4086 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4088 bool calcHeight = false;
4090 if (mInnerFrame) {
4091 calcHeight = true;
4093 const nsStyleDisplay* displayData = StyleDisplay();
4094 if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
4095 !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
4096 // An outer SVG frame should behave the same as eReplaced in this case
4097 mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) {
4099 calcHeight = false;
4103 if (calcHeight) {
4104 AssertFlushedPendingReflows();
4105 nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
4106 val->SetAppUnits(mInnerFrame->GetContentRect().height +
4107 adjustedValues.TopBottom());
4108 } else {
4109 const nsStylePosition *positionData = StylePosition();
4111 nscoord minHeight =
4112 StyleCoordToNSCoord(positionData->mMinHeight,
4113 &nsComputedDOMStyle::GetCBContentHeight, 0, true);
4115 nscoord maxHeight =
4116 StyleCoordToNSCoord(positionData->mMaxHeight,
4117 &nsComputedDOMStyle::GetCBContentHeight,
4118 nscoord_MAX, true);
4120 SetValueToCoord(val, positionData->mHeight, true, nullptr, nullptr,
4121 minHeight, maxHeight);
4124 return val;
4127 CSSValue*
4128 nsComputedDOMStyle::DoGetWidth()
4130 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4132 bool calcWidth = false;
4134 if (mInnerFrame) {
4135 calcWidth = true;
4137 const nsStyleDisplay *displayData = StyleDisplay();
4138 if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
4139 !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
4140 // An outer SVG frame should behave the same as eReplaced in this case
4141 mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) {
4143 calcWidth = false;
4147 if (calcWidth) {
4148 AssertFlushedPendingReflows();
4149 nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
4150 val->SetAppUnits(mInnerFrame->GetContentRect().width +
4151 adjustedValues.LeftRight());
4152 } else {
4153 const nsStylePosition *positionData = StylePosition();
4155 nscoord minWidth =
4156 StyleCoordToNSCoord(positionData->mMinWidth,
4157 &nsComputedDOMStyle::GetCBContentWidth, 0, true);
4159 nscoord maxWidth =
4160 StyleCoordToNSCoord(positionData->mMaxWidth,
4161 &nsComputedDOMStyle::GetCBContentWidth,
4162 nscoord_MAX, true);
4164 SetValueToCoord(val, positionData->mWidth, true, nullptr,
4165 nsCSSProps::kWidthKTable, minWidth, maxWidth);
4168 return val;
4171 CSSValue*
4172 nsComputedDOMStyle::DoGetMaxHeight()
4174 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4175 SetValueToCoord(val, StylePosition()->mMaxHeight, true,
4176 &nsComputedDOMStyle::GetCBContentHeight);
4177 return val;
4180 CSSValue*
4181 nsComputedDOMStyle::DoGetMaxWidth()
4183 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4184 SetValueToCoord(val, StylePosition()->mMaxWidth, true,
4185 &nsComputedDOMStyle::GetCBContentWidth,
4186 nsCSSProps::kWidthKTable);
4187 return val;
4190 CSSValue*
4191 nsComputedDOMStyle::DoGetMinHeight()
4193 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4194 nsStyleCoord minHeight = StylePosition()->mMinHeight;
4196 if (eStyleUnit_Auto == minHeight.GetUnit()) {
4197 // In non-flexbox contexts, "min-height: auto" means "min-height: 0"
4198 // XXXdholbert For flex items, we should set |minHeight| to the
4199 // -moz-min-content keyword, instead of 0, once we support -moz-min-content
4200 // as a height value.
4201 minHeight.SetCoordValue(0);
4204 SetValueToCoord(val, minHeight, true,
4205 &nsComputedDOMStyle::GetCBContentHeight);
4206 return val;
4209 CSSValue*
4210 nsComputedDOMStyle::DoGetMinWidth()
4212 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4214 nsStyleCoord minWidth = StylePosition()->mMinWidth;
4216 if (eStyleUnit_Auto == minWidth.GetUnit()) {
4217 // "min-width: auto" means "0", unless we're a flex item in a horizontal
4218 // flex container, in which case it means "min-content"
4219 minWidth.SetCoordValue(0);
4220 if (mOuterFrame && mOuterFrame->IsFlexItem()) {
4221 nsIFrame* flexContainer = mOuterFrame->GetParent();
4222 MOZ_ASSERT(flexContainer &&
4223 flexContainer->GetType() == nsGkAtoms::flexContainerFrame,
4224 "IsFlexItem() lied...?");
4226 if (static_cast<nsFlexContainerFrame*>(flexContainer)->IsHorizontal()) {
4227 minWidth.SetIntValue(NS_STYLE_WIDTH_MIN_CONTENT, eStyleUnit_Enumerated);
4231 SetValueToCoord(val, minWidth, true,
4232 &nsComputedDOMStyle::GetCBContentWidth,
4233 nsCSSProps::kWidthKTable);
4234 return val;
4237 CSSValue*
4238 nsComputedDOMStyle::DoGetMixBlendMode()
4240 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4241 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mMixBlendMode,
4242 nsCSSProps::kBlendModeKTable));
4243 return val;
4246 CSSValue*
4247 nsComputedDOMStyle::DoGetIsolation()
4249 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4250 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mIsolation,
4251 nsCSSProps::kIsolationKTable));
4252 return val;
4255 CSSValue*
4256 nsComputedDOMStyle::DoGetObjectFit()
4258 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4259 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StylePosition()->mObjectFit,
4260 nsCSSProps::kObjectFitKTable));
4261 return val;
4264 CSSValue*
4265 nsComputedDOMStyle::DoGetObjectPosition()
4267 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
4268 SetValueToPosition(StylePosition()->mObjectPosition, valueList);
4269 return valueList;
4272 CSSValue*
4273 nsComputedDOMStyle::DoGetLeft()
4275 return GetOffsetWidthFor(NS_SIDE_LEFT);
4278 CSSValue*
4279 nsComputedDOMStyle::DoGetRight()
4281 return GetOffsetWidthFor(NS_SIDE_RIGHT);
4284 CSSValue*
4285 nsComputedDOMStyle::DoGetTop()
4287 return GetOffsetWidthFor(NS_SIDE_TOP);
4290 nsDOMCSSValueList*
4291 nsComputedDOMStyle::GetROCSSValueList(bool aCommaDelimited)
4293 return new nsDOMCSSValueList(aCommaDelimited, true);
4296 CSSValue*
4297 nsComputedDOMStyle::GetOffsetWidthFor(mozilla::css::Side aSide)
4299 const nsStyleDisplay* display = StyleDisplay();
4301 AssertFlushedPendingReflows();
4303 uint8_t position = display->mPosition;
4304 if (!mOuterFrame) {
4305 // GetRelativeOffset and GetAbsoluteOffset don't handle elements
4306 // without frames in any sensible way. GetStaticOffset, however,
4307 // is perfect for that case.
4308 position = NS_STYLE_POSITION_STATIC;
4311 switch (position) {
4312 case NS_STYLE_POSITION_STATIC:
4313 return GetStaticOffset(aSide);
4314 case NS_STYLE_POSITION_RELATIVE:
4315 return GetRelativeOffset(aSide);
4316 case NS_STYLE_POSITION_STICKY:
4317 return GetStickyOffset(aSide);
4318 case NS_STYLE_POSITION_ABSOLUTE:
4319 case NS_STYLE_POSITION_FIXED:
4320 return GetAbsoluteOffset(aSide);
4321 default:
4322 NS_ERROR("Invalid position");
4323 return nullptr;
4327 CSSValue*
4328 nsComputedDOMStyle::GetAbsoluteOffset(mozilla::css::Side aSide)
4330 MOZ_ASSERT(mOuterFrame, "need a frame, so we can call GetContainingBlock()");
4332 nsIFrame* container = mOuterFrame->GetContainingBlock();
4333 nsMargin margin = mOuterFrame->GetUsedMargin();
4334 nsMargin border = container->GetUsedBorder();
4335 nsMargin scrollbarSizes(0, 0, 0, 0);
4336 nsRect rect = mOuterFrame->GetRect();
4337 nsRect containerRect = container->GetRect();
4339 if (container->GetType() == nsGkAtoms::viewportFrame) {
4340 // For absolutely positioned frames scrollbars are taken into
4341 // account by virtue of getting a containing block that does
4342 // _not_ include the scrollbars. For fixed positioned frames,
4343 // the containing block is the viewport, which _does_ include
4344 // scrollbars. We have to do some extra work.
4345 // the first child in the default frame list is what we want
4346 nsIFrame* scrollingChild = container->GetFirstPrincipalChild();
4347 nsIScrollableFrame *scrollFrame = do_QueryFrame(scrollingChild);
4348 if (scrollFrame) {
4349 scrollbarSizes = scrollFrame->GetActualScrollbarSizes();
4353 nscoord offset = 0;
4354 switch (aSide) {
4355 case NS_SIDE_TOP:
4356 offset = rect.y - margin.top - border.top - scrollbarSizes.top;
4358 break;
4359 case NS_SIDE_RIGHT:
4360 offset = containerRect.width - rect.width -
4361 rect.x - margin.right - border.right - scrollbarSizes.right;
4363 break;
4364 case NS_SIDE_BOTTOM:
4365 offset = containerRect.height - rect.height -
4366 rect.y - margin.bottom - border.bottom - scrollbarSizes.bottom;
4368 break;
4369 case NS_SIDE_LEFT:
4370 offset = rect.x - margin.left - border.left - scrollbarSizes.left;
4372 break;
4373 default:
4374 NS_ERROR("Invalid side");
4375 break;
4378 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4379 val->SetAppUnits(offset);
4380 return val;
4383 static_assert(NS_SIDE_TOP == 0 && NS_SIDE_RIGHT == 1 &&
4384 NS_SIDE_BOTTOM == 2 && NS_SIDE_LEFT == 3,
4385 "box side constants not as expected for NS_OPPOSITE_SIDE");
4386 #define NS_OPPOSITE_SIDE(s_) mozilla::css::Side(((s_) + 2) & 3)
4388 CSSValue*
4389 nsComputedDOMStyle::GetRelativeOffset(mozilla::css::Side aSide)
4391 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4393 const nsStylePosition* positionData = StylePosition();
4394 int32_t sign = 1;
4395 nsStyleCoord coord = positionData->mOffset.Get(aSide);
4397 NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
4398 coord.GetUnit() == eStyleUnit_Percent ||
4399 coord.GetUnit() == eStyleUnit_Auto ||
4400 coord.IsCalcUnit(),
4401 "Unexpected unit");
4403 if (coord.GetUnit() == eStyleUnit_Auto) {
4404 coord = positionData->mOffset.Get(NS_OPPOSITE_SIDE(aSide));
4405 sign = -1;
4407 PercentageBaseGetter baseGetter;
4408 if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) {
4409 baseGetter = &nsComputedDOMStyle::GetCBContentWidth;
4410 } else {
4411 baseGetter = &nsComputedDOMStyle::GetCBContentHeight;
4414 val->SetAppUnits(sign * StyleCoordToNSCoord(coord, baseGetter, 0, false));
4415 return val;
4418 CSSValue*
4419 nsComputedDOMStyle::GetStickyOffset(mozilla::css::Side aSide)
4421 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4423 const nsStylePosition* positionData = StylePosition();
4424 nsStyleCoord coord = positionData->mOffset.Get(aSide);
4426 NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
4427 coord.GetUnit() == eStyleUnit_Percent ||
4428 coord.GetUnit() == eStyleUnit_Auto ||
4429 coord.IsCalcUnit(),
4430 "Unexpected unit");
4432 if (coord.GetUnit() == eStyleUnit_Auto) {
4433 val->SetIdent(eCSSKeyword_auto);
4434 return val;
4436 PercentageBaseGetter baseGetter;
4437 if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) {
4438 baseGetter = &nsComputedDOMStyle::GetScrollFrameContentWidth;
4439 } else {
4440 baseGetter = &nsComputedDOMStyle::GetScrollFrameContentHeight;
4443 val->SetAppUnits(StyleCoordToNSCoord(coord, baseGetter, 0, false));
4444 return val;
4448 CSSValue*
4449 nsComputedDOMStyle::GetStaticOffset(mozilla::css::Side aSide)
4452 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4453 SetValueToCoord(val, StylePosition()->mOffset.Get(aSide), false);
4454 return val;
4457 CSSValue*
4458 nsComputedDOMStyle::GetPaddingWidthFor(mozilla::css::Side aSide)
4460 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4462 if (!mInnerFrame) {
4463 SetValueToCoord(val, StylePadding()->mPadding.Get(aSide), true);
4464 } else {
4465 AssertFlushedPendingReflows();
4467 val->SetAppUnits(mInnerFrame->GetUsedPadding().Side(aSide));
4470 return val;
4473 bool
4474 nsComputedDOMStyle::GetLineHeightCoord(nscoord& aCoord)
4476 AssertFlushedPendingReflows();
4478 nscoord blockHeight = NS_AUTOHEIGHT;
4479 if (StyleText()->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
4480 if (!mInnerFrame)
4481 return false;
4483 if (nsLayoutUtils::IsNonWrapperBlock(mInnerFrame)) {
4484 blockHeight = mInnerFrame->GetContentRect().height;
4485 } else {
4486 GetCBContentHeight(blockHeight);
4490 // lie about font size inflation since we lie about font size (since
4491 // the inflation only applies to text)
4492 aCoord = nsHTMLReflowState::CalcLineHeight(mContent, mStyleContextHolder,
4493 blockHeight, 1.0f);
4495 // CalcLineHeight uses font->mFont.size, but we want to use
4496 // font->mSize as the font size. Adjust for that. Also adjust for
4497 // the text zoom, if any.
4498 const nsStyleFont* font = StyleFont();
4499 float fCoord = float(aCoord);
4500 if (font->mAllowZoom) {
4501 fCoord /= mPresShell->GetPresContext()->TextZoom();
4503 if (font->mFont.size != font->mSize) {
4504 fCoord = fCoord * (float(font->mSize) / float(font->mFont.size));
4506 aCoord = NSToCoordRound(fCoord);
4508 return true;
4511 CSSValue*
4512 nsComputedDOMStyle::GetBorderColorsFor(mozilla::css::Side aSide)
4514 const nsStyleBorder *border = StyleBorder();
4516 if (border->mBorderColors) {
4517 nsBorderColors* borderColors = border->mBorderColors[aSide];
4518 if (borderColors) {
4519 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
4521 do {
4522 nsROCSSPrimitiveValue *primitive = new nsROCSSPrimitiveValue;
4524 SetToRGBAColor(primitive, borderColors->mColor);
4526 valueList->AppendCSSValue(primitive);
4527 borderColors = borderColors->mNext;
4528 } while (borderColors);
4530 return valueList;
4534 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
4535 val->SetIdent(eCSSKeyword_none);
4536 return val;
4539 CSSValue*
4540 nsComputedDOMStyle::GetBorderWidthFor(mozilla::css::Side aSide)
4542 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4544 nscoord width;
4545 if (mInnerFrame) {
4546 AssertFlushedPendingReflows();
4547 width = mInnerFrame->GetUsedBorder().Side(aSide);
4548 } else {
4549 width = StyleBorder()->GetComputedBorderWidth(aSide);
4551 val->SetAppUnits(width);
4553 return val;
4556 CSSValue*
4557 nsComputedDOMStyle::GetBorderColorFor(mozilla::css::Side aSide)
4559 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4561 nscolor color;
4562 bool foreground;
4563 StyleBorder()->GetBorderColor(aSide, color, foreground);
4564 if (foreground) {
4565 color = StyleColor()->mColor;
4568 SetToRGBAColor(val, color);
4569 return val;
4572 CSSValue*
4573 nsComputedDOMStyle::GetMarginWidthFor(mozilla::css::Side aSide)
4575 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4577 if (!mInnerFrame) {
4578 SetValueToCoord(val, StyleMargin()->mMargin.Get(aSide), false);
4579 } else {
4580 AssertFlushedPendingReflows();
4582 // For tables, GetUsedMargin always returns an empty margin, so we
4583 // should read the margin from the outer table frame instead.
4584 val->SetAppUnits(mOuterFrame->GetUsedMargin().Side(aSide));
4585 NS_ASSERTION(mOuterFrame == mInnerFrame ||
4586 mInnerFrame->GetUsedMargin() == nsMargin(0, 0, 0, 0),
4587 "Inner tables must have zero margins");
4590 return val;
4593 CSSValue*
4594 nsComputedDOMStyle::GetBorderStyleFor(mozilla::css::Side aSide)
4596 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4597 val->SetIdent(
4598 nsCSSProps::ValueToKeywordEnum(StyleBorder()->GetBorderStyle(aSide),
4599 nsCSSProps::kBorderStyleKTable));
4600 return val;
4603 void
4604 nsComputedDOMStyle::SetValueToCoord(nsROCSSPrimitiveValue* aValue,
4605 const nsStyleCoord& aCoord,
4606 bool aClampNegativeCalc,
4607 PercentageBaseGetter aPercentageBaseGetter,
4608 const KTableValue aTable[],
4609 nscoord aMinAppUnits,
4610 nscoord aMaxAppUnits)
4612 NS_PRECONDITION(aValue, "Must have a value to work with");
4614 switch (aCoord.GetUnit()) {
4615 case eStyleUnit_Normal:
4616 aValue->SetIdent(eCSSKeyword_normal);
4617 break;
4619 case eStyleUnit_Auto:
4620 aValue->SetIdent(eCSSKeyword_auto);
4621 break;
4623 case eStyleUnit_Percent:
4625 nscoord percentageBase;
4626 if (aPercentageBaseGetter &&
4627 (this->*aPercentageBaseGetter)(percentageBase)) {
4628 nscoord val = NSCoordSaturatingMultiply(percentageBase,
4629 aCoord.GetPercentValue());
4630 aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4631 } else {
4632 aValue->SetPercent(aCoord.GetPercentValue());
4635 break;
4637 case eStyleUnit_Factor:
4638 aValue->SetNumber(aCoord.GetFactorValue());
4639 break;
4641 case eStyleUnit_Coord:
4643 nscoord val = aCoord.GetCoordValue();
4644 aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4646 break;
4648 case eStyleUnit_Integer:
4649 aValue->SetNumber(aCoord.GetIntValue());
4650 break;
4652 case eStyleUnit_Enumerated:
4653 NS_ASSERTION(aTable, "Must have table to handle this case");
4654 aValue->SetIdent(nsCSSProps::ValueToKeywordEnum(aCoord.GetIntValue(),
4655 aTable));
4656 break;
4658 case eStyleUnit_None:
4659 aValue->SetIdent(eCSSKeyword_none);
4660 break;
4662 case eStyleUnit_Calc:
4663 nscoord percentageBase;
4664 if (!aCoord.CalcHasPercent()) {
4665 nscoord val = nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
4666 if (aClampNegativeCalc && val < 0) {
4667 NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
4668 "parser should have rejected value");
4669 val = 0;
4671 aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4672 } else if (aPercentageBaseGetter &&
4673 (this->*aPercentageBaseGetter)(percentageBase)) {
4674 nscoord val =
4675 nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase);
4676 if (aClampNegativeCalc && val < 0) {
4677 NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
4678 "parser should have rejected value");
4679 val = 0;
4681 aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
4682 } else {
4683 nsStyleCoord::Calc *calc = aCoord.GetCalcValue();
4684 SetValueToCalc(calc, aValue);
4686 break;
4688 case eStyleUnit_Degree:
4689 aValue->SetDegree(aCoord.GetAngleValue());
4690 break;
4692 case eStyleUnit_Grad:
4693 aValue->SetGrad(aCoord.GetAngleValue());
4694 break;
4696 case eStyleUnit_Radian:
4697 aValue->SetRadian(aCoord.GetAngleValue());
4698 break;
4700 case eStyleUnit_Turn:
4701 aValue->SetTurn(aCoord.GetAngleValue());
4702 break;
4704 case eStyleUnit_FlexFraction: {
4705 nsAutoString tmpStr;
4706 nsStyleUtil::AppendCSSNumber(aCoord.GetFlexFractionValue(), tmpStr);
4707 tmpStr.AppendLiteral("fr");
4708 aValue->SetString(tmpStr);
4709 break;
4712 default:
4713 NS_ERROR("Can't handle this unit");
4714 break;
4718 nscoord
4719 nsComputedDOMStyle::StyleCoordToNSCoord(const nsStyleCoord& aCoord,
4720 PercentageBaseGetter aPercentageBaseGetter,
4721 nscoord aDefaultValue,
4722 bool aClampNegativeCalc)
4724 NS_PRECONDITION(aPercentageBaseGetter, "Must have a percentage base getter");
4725 if (aCoord.GetUnit() == eStyleUnit_Coord) {
4726 return aCoord.GetCoordValue();
4728 if (aCoord.GetUnit() == eStyleUnit_Percent || aCoord.IsCalcUnit()) {
4729 nscoord percentageBase;
4730 if ((this->*aPercentageBaseGetter)(percentageBase)) {
4731 nscoord result =
4732 nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase);
4733 if (aClampNegativeCalc && result < 0) {
4734 NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
4735 "parser should have rejected value");
4736 result = 0;
4738 return result;
4740 // Fall through to returning aDefaultValue if we have no percentage base.
4743 return aDefaultValue;
4746 bool
4747 nsComputedDOMStyle::GetCBContentWidth(nscoord& aWidth)
4749 if (!mOuterFrame) {
4750 return false;
4753 AssertFlushedPendingReflows();
4755 nsIFrame* container = mOuterFrame->GetContainingBlock();
4756 aWidth = container->GetContentRect().width;
4757 return true;
4760 bool
4761 nsComputedDOMStyle::GetCBContentHeight(nscoord& aHeight)
4763 if (!mOuterFrame) {
4764 return false;
4767 AssertFlushedPendingReflows();
4769 nsIFrame* container = mOuterFrame->GetContainingBlock();
4770 aHeight = container->GetContentRect().height;
4771 return true;
4774 bool
4775 nsComputedDOMStyle::GetScrollFrameContentWidth(nscoord& aWidth)
4777 if (!mOuterFrame) {
4778 return false;
4781 AssertFlushedPendingReflows();
4783 nsIScrollableFrame* scrollableFrame =
4784 nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(),
4785 nsLayoutUtils::SCROLLABLE_SAME_DOC |
4786 nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4788 if (!scrollableFrame) {
4789 return false;
4791 aWidth =
4792 scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().width;
4793 return true;
4796 bool
4797 nsComputedDOMStyle::GetScrollFrameContentHeight(nscoord& aHeight)
4799 if (!mOuterFrame) {
4800 return false;
4803 AssertFlushedPendingReflows();
4805 nsIScrollableFrame* scrollableFrame =
4806 nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(),
4807 nsLayoutUtils::SCROLLABLE_SAME_DOC |
4808 nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4810 if (!scrollableFrame) {
4811 return false;
4813 aHeight =
4814 scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().height;
4815 return true;
4818 bool
4819 nsComputedDOMStyle::GetFrameBorderRectWidth(nscoord& aWidth)
4821 if (!mInnerFrame) {
4822 return false;
4825 AssertFlushedPendingReflows();
4827 aWidth = mInnerFrame->GetSize().width;
4828 return true;
4831 bool
4832 nsComputedDOMStyle::GetFrameBorderRectHeight(nscoord& aHeight)
4834 if (!mInnerFrame) {
4835 return false;
4838 AssertFlushedPendingReflows();
4840 aHeight = mInnerFrame->GetSize().height;
4841 return true;
4844 bool
4845 nsComputedDOMStyle::GetFrameBoundsWidthForTransform(nscoord& aWidth)
4847 // We need a frame to work with.
4848 if (!mInnerFrame) {
4849 return false;
4852 AssertFlushedPendingReflows();
4854 aWidth = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).width;
4855 return true;
4858 bool
4859 nsComputedDOMStyle::GetFrameBoundsHeightForTransform(nscoord& aHeight)
4861 // We need a frame to work with.
4862 if (!mInnerFrame) {
4863 return false;
4866 AssertFlushedPendingReflows();
4868 aHeight = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).height;
4869 return true;
4872 CSSValue*
4873 nsComputedDOMStyle::GetSVGPaintFor(bool aFill)
4875 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4877 const nsStyleSVG* svg = StyleSVG();
4878 const nsStyleSVGPaint* paint = nullptr;
4880 if (aFill)
4881 paint = &svg->mFill;
4882 else
4883 paint = &svg->mStroke;
4885 nsAutoString paintString;
4887 switch (paint->mType) {
4888 case eStyleSVGPaintType_None:
4890 val->SetIdent(eCSSKeyword_none);
4891 break;
4893 case eStyleSVGPaintType_Color:
4895 SetToRGBAColor(val, paint->mPaint.mColor);
4896 break;
4898 case eStyleSVGPaintType_Server:
4900 nsDOMCSSValueList *valueList = GetROCSSValueList(false);
4901 valueList->AppendCSSValue(val);
4903 nsROCSSPrimitiveValue* fallback = new nsROCSSPrimitiveValue;
4904 valueList->AppendCSSValue(fallback);
4906 val->SetURI(paint->mPaint.mPaintServer);
4907 SetToRGBAColor(fallback, paint->mFallbackColor);
4908 return valueList;
4910 case eStyleSVGPaintType_ContextFill:
4912 val->SetIdent(eCSSKeyword_context_fill);
4913 break;
4915 case eStyleSVGPaintType_ContextStroke:
4917 val->SetIdent(eCSSKeyword_context_stroke);
4918 break;
4922 return val;
4925 CSSValue*
4926 nsComputedDOMStyle::DoGetFill()
4928 return GetSVGPaintFor(true);
4931 CSSValue*
4932 nsComputedDOMStyle::DoGetStroke()
4934 return GetSVGPaintFor(false);
4937 CSSValue*
4938 nsComputedDOMStyle::DoGetMarkerEnd()
4940 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4942 const nsStyleSVG* svg = StyleSVG();
4944 if (svg->mMarkerEnd)
4945 val->SetURI(svg->mMarkerEnd);
4946 else
4947 val->SetIdent(eCSSKeyword_none);
4949 return val;
4952 CSSValue*
4953 nsComputedDOMStyle::DoGetMarkerMid()
4955 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4957 const nsStyleSVG* svg = StyleSVG();
4959 if (svg->mMarkerMid)
4960 val->SetURI(svg->mMarkerMid);
4961 else
4962 val->SetIdent(eCSSKeyword_none);
4964 return val;
4967 CSSValue*
4968 nsComputedDOMStyle::DoGetMarkerStart()
4970 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4972 const nsStyleSVG* svg = StyleSVG();
4974 if (svg->mMarkerStart)
4975 val->SetURI(svg->mMarkerStart);
4976 else
4977 val->SetIdent(eCSSKeyword_none);
4979 return val;
4982 CSSValue*
4983 nsComputedDOMStyle::DoGetStrokeDasharray()
4985 const nsStyleSVG* svg = StyleSVG();
4987 if (!svg->mStrokeDasharrayLength || !svg->mStrokeDasharray) {
4988 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
4989 val->SetIdent(eCSSKeyword_none);
4990 return val;
4993 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
4995 for (uint32_t i = 0; i < svg->mStrokeDasharrayLength; i++) {
4996 nsROCSSPrimitiveValue* dash = new nsROCSSPrimitiveValue;
4997 valueList->AppendCSSValue(dash);
4999 SetValueToCoord(dash, svg->mStrokeDasharray[i], true);
5002 return valueList;
5005 CSSValue*
5006 nsComputedDOMStyle::DoGetStrokeDashoffset()
5008 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
5009 SetValueToCoord(val, StyleSVG()->mStrokeDashoffset, false);
5010 return val;
5013 CSSValue*
5014 nsComputedDOMStyle::DoGetStrokeWidth()
5016 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
5017 SetValueToCoord(val, StyleSVG()->mStrokeWidth, true);
5018 return val;
5021 CSSValue*
5022 nsComputedDOMStyle::DoGetVectorEffect()
5024 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5025 val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mVectorEffect,
5026 nsCSSProps::kVectorEffectKTable));
5027 return val;
5030 CSSValue*
5031 nsComputedDOMStyle::DoGetFillOpacity()
5033 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5034 val->SetNumber(StyleSVG()->mFillOpacity);
5035 return val;
5038 CSSValue*
5039 nsComputedDOMStyle::DoGetFloodOpacity()
5041 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5042 val->SetNumber(StyleSVGReset()->mFloodOpacity);
5043 return val;
5046 CSSValue*
5047 nsComputedDOMStyle::DoGetStopOpacity()
5049 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5050 val->SetNumber(StyleSVGReset()->mStopOpacity);
5051 return val;
5054 CSSValue*
5055 nsComputedDOMStyle::DoGetStrokeMiterlimit()
5057 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5058 val->SetNumber(StyleSVG()->mStrokeMiterlimit);
5059 return val;
5062 CSSValue*
5063 nsComputedDOMStyle::DoGetStrokeOpacity()
5065 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5066 val->SetNumber(StyleSVG()->mStrokeOpacity);
5067 return val;
5070 CSSValue*
5071 nsComputedDOMStyle::DoGetClipRule()
5073 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5074 val->SetIdent(nsCSSProps::ValueToKeywordEnum(
5075 StyleSVG()->mClipRule, nsCSSProps::kFillRuleKTable));
5076 return val;
5079 CSSValue*
5080 nsComputedDOMStyle::DoGetFillRule()
5082 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5083 val->SetIdent(nsCSSProps::ValueToKeywordEnum(
5084 StyleSVG()->mFillRule, nsCSSProps::kFillRuleKTable));
5085 return val;
5088 CSSValue*
5089 nsComputedDOMStyle::DoGetStrokeLinecap()
5091 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5092 val->SetIdent(
5093 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinecap,
5094 nsCSSProps::kStrokeLinecapKTable));
5095 return val;
5098 CSSValue*
5099 nsComputedDOMStyle::DoGetStrokeLinejoin()
5101 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5102 val->SetIdent(
5103 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinejoin,
5104 nsCSSProps::kStrokeLinejoinKTable));
5105 return val;
5108 CSSValue*
5109 nsComputedDOMStyle::DoGetTextAnchor()
5111 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5112 val->SetIdent(
5113 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mTextAnchor,
5114 nsCSSProps::kTextAnchorKTable));
5115 return val;
5118 CSSValue*
5119 nsComputedDOMStyle::DoGetColorInterpolation()
5121 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5122 val->SetIdent(
5123 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolation,
5124 nsCSSProps::kColorInterpolationKTable));
5125 return val;
5128 CSSValue*
5129 nsComputedDOMStyle::DoGetColorInterpolationFilters()
5131 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5132 val->SetIdent(
5133 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolationFilters,
5134 nsCSSProps::kColorInterpolationKTable));
5135 return val;
5138 CSSValue*
5139 nsComputedDOMStyle::DoGetDominantBaseline()
5141 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5142 val->SetIdent(
5143 nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mDominantBaseline,
5144 nsCSSProps::kDominantBaselineKTable));
5145 return val;
5148 CSSValue*
5149 nsComputedDOMStyle::DoGetImageRendering()
5151 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5152 val->SetIdent(
5153 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mImageRendering,
5154 nsCSSProps::kImageRenderingKTable));
5155 return val;
5158 CSSValue*
5159 nsComputedDOMStyle::DoGetShapeRendering()
5161 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5162 val->SetIdent(
5163 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mShapeRendering,
5164 nsCSSProps::kShapeRenderingKTable));
5165 return val;
5168 CSSValue*
5169 nsComputedDOMStyle::DoGetTextRendering()
5171 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5172 val->SetIdent(
5173 nsCSSProps::ValueToKeywordEnum(StyleSVG()->mTextRendering,
5174 nsCSSProps::kTextRenderingKTable));
5175 return val;
5178 CSSValue*
5179 nsComputedDOMStyle::DoGetFloodColor()
5181 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5182 SetToRGBAColor(val, StyleSVGReset()->mFloodColor);
5183 return val;
5186 CSSValue*
5187 nsComputedDOMStyle::DoGetLightingColor()
5189 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5190 SetToRGBAColor(val, StyleSVGReset()->mLightingColor);
5191 return val;
5194 CSSValue*
5195 nsComputedDOMStyle::DoGetStopColor()
5197 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5198 SetToRGBAColor(val, StyleSVGReset()->mStopColor);
5199 return val;
5202 inline void AppendBasicShapeTypeToString(nsStyleBasicShape::Type aType,
5203 nsAutoString& aString)
5205 nsCSSKeyword functionName;
5206 switch (aType) {
5207 case nsStyleBasicShape::Type::ePolygon:
5208 functionName = eCSSKeyword_polygon;
5209 break;
5210 case nsStyleBasicShape::Type::eCircle:
5211 functionName = eCSSKeyword_circle;
5212 break;
5213 case nsStyleBasicShape::Type::eEllipse:
5214 functionName = eCSSKeyword_ellipse;
5215 break;
5216 case nsStyleBasicShape::Type::eInset:
5217 functionName = eCSSKeyword_inset;
5218 break;
5219 default:
5220 functionName = eCSSKeyword_UNKNOWN;
5221 NS_NOTREACHED("unexpected type");
5223 AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(functionName),
5224 aString);
5227 void
5228 nsComputedDOMStyle::BoxValuesToString(nsAString& aString,
5229 const nsTArray<nsStyleCoord>& aBoxValues)
5231 NS_ABORT_IF_FALSE(aBoxValues.Length() == 4, "wrong number of box values");
5232 nsAutoString value1, value2, value3, value4;
5233 SetCssTextToCoord(value1, aBoxValues[0]);
5234 SetCssTextToCoord(value2, aBoxValues[1]);
5235 SetCssTextToCoord(value3, aBoxValues[2]);
5236 SetCssTextToCoord(value4, aBoxValues[3]);
5238 // nsROCSSPrimitiveValue do not have binary comparison operators.
5239 // Compare string results instead.
5240 aString.Append(value1);
5241 if (value1 != value2 || value1 != value3 || value1 != value4) {
5242 aString.Append(' ');
5243 aString.Append(value2);
5244 if (value1 != value3 || value2 != value4) {
5245 aString.Append(' ');
5246 aString.Append(value3);
5247 if (value2 != value4) {
5248 aString.Append(' ');
5249 aString.Append(value4);
5255 void
5256 nsComputedDOMStyle::BasicShapeRadiiToString(nsAString& aCssText,
5257 const nsStyleCorners& aCorners)
5259 nsTArray<nsStyleCoord> horizontal, vertical;
5260 nsAutoString horizontalString, verticalString;
5261 NS_FOR_CSS_FULL_CORNERS(corner) {
5262 horizontal.AppendElement(
5263 aCorners.Get(NS_FULL_TO_HALF_CORNER(corner, false)));
5264 vertical.AppendElement(
5265 aCorners.Get(NS_FULL_TO_HALF_CORNER(corner, true)));
5267 BoxValuesToString(horizontalString, horizontal);
5268 BoxValuesToString(verticalString, vertical);
5269 aCssText.Append(horizontalString);
5270 if (horizontalString == verticalString) {
5271 return;
5273 aCssText.AppendLiteral(" / ");
5274 aCssText.Append(verticalString);
5277 CSSValue*
5278 nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
5279 const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox)
5281 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
5282 if (aStyleBasicShape) {
5283 nsStyleBasicShape::Type type = aStyleBasicShape->GetShapeType();
5284 // Shape function name and opening parenthesis.
5285 nsAutoString shapeFunctionString;
5286 AppendBasicShapeTypeToString(type, shapeFunctionString);
5287 shapeFunctionString.Append('(');
5288 switch (type) {
5289 case nsStyleBasicShape::Type::ePolygon: {
5290 bool hasEvenOdd = aStyleBasicShape->GetFillRule() ==
5291 NS_STYLE_FILL_RULE_EVENODD;
5292 if (hasEvenOdd) {
5293 shapeFunctionString.AppendLiteral("evenodd");
5295 for (size_t i = 0;
5296 i < aStyleBasicShape->Coordinates().Length(); i += 2) {
5297 nsAutoString coordString;
5298 if (i > 0 || hasEvenOdd) {
5299 shapeFunctionString.AppendLiteral(", ");
5301 SetCssTextToCoord(coordString,
5302 aStyleBasicShape->Coordinates()[i]);
5303 shapeFunctionString.Append(coordString);
5304 shapeFunctionString.Append(' ');
5305 SetCssTextToCoord(coordString,
5306 aStyleBasicShape->Coordinates()[i + 1]);
5307 shapeFunctionString.Append(coordString);
5309 break;
5311 case nsStyleBasicShape::Type::eCircle:
5312 case nsStyleBasicShape::Type::eEllipse: {
5313 const nsTArray<nsStyleCoord>& radii = aStyleBasicShape->Coordinates();
5314 NS_ABORT_IF_FALSE(radii.Length() ==
5315 (nsStyleBasicShape::Type::eCircle ? 1 : 2),
5316 "wrong number of radii");
5317 for (size_t i = 0; i < radii.Length(); ++i) {
5318 nsAutoString radius;
5319 nsRefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
5320 bool clampNegativeCalc = true;
5321 SetValueToCoord(value, radii[i], clampNegativeCalc, nullptr,
5322 nsCSSProps::kShapeRadiusKTable);
5323 value->GetCssText(radius);
5324 shapeFunctionString.Append(radius);
5325 shapeFunctionString.Append(' ');
5327 shapeFunctionString.AppendLiteral("at ");
5329 nsRefPtr<nsDOMCSSValueList> position = GetROCSSValueList(false);
5330 nsAutoString positionString;
5331 SetValueToPosition(aStyleBasicShape->GetPosition(), position);
5332 position->GetCssText(positionString);
5333 shapeFunctionString.Append(positionString);
5334 break;
5336 case nsStyleBasicShape::Type::eInset: {
5337 BoxValuesToString(shapeFunctionString, aStyleBasicShape->Coordinates());
5338 if (aStyleBasicShape->HasRadius()) {
5339 shapeFunctionString.AppendLiteral(" round ");
5340 nsAutoString radiiString;
5341 BasicShapeRadiiToString(radiiString, aStyleBasicShape->GetRadius());
5342 shapeFunctionString.Append(radiiString);
5344 break;
5346 default:
5347 NS_NOTREACHED("unexpected type");
5349 shapeFunctionString.Append(')');
5350 nsROCSSPrimitiveValue* functionValue = new nsROCSSPrimitiveValue;
5351 functionValue->SetString(shapeFunctionString);
5352 valueList->AppendCSSValue(functionValue);
5355 if (aSizingBox == NS_STYLE_CLIP_SHAPE_SIZING_NOBOX) {
5356 return valueList;
5359 nsAutoString boxString;
5360 AppendASCIItoUTF16(
5361 nsCSSProps::ValueToKeyword(aSizingBox,
5362 nsCSSProps::kClipShapeSizingKTable),
5363 boxString);
5364 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
5365 val->SetString(boxString);
5366 valueList->AppendCSSValue(val);
5368 return valueList;
5371 CSSValue*
5372 nsComputedDOMStyle::DoGetClipPath()
5374 const nsStyleSVGReset* svg = StyleSVGReset();
5375 switch (svg->mClipPath.GetType()) {
5376 case NS_STYLE_CLIP_PATH_SHAPE:
5377 return CreatePrimitiveValueForClipPath(svg->mClipPath.GetBasicShape(),
5378 svg->mClipPath.GetSizingBox());
5379 case NS_STYLE_CLIP_PATH_BOX:
5380 return CreatePrimitiveValueForClipPath(nullptr,
5381 svg->mClipPath.GetSizingBox());
5382 case NS_STYLE_CLIP_PATH_URL: {
5383 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
5384 val->SetURI(svg->mClipPath.GetURL());
5385 return val;
5387 case NS_STYLE_CLIP_PATH_NONE: {
5388 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
5389 val->SetIdent(eCSSKeyword_none);
5390 return val;
5392 default:
5393 NS_NOTREACHED("unexpected type");
5395 return nullptr;
5398 void
5399 nsComputedDOMStyle::SetCssTextToCoord(nsAString& aCssText,
5400 const nsStyleCoord& aCoord)
5402 nsRefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
5403 bool clampNegativeCalc = true;
5404 SetValueToCoord(value, aCoord, clampNegativeCalc);
5405 value->GetCssText(aCssText);
5408 CSSValue*
5409 nsComputedDOMStyle::CreatePrimitiveValueForStyleFilter(
5410 const nsStyleFilter& aStyleFilter)
5412 nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
5413 // Handle url().
5414 if (aStyleFilter.GetType() == NS_STYLE_FILTER_URL) {
5415 value->SetURI(aStyleFilter.GetURL());
5416 return value;
5419 // Filter function name and opening parenthesis.
5420 nsAutoString filterFunctionString;
5421 AppendASCIItoUTF16(
5422 nsCSSProps::ValueToKeyword(aStyleFilter.GetType(),
5423 nsCSSProps::kFilterFunctionKTable),
5424 filterFunctionString);
5425 filterFunctionString.Append('(');
5427 nsAutoString argumentString;
5428 if (aStyleFilter.GetType() == NS_STYLE_FILTER_DROP_SHADOW) {
5429 // Handle drop-shadow()
5430 nsRefPtr<CSSValue> shadowValue =
5431 GetCSSShadowArray(aStyleFilter.GetDropShadow(),
5432 StyleColor()->mColor,
5433 false);
5434 ErrorResult dummy;
5435 shadowValue->GetCssText(argumentString, dummy);
5436 } else {
5437 // Filter function argument.
5438 SetCssTextToCoord(argumentString, aStyleFilter.GetFilterParameter());
5440 filterFunctionString.Append(argumentString);
5442 // Filter function closing parenthesis.
5443 filterFunctionString.Append(')');
5445 value->SetString(filterFunctionString);
5446 return value;
5449 CSSValue*
5450 nsComputedDOMStyle::DoGetFilter()
5452 const nsTArray<nsStyleFilter>& filters = StyleSVGReset()->mFilters;
5454 if (filters.IsEmpty()) {
5455 nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
5456 value->SetIdent(eCSSKeyword_none);
5457 return value;
5460 nsDOMCSSValueList* valueList = GetROCSSValueList(false);
5461 for(uint32_t i = 0; i < filters.Length(); i++) {
5462 CSSValue* value = CreatePrimitiveValueForStyleFilter(filters[i]);
5463 valueList->AppendCSSValue(value);
5465 return valueList;
5468 CSSValue*
5469 nsComputedDOMStyle::DoGetMask()
5471 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
5473 const nsStyleSVGReset* svg = StyleSVGReset();
5475 if (svg->mMask)
5476 val->SetURI(svg->mMask);
5477 else
5478 val->SetIdent(eCSSKeyword_none);
5480 return val;
5483 CSSValue*
5484 nsComputedDOMStyle::DoGetMaskType()
5486 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5487 val->SetIdent(
5488 nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mMaskType,
5489 nsCSSProps::kMaskTypeKTable));
5490 return val;
5493 CSSValue*
5494 nsComputedDOMStyle::DoGetPaintOrder()
5496 nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
5497 nsAutoString string;
5498 uint8_t paintOrder = StyleSVG()->mPaintOrder;
5499 nsStyleUtil::AppendPaintOrderValue(paintOrder, string);
5500 val->SetString(string);
5501 return val;
5504 CSSValue*
5505 nsComputedDOMStyle::DoGetTransitionDelay()
5507 const nsStyleDisplay* display = StyleDisplay();
5509 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5511 NS_ABORT_IF_FALSE(display->mTransitionDelayCount > 0,
5512 "first item must be explicit");
5513 uint32_t i = 0;
5514 do {
5515 const StyleTransition *transition = &display->mTransitions[i];
5516 nsROCSSPrimitiveValue* delay = new nsROCSSPrimitiveValue;
5517 valueList->AppendCSSValue(delay);
5518 delay->SetTime((float)transition->GetDelay() / (float)PR_MSEC_PER_SEC);
5519 } while (++i < display->mTransitionDelayCount);
5521 return valueList;
5524 CSSValue*
5525 nsComputedDOMStyle::DoGetTransitionDuration()
5527 const nsStyleDisplay* display = StyleDisplay();
5529 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5531 NS_ABORT_IF_FALSE(display->mTransitionDurationCount > 0,
5532 "first item must be explicit");
5533 uint32_t i = 0;
5534 do {
5535 const StyleTransition *transition = &display->mTransitions[i];
5536 nsROCSSPrimitiveValue* duration = new nsROCSSPrimitiveValue;
5537 valueList->AppendCSSValue(duration);
5539 duration->SetTime((float)transition->GetDuration() / (float)PR_MSEC_PER_SEC);
5540 } while (++i < display->mTransitionDurationCount);
5542 return valueList;
5545 CSSValue*
5546 nsComputedDOMStyle::DoGetTransitionProperty()
5548 const nsStyleDisplay* display = StyleDisplay();
5550 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5552 NS_ABORT_IF_FALSE(display->mTransitionPropertyCount > 0,
5553 "first item must be explicit");
5554 uint32_t i = 0;
5555 do {
5556 const StyleTransition *transition = &display->mTransitions[i];
5557 nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue;
5558 valueList->AppendCSSValue(property);
5559 nsCSSProperty cssprop = transition->GetProperty();
5560 if (cssprop == eCSSPropertyExtra_all_properties)
5561 property->SetIdent(eCSSKeyword_all);
5562 else if (cssprop == eCSSPropertyExtra_no_properties)
5563 property->SetIdent(eCSSKeyword_none);
5564 else if (cssprop == eCSSProperty_UNKNOWN)
5566 nsAutoString escaped;
5567 nsStyleUtil::AppendEscapedCSSIdent(
5568 nsDependentAtomString(transition->GetUnknownProperty()), escaped);
5569 property->SetString(escaped); // really want SetIdent
5571 else
5572 property->SetString(nsCSSProps::GetStringValue(cssprop));
5573 } while (++i < display->mTransitionPropertyCount);
5575 return valueList;
5578 void
5579 nsComputedDOMStyle::AppendTimingFunction(nsDOMCSSValueList *aValueList,
5580 const nsTimingFunction& aTimingFunction)
5582 nsROCSSPrimitiveValue* timingFunction = new nsROCSSPrimitiveValue;
5583 aValueList->AppendCSSValue(timingFunction);
5585 nsAutoString tmp;
5587 if (aTimingFunction.mType == nsTimingFunction::Function) {
5588 // set the value from the cubic-bezier control points
5589 // (We could try to regenerate the keywords if we want.)
5590 tmp.AppendLiteral("cubic-bezier(");
5591 tmp.AppendFloat(aTimingFunction.mFunc.mX1);
5592 tmp.AppendLiteral(", ");
5593 tmp.AppendFloat(aTimingFunction.mFunc.mY1);
5594 tmp.AppendLiteral(", ");
5595 tmp.AppendFloat(aTimingFunction.mFunc.mX2);
5596 tmp.AppendLiteral(", ");
5597 tmp.AppendFloat(aTimingFunction.mFunc.mY2);
5598 tmp.Append(')');
5599 } else {
5600 tmp.AppendLiteral("steps(");
5601 tmp.AppendInt(aTimingFunction.mSteps);
5602 if (aTimingFunction.mType == nsTimingFunction::StepStart) {
5603 tmp.AppendLiteral(", start)");
5604 } else {
5605 tmp.AppendLiteral(", end)");
5608 timingFunction->SetString(tmp);
5611 CSSValue*
5612 nsComputedDOMStyle::DoGetTransitionTimingFunction()
5614 const nsStyleDisplay* display = StyleDisplay();
5616 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5618 NS_ABORT_IF_FALSE(display->mTransitionTimingFunctionCount > 0,
5619 "first item must be explicit");
5620 uint32_t i = 0;
5621 do {
5622 AppendTimingFunction(valueList,
5623 display->mTransitions[i].GetTimingFunction());
5624 } while (++i < display->mTransitionTimingFunctionCount);
5626 return valueList;
5629 CSSValue*
5630 nsComputedDOMStyle::DoGetAnimationName()
5632 const nsStyleDisplay* display = StyleDisplay();
5634 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5636 NS_ABORT_IF_FALSE(display->mAnimationNameCount > 0,
5637 "first item must be explicit");
5638 uint32_t i = 0;
5639 do {
5640 const StyleAnimation *animation = &display->mAnimations[i];
5641 nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue;
5642 valueList->AppendCSSValue(property);
5644 const nsString& name = animation->GetName();
5645 if (name.IsEmpty()) {
5646 property->SetIdent(eCSSKeyword_none);
5647 } else {
5648 nsAutoString escaped;
5649 nsStyleUtil::AppendEscapedCSSIdent(animation->GetName(), escaped);
5650 property->SetString(escaped); // really want SetIdent
5652 } while (++i < display->mAnimationNameCount);
5654 return valueList;
5657 CSSValue*
5658 nsComputedDOMStyle::DoGetAnimationDelay()
5660 const nsStyleDisplay* display = StyleDisplay();
5662 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5664 NS_ABORT_IF_FALSE(display->mAnimationDelayCount > 0,
5665 "first item must be explicit");
5666 uint32_t i = 0;
5667 do {
5668 const StyleAnimation *animation = &display->mAnimations[i];
5669 nsROCSSPrimitiveValue* delay = new nsROCSSPrimitiveValue;
5670 valueList->AppendCSSValue(delay);
5671 delay->SetTime((float)animation->GetDelay() / (float)PR_MSEC_PER_SEC);
5672 } while (++i < display->mAnimationDelayCount);
5674 return valueList;
5677 CSSValue*
5678 nsComputedDOMStyle::DoGetAnimationDuration()
5680 const nsStyleDisplay* display = StyleDisplay();
5682 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5684 NS_ABORT_IF_FALSE(display->mAnimationDurationCount > 0,
5685 "first item must be explicit");
5686 uint32_t i = 0;
5687 do {
5688 const StyleAnimation *animation = &display->mAnimations[i];
5689 nsROCSSPrimitiveValue* duration = new nsROCSSPrimitiveValue;
5690 valueList->AppendCSSValue(duration);
5692 duration->SetTime((float)animation->GetDuration() / (float)PR_MSEC_PER_SEC);
5693 } while (++i < display->mAnimationDurationCount);
5695 return valueList;
5698 CSSValue*
5699 nsComputedDOMStyle::DoGetAnimationTimingFunction()
5701 const nsStyleDisplay* display = StyleDisplay();
5703 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5705 NS_ABORT_IF_FALSE(display->mAnimationTimingFunctionCount > 0,
5706 "first item must be explicit");
5707 uint32_t i = 0;
5708 do {
5709 AppendTimingFunction(valueList,
5710 display->mAnimations[i].GetTimingFunction());
5711 } while (++i < display->mAnimationTimingFunctionCount);
5713 return valueList;
5716 CSSValue*
5717 nsComputedDOMStyle::DoGetAnimationDirection()
5719 const nsStyleDisplay* display = StyleDisplay();
5721 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5723 NS_ABORT_IF_FALSE(display->mAnimationDirectionCount > 0,
5724 "first item must be explicit");
5725 uint32_t i = 0;
5726 do {
5727 const StyleAnimation *animation = &display->mAnimations[i];
5728 nsROCSSPrimitiveValue* direction = new nsROCSSPrimitiveValue;
5729 valueList->AppendCSSValue(direction);
5730 direction->SetIdent(
5731 nsCSSProps::ValueToKeywordEnum(animation->GetDirection(),
5732 nsCSSProps::kAnimationDirectionKTable));
5733 } while (++i < display->mAnimationDirectionCount);
5735 return valueList;
5738 CSSValue*
5739 nsComputedDOMStyle::DoGetAnimationFillMode()
5741 const nsStyleDisplay* display = StyleDisplay();
5743 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5745 NS_ABORT_IF_FALSE(display->mAnimationFillModeCount > 0,
5746 "first item must be explicit");
5747 uint32_t i = 0;
5748 do {
5749 const StyleAnimation *animation = &display->mAnimations[i];
5750 nsROCSSPrimitiveValue* fillMode = new nsROCSSPrimitiveValue;
5751 valueList->AppendCSSValue(fillMode);
5752 fillMode->SetIdent(
5753 nsCSSProps::ValueToKeywordEnum(animation->GetFillMode(),
5754 nsCSSProps::kAnimationFillModeKTable));
5755 } while (++i < display->mAnimationFillModeCount);
5757 return valueList;
5760 CSSValue*
5761 nsComputedDOMStyle::DoGetAnimationIterationCount()
5763 const nsStyleDisplay* display = StyleDisplay();
5765 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5767 NS_ABORT_IF_FALSE(display->mAnimationIterationCountCount > 0,
5768 "first item must be explicit");
5769 uint32_t i = 0;
5770 do {
5771 const StyleAnimation *animation = &display->mAnimations[i];
5772 nsROCSSPrimitiveValue* iterationCount = new nsROCSSPrimitiveValue;
5773 valueList->AppendCSSValue(iterationCount);
5775 float f = animation->GetIterationCount();
5776 /* Need a nasty hack here to work around an optimizer bug in gcc
5777 4.2 on Mac, which somehow gets confused when directly comparing
5778 a float to the return value of NS_IEEEPositiveInfinity when
5779 building 32-bit builds. */
5780 #ifdef XP_MACOSX
5781 volatile
5782 #endif
5783 float inf = NS_IEEEPositiveInfinity();
5784 if (f == inf) {
5785 iterationCount->SetIdent(eCSSKeyword_infinite);
5786 } else {
5787 iterationCount->SetNumber(f);
5789 } while (++i < display->mAnimationIterationCountCount);
5791 return valueList;
5794 CSSValue*
5795 nsComputedDOMStyle::DoGetAnimationPlayState()
5797 const nsStyleDisplay* display = StyleDisplay();
5799 nsDOMCSSValueList *valueList = GetROCSSValueList(true);
5801 NS_ABORT_IF_FALSE(display->mAnimationPlayStateCount > 0,
5802 "first item must be explicit");
5803 uint32_t i = 0;
5804 do {
5805 const StyleAnimation *animation = &display->mAnimations[i];
5806 nsROCSSPrimitiveValue* playState = new nsROCSSPrimitiveValue;
5807 valueList->AppendCSSValue(playState);
5808 playState->SetIdent(
5809 nsCSSProps::ValueToKeywordEnum(animation->GetPlayState(),
5810 nsCSSProps::kAnimationPlayStateKTable));
5811 } while (++i < display->mAnimationPlayStateCount);
5813 return valueList;
5816 static void
5817 MarkComputedStyleMapDirty(const char* aPref, void* aData)
5819 static_cast<nsComputedStyleMap*>(aData)->MarkDirty();
5822 CSSValue*
5823 nsComputedDOMStyle::DoGetCustomProperty(const nsAString& aPropertyName)
5825 MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
5827 const nsStyleVariables* variables = StyleVariables();
5829 nsString variableValue;
5830 const nsAString& name = Substring(aPropertyName,
5831 CSS_CUSTOM_NAME_PREFIX_LENGTH);
5832 if (!variables->mVariables.Get(name, variableValue)) {
5833 return nullptr;
5836 nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
5837 val->SetString(variableValue);
5839 return val;
5842 /* static */ nsComputedStyleMap*
5843 nsComputedDOMStyle::GetComputedStyleMap()
5845 static nsComputedStyleMap map = {
5847 #define COMPUTED_STYLE_PROP(prop_, method_) \
5848 { eCSSProperty_##prop_, &nsComputedDOMStyle::DoGet##method_ },
5849 #include "nsComputedDOMStylePropertyList.h"
5850 #undef COMPUTED_STYLE_PROP
5853 return &map;
5856 /* static */ void
5857 nsComputedDOMStyle::RegisterPrefChangeCallbacks()
5859 // Note that this will register callbacks for all properties with prefs, not
5860 // just those that are implemented on computed style objects, as it's not
5861 // easy to grab specific property data from nsCSSPropList.h based on the
5862 // entries iterated in nsComputedDOMStylePropertyList.h.
5863 nsComputedStyleMap* data = GetComputedStyleMap();
5864 #define REGISTER_CALLBACK(pref_) \
5865 if (pref_[0]) { \
5866 Preferences::RegisterCallback(MarkComputedStyleMapDirty, pref_, data); \
5868 #define CSS_PROP(prop_, id_, method_, flags_, pref_, parsevariant_, \
5869 kwtable_, stylestruct_, stylestructoffset_, animtype_) \
5870 REGISTER_CALLBACK(pref_)
5871 #include "nsCSSPropList.h"
5872 #undef CSS_PROP
5873 #undef REGISTER_CALLBACK
5876 /* static */ void
5877 nsComputedDOMStyle::UnregisterPrefChangeCallbacks()
5879 nsComputedStyleMap* data = GetComputedStyleMap();
5880 #define UNREGISTER_CALLBACK(pref_) \
5881 if (pref_[0]) { \
5882 Preferences::UnregisterCallback(MarkComputedStyleMapDirty, pref_, data); \
5884 #define CSS_PROP(prop_, id_, method_, flags_, pref_, parsevariant_, \
5885 kwtable_, stylestruct_, stylestructoffset_, animtype_) \
5886 UNREGISTER_CALLBACK(pref_)
5887 #include "nsCSSPropList.h"
5888 #undef CSS_PROP
5889 #undef UNREGISTER_CALLBACK