summaryrefslogtreecommitdiffstats
path: root/layout/style/nsComputedDOMStyle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/style/nsComputedDOMStyle.cpp')
-rw-r--r--layout/style/nsComputedDOMStyle.cpp6698
1 files changed, 6698 insertions, 0 deletions
diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp
new file mode 100644
index 000000000..4eb24b76b
--- /dev/null
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -0,0 +1,6698 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* DOM object returned from element.getComputedStyle() */
+
+#include "nsComputedDOMStyle.h"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Preferences.h"
+
+#include "nsError.h"
+#include "nsDOMString.h"
+#include "nsIDOMCSSPrimitiveValue.h"
+#include "nsIFrame.h"
+#include "nsIFrameInlines.h"
+#include "nsStyleContext.h"
+#include "nsIScrollableFrame.h"
+#include "nsContentUtils.h"
+#include "nsIContent.h"
+
+#include "nsDOMCSSRect.h"
+#include "nsDOMCSSRGBColor.h"
+#include "nsDOMCSSValueList.h"
+#include "nsFlexContainerFrame.h"
+#include "nsGridContainerFrame.h"
+#include "nsGkAtoms.h"
+#include "mozilla/ReflowInput.h"
+#include "nsStyleUtil.h"
+#include "nsStyleStructInlines.h"
+#include "nsROCSSPrimitiveValue.h"
+
+#include "nsPresContext.h"
+#include "nsIDocument.h"
+
+#include "nsCSSPseudoElements.h"
+#include "mozilla/StyleSetHandle.h"
+#include "mozilla/StyleSetHandleInlines.h"
+#include "imgIRequest.h"
+#include "nsLayoutUtils.h"
+#include "nsCSSKeywords.h"
+#include "nsStyleCoord.h"
+#include "nsDisplayList.h"
+#include "nsDOMCSSDeclaration.h"
+#include "nsStyleTransformMatrix.h"
+#include "mozilla/dom/Element.h"
+#include "prtime.h"
+#include "nsWrapperCacheInlines.h"
+#include "mozilla/AppUnits.h"
+#include <algorithm>
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+#if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
+#define DEBUG_ComputedDOMStyle
+#endif
+
+/*
+ * This is the implementation of the readonly CSSStyleDeclaration that is
+ * returned by the getComputedStyle() function.
+ */
+
+already_AddRefed<nsComputedDOMStyle>
+NS_NewComputedDOMStyle(dom::Element* aElement, const nsAString& aPseudoElt,
+ nsIPresShell* aPresShell,
+ nsComputedDOMStyle::StyleType aStyleType)
+{
+ RefPtr<nsComputedDOMStyle> computedStyle;
+ computedStyle = new nsComputedDOMStyle(aElement, aPseudoElt, aPresShell,
+ aStyleType);
+ return computedStyle.forget();
+}
+
+/**
+ * An object that represents the ordered set of properties that are exposed on
+ * an nsComputedDOMStyle object and how their computed values can be obtained.
+ */
+struct nsComputedStyleMap
+{
+ friend class nsComputedDOMStyle;
+
+ struct Entry
+ {
+ // Create a pointer-to-member-function type.
+ typedef already_AddRefed<CSSValue> (nsComputedDOMStyle::*ComputeMethod)();
+
+ nsCSSPropertyID mProperty;
+ ComputeMethod mGetter;
+
+ bool IsLayoutFlushNeeded() const
+ {
+ return nsCSSProps::PropHasFlags(mProperty,
+ CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH);
+ }
+
+ bool IsEnabled() const
+ {
+ return nsCSSProps::IsEnabled(mProperty, CSSEnabledState::eForAllContent);
+ }
+ };
+
+ // We define this enum just to count the total number of properties that can
+ // be exposed on an nsComputedDOMStyle, including properties that may be
+ // disabled.
+ enum {
+#define COMPUTED_STYLE_PROP(prop_, method_) \
+ eComputedStyleProperty_##prop_,
+#include "nsComputedDOMStylePropertyList.h"
+#undef COMPUTED_STYLE_PROP
+ eComputedStyleProperty_COUNT
+ };
+
+ /**
+ * Returns the number of properties that should be exposed on an
+ * nsComputedDOMStyle, ecxluding any disabled properties.
+ */
+ uint32_t Length()
+ {
+ Update();
+ return mExposedPropertyCount;
+ }
+
+ /**
+ * Returns the property at the given index in the list of properties
+ * that should be exposed on an nsComputedDOMStyle, excluding any
+ * disabled properties.
+ */
+ nsCSSPropertyID PropertyAt(uint32_t aIndex)
+ {
+ Update();
+ return kEntries[EntryIndex(aIndex)].mProperty;
+ }
+
+ /**
+ * Searches for and returns the computed style map entry for the given
+ * property, or nullptr if the property is not exposed on nsComputedDOMStyle
+ * or is currently disabled.
+ */
+ const Entry* FindEntryForProperty(nsCSSPropertyID aPropID)
+ {
+ Update();
+ for (uint32_t i = 0; i < mExposedPropertyCount; i++) {
+ const Entry* entry = &kEntries[EntryIndex(i)];
+ if (entry->mProperty == aPropID) {
+ return entry;
+ }
+ }
+ return nullptr;
+ }
+
+ /**
+ * Records that mIndexMap needs updating, due to prefs changing that could
+ * affect the set of properties exposed on an nsComputedDOMStyle.
+ */
+ void MarkDirty() { mExposedPropertyCount = 0; }
+
+ // The member variables are public so that we can use an initializer in
+ // nsComputedDOMStyle::GetComputedStyleMap. Use the member functions
+ // above to get information from this object.
+
+ /**
+ * An entry for each property that can be exposed on an nsComputedDOMStyle.
+ */
+ const Entry kEntries[eComputedStyleProperty_COUNT];
+
+ /**
+ * The number of properties that should be exposed on an nsComputedDOMStyle.
+ * This will be less than eComputedStyleProperty_COUNT if some property
+ * prefs are disabled. A value of 0 indicates that it and mIndexMap are out
+ * of date.
+ */
+ uint32_t mExposedPropertyCount;
+
+ /**
+ * A map of indexes on the nsComputedDOMStyle object to indexes into kEntries.
+ */
+ uint32_t mIndexMap[eComputedStyleProperty_COUNT];
+
+private:
+ /**
+ * Returns whether mExposedPropertyCount and mIndexMap are out of date.
+ */
+ bool IsDirty() { return mExposedPropertyCount == 0; }
+
+ /**
+ * Updates mExposedPropertyCount and mIndexMap to take into account properties
+ * whose prefs are currently disabled.
+ */
+ void Update();
+
+ /**
+ * Maps an nsComputedDOMStyle indexed getter index to an index into kEntries.
+ */
+ uint32_t EntryIndex(uint32_t aIndex) const
+ {
+ MOZ_ASSERT(aIndex < mExposedPropertyCount);
+ return mIndexMap[aIndex];
+ }
+};
+
+void
+nsComputedStyleMap::Update()
+{
+ if (!IsDirty()) {
+ return;
+ }
+
+ uint32_t index = 0;
+ for (uint32_t i = 0; i < eComputedStyleProperty_COUNT; i++) {
+ if (kEntries[i].IsEnabled()) {
+ mIndexMap[index++] = i;
+ }
+ }
+ mExposedPropertyCount = index;
+}
+
+nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement,
+ const nsAString& aPseudoElt,
+ nsIPresShell* aPresShell,
+ StyleType aStyleType)
+ : mDocumentWeak(nullptr)
+ , mOuterFrame(nullptr)
+ , mInnerFrame(nullptr)
+ , mPresShell(nullptr)
+ , mStyleType(aStyleType)
+ , mStyleContextGeneration(0)
+ , mExposeVisitedStyle(false)
+ , mResolvedStyleContext(false)
+{
+ MOZ_ASSERT(aElement && aPresShell);
+
+ mDocumentWeak = do_GetWeakReference(aPresShell->GetDocument());
+
+ mContent = aElement;
+
+ if (!DOMStringIsNull(aPseudoElt) && !aPseudoElt.IsEmpty() &&
+ aPseudoElt.First() == char16_t(':')) {
+ // deal with two-colon forms of aPseudoElt
+ nsAString::const_iterator start, end;
+ aPseudoElt.BeginReading(start);
+ aPseudoElt.EndReading(end);
+ NS_ASSERTION(start != end, "aPseudoElt is not empty!");
+ ++start;
+ bool haveTwoColons = true;
+ if (start == end || *start != char16_t(':')) {
+ --start;
+ haveTwoColons = false;
+ }
+ mPseudo = NS_Atomize(Substring(start, end));
+ MOZ_ASSERT(mPseudo);
+
+ // There aren't any non-CSS2 pseudo-elements with a single ':'
+ if (!haveTwoColons &&
+ (!nsCSSPseudoElements::IsPseudoElement(mPseudo) ||
+ !nsCSSPseudoElements::IsCSS2PseudoElement(mPseudo))) {
+ // XXXbz I'd really rather we threw an exception or something, but
+ // the DOM spec sucks.
+ mPseudo = nullptr;
+ }
+ }
+
+ MOZ_ASSERT(aPresShell->GetPresContext());
+}
+
+nsComputedDOMStyle::~nsComputedDOMStyle()
+{
+ ClearStyleContext();
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsComputedDOMStyle)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsComputedDOMStyle)
+ tmp->ClearStyleContext(); // remove observer before clearing mContent
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsComputedDOMStyle)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsComputedDOMStyle)
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle)
+ return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsComputedDOMStyle)
+ return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsComputedDOMStyle)
+ return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
+// QueryInterface implementation for nsComputedDOMStyle
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsComputedDOMStyle)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
+
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsComputedDOMStyle)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsComputedDOMStyle)
+
+NS_IMETHODIMP
+nsComputedDOMStyle::GetPropertyValue(const nsCSSPropertyID aPropID,
+ nsAString& aValue)
+{
+ // This is mostly to avoid code duplication with GetPropertyCSSValue(); if
+ // perf ever becomes an issue here (doubtful), we can look into changing
+ // this.
+ return GetPropertyValue(
+ NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(aPropID)),
+ aValue);
+}
+
+NS_IMETHODIMP
+nsComputedDOMStyle::SetPropertyValue(const nsCSSPropertyID aPropID,
+ const nsAString& aValue)
+{
+ return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+}
+
+NS_IMETHODIMP
+nsComputedDOMStyle::GetCssText(nsAString& aCssText)
+{
+ aCssText.Truncate();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComputedDOMStyle::SetCssText(const nsAString& aCssText)
+{
+ return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+}
+
+NS_IMETHODIMP
+nsComputedDOMStyle::GetLength(uint32_t* aLength)
+{
+ NS_PRECONDITION(aLength, "Null aLength! Prepare to die!");
+
+ uint32_t length = GetComputedStyleMap()->Length();
+
+ // Make sure we have up to date style so that we can include custom
+ // properties.
+ UpdateCurrentStyleSources(false);
+ if (mStyleContext) {
+ length += StyleVariables()->mVariables.Count();
+ }
+
+ *aLength = length;
+
+ ClearCurrentStyleSources();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComputedDOMStyle::GetParentRule(nsIDOMCSSRule** aParentRule)
+{
+ *aParentRule = nullptr;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComputedDOMStyle::GetPropertyValue(const nsAString& aPropertyName,
+ nsAString& aReturn)
+{
+ aReturn.Truncate();
+
+ ErrorResult error;
+ RefPtr<CSSValue> val = GetPropertyCSSValue(aPropertyName, error);
+ if (error.Failed()) {
+ return error.StealNSResult();
+ }
+
+ if (val) {
+ nsString text;
+ val->GetCssText(text, error);
+ aReturn.Assign(text);
+ return error.StealNSResult();
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComputedDOMStyle::GetAuthoredPropertyValue(const nsAString& aPropertyName,
+ nsAString& aReturn)
+{
+ // Authored style doesn't make sense to return from computed DOM style,
+ // so just return whatever GetPropertyValue() returns.
+ return GetPropertyValue(aPropertyName, aReturn);
+}
+
+/* static */
+already_AddRefed<nsStyleContext>
+nsComputedDOMStyle::GetStyleContextForElement(Element* aElement,
+ nsIAtom* aPseudo,
+ nsIPresShell* aPresShell,
+ StyleType aStyleType)
+{
+ // If the content has a pres shell, we must use it. Otherwise we'd
+ // potentially mix rule trees by using the wrong pres shell's style
+ // set. Using the pres shell from the content also means that any
+ // content that's actually *in* a document will get the style from the
+ // correct document.
+ nsCOMPtr<nsIPresShell> presShell = GetPresShellForContent(aElement);
+ if (!presShell) {
+ presShell = aPresShell;
+ if (!presShell)
+ return nullptr;
+ }
+
+ presShell->FlushPendingNotifications(Flush_Style);
+
+ return GetStyleContextForElementNoFlush(aElement, aPseudo, presShell,
+ aStyleType);
+}
+
+/* static */
+already_AddRefed<nsStyleContext>
+nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
+ nsIAtom* aPseudo,
+ nsIPresShell* aPresShell,
+ StyleType aStyleType)
+{
+ MOZ_ASSERT(aElement, "NULL element");
+ // If the content has a pres shell, we must use it. Otherwise we'd
+ // potentially mix rule trees by using the wrong pres shell's style
+ // set. Using the pres shell from the content also means that any
+ // content that's actually *in* a document will get the style from the
+ // correct document.
+ nsIPresShell *presShell = GetPresShellForContent(aElement);
+ bool inDocWithShell = true;
+ if (!presShell) {
+ inDocWithShell = false;
+ presShell = aPresShell;
+ if (!presShell)
+ return nullptr;
+ }
+
+ // XXX the !aElement->IsHTMLElement(nsGkAtoms::area)
+ // check is needed due to bug 135040 (to avoid using
+ // mPrimaryFrame). Remove it once that's fixed.
+ if (!aPseudo && aStyleType == eAll && inDocWithShell &&
+ !aElement->IsHTMLElement(nsGkAtoms::area)) {
+ nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
+ if (frame) {
+ nsStyleContext* result = frame->StyleContext();
+ // Don't use the style context if it was influenced by
+ // pseudo-elements, since then it's not the primary style
+ // for this element.
+ if (!result->HasPseudoElementData()) {
+ // this function returns an addrefed style context
+ RefPtr<nsStyleContext> ret = result;
+ return ret.forget();
+ }
+ }
+ }
+
+ // No frame has been created, or we have a pseudo, or we're looking
+ // for the default style, so resolve the style ourselves.
+ RefPtr<nsStyleContext> parentContext;
+ nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
+ // Don't resolve parent context for document fragments.
+ if (parent && parent->IsElement())
+ parentContext = GetStyleContextForElementNoFlush(parent->AsElement(),
+ nullptr, presShell,
+ aStyleType);
+
+ nsPresContext *presContext = presShell->GetPresContext();
+ if (!presContext)
+ return nullptr;
+
+ StyleSetHandle styleSet = presShell->StyleSet();
+
+ RefPtr<nsStyleContext> sc;
+ if (aPseudo) {
+ CSSPseudoElementType type = nsCSSPseudoElements::
+ GetPseudoType(aPseudo, CSSEnabledState::eIgnoreEnabledState);
+ if (type >= CSSPseudoElementType::Count) {
+ return nullptr;
+ }
+ nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
+ Element* pseudoElement =
+ frame && inDocWithShell ? frame->GetPseudoElement(type) : nullptr;
+ sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext,
+ pseudoElement);
+ } else {
+ sc = styleSet->ResolveStyleFor(aElement, parentContext);
+ }
+
+ if (aStyleType == eDefaultOnly) {
+ if (styleSet->IsServo()) {
+ NS_ERROR("stylo: ServoStyleSets cannot supply UA-only styles yet");
+ return nullptr;
+ }
+
+ // We really only want the user and UA rules. Filter out the other ones.
+ nsTArray< nsCOMPtr<nsIStyleRule> > rules;
+ for (nsRuleNode* ruleNode = sc->RuleNode();
+ !ruleNode->IsRoot();
+ ruleNode = ruleNode->GetParent()) {
+ if (ruleNode->GetLevel() == SheetType::Agent ||
+ ruleNode->GetLevel() == SheetType::User) {
+ rules.AppendElement(ruleNode->GetRule());
+ }
+ }
+
+ // We want to build a list of user/ua rules that is in order from least to
+ // most important, so we have to reverse the list.
+ // Integer division to get "stop" is purposeful here: if length is odd, we
+ // don't have to do anything with the middle element of the array.
+ for (uint32_t i = 0, length = rules.Length(), stop = length / 2;
+ i < stop; ++i) {
+ rules[i].swap(rules[length - i - 1]);
+ }
+
+ sc = styleSet->AsGecko()->ResolveStyleForRules(parentContext, rules);
+ }
+
+ return sc.forget();
+}
+
+nsMargin
+nsComputedDOMStyle::GetAdjustedValuesForBoxSizing()
+{
+ // We want the width/height of whatever parts 'width' or 'height' controls,
+ // which can be different depending on the value of the 'box-sizing' property.
+ const nsStylePosition* stylePos = StylePosition();
+
+ nsMargin adjustment;
+ if (stylePos->mBoxSizing == StyleBoxSizing::Border) {
+ adjustment = mInnerFrame->GetUsedBorderAndPadding();
+ }
+
+ return adjustment;
+}
+
+/* static */
+nsIPresShell*
+nsComputedDOMStyle::GetPresShellForContent(nsIContent* aContent)
+{
+ nsIDocument* composedDoc = aContent->GetComposedDoc();
+ if (!composedDoc)
+ return nullptr;
+
+ return composedDoc->GetShell();
+}
+
+// nsDOMCSSDeclaration abstract methods which should never be called
+// on a nsComputedDOMStyle object, but must be defined to avoid
+// compile errors.
+DeclarationBlock*
+nsComputedDOMStyle::GetCSSDeclaration(Operation)
+{
+ NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSDeclaration");
+ return nullptr;
+}
+
+nsresult
+nsComputedDOMStyle::SetCSSDeclaration(DeclarationBlock*)
+{
+ NS_RUNTIMEABORT("called nsComputedDOMStyle::SetCSSDeclaration");
+ return NS_ERROR_FAILURE;
+}
+
+nsIDocument*
+nsComputedDOMStyle::DocToUpdate()
+{
+ NS_RUNTIMEABORT("called nsComputedDOMStyle::DocToUpdate");
+ return nullptr;
+}
+
+void
+nsComputedDOMStyle::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
+{
+ NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSParsingEnvironment");
+ // Just in case NS_RUNTIMEABORT ever stops killing us for some reason
+ aCSSParseEnv.mPrincipal = nullptr;
+}
+
+void
+nsComputedDOMStyle::ClearStyleContext()
+{
+ if (mResolvedStyleContext) {
+ mResolvedStyleContext = false;
+ mContent->RemoveMutationObserver(this);
+ }
+ mStyleContext = nullptr;
+}
+
+void
+nsComputedDOMStyle::SetResolvedStyleContext(RefPtr<nsStyleContext>&& aContext)
+{
+ if (!mResolvedStyleContext) {
+ mResolvedStyleContext = true;
+ mContent->AddMutationObserver(this);
+ }
+ mStyleContext = aContext;
+}
+
+void
+nsComputedDOMStyle::SetFrameStyleContext(nsStyleContext* aContext)
+{
+ ClearStyleContext();
+ mStyleContext = aContext;
+}
+
+void
+nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
+{
+ nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocumentWeak);
+ if (!document) {
+ ClearStyleContext();
+ return;
+ }
+
+ document->FlushPendingLinkUpdates();
+
+ // Flush _before_ getting the presshell, since that could create a new
+ // presshell. Also note that we want to flush the style on the document
+ // we're computing style in, not on the document mContent is in -- the two
+ // may be different.
+ document->FlushPendingNotifications(
+ aNeedsLayoutFlush ? Flush_Layout : Flush_Style);
+#ifdef DEBUG
+ mFlushedPendingReflows = aNeedsLayoutFlush;
+#endif
+
+ nsCOMPtr<nsIPresShell> presShellForContent = GetPresShellForContent(mContent);
+ if (presShellForContent && presShellForContent != document->GetShell()) {
+ presShellForContent->FlushPendingNotifications(Flush_Style);
+ }
+
+ mPresShell = document->GetShell();
+ if (!mPresShell || !mPresShell->GetPresContext()) {
+ ClearStyleContext();
+ return;
+ }
+
+ uint64_t currentGeneration =
+ mPresShell->GetPresContext()->GetRestyleGeneration();
+
+ if (mStyleContext) {
+ if (mStyleContextGeneration == currentGeneration) {
+ // Our cached style context is still valid.
+ return;
+ }
+ // We've processed some restyles, so the cached style context might
+ // be out of date.
+ mStyleContext = nullptr;
+ }
+
+ // XXX the !mContent->IsHTMLElement(nsGkAtoms::area)
+ // check is needed due to bug 135040 (to avoid using
+ // mPrimaryFrame). Remove it once that's fixed.
+ if (!mPseudo && mStyleType == eAll &&
+ !mContent->IsHTMLElement(nsGkAtoms::area)) {
+ mOuterFrame = mContent->GetPrimaryFrame();
+ mInnerFrame = mOuterFrame;
+ if (mOuterFrame) {
+ nsIAtom* type = mOuterFrame->GetType();
+ if (type == nsGkAtoms::tableWrapperFrame) {
+ // If the frame is a table wrapper frame then we should get the style
+ // from the inner table frame.
+ mInnerFrame = mOuterFrame->PrincipalChildList().FirstChild();
+ NS_ASSERTION(mInnerFrame, "table wrapper must have an inner");
+ NS_ASSERTION(!mInnerFrame->GetNextSibling(),
+ "table wrapper frames should have just one child, "
+ "the inner table");
+ }
+
+ SetFrameStyleContext(mInnerFrame->StyleContext());
+ NS_ASSERTION(mStyleContext, "Frame without style context?");
+ }
+ }
+
+ if (!mStyleContext || mStyleContext->HasPseudoElementData()) {
+#ifdef DEBUG
+ if (mStyleContext) {
+ // We want to check that going through this path because of
+ // HasPseudoElementData is rare, because it slows us down a good
+ // bit. So check that we're really inside something associated
+ // with a pseudo-element that contains elements.
+ nsStyleContext* topWithPseudoElementData = mStyleContext;
+ while (topWithPseudoElementData->GetParent()->HasPseudoElementData()) {
+ topWithPseudoElementData = topWithPseudoElementData->GetParent();
+ }
+ CSSPseudoElementType pseudo = topWithPseudoElementData->GetPseudoType();
+ nsIAtom* pseudoAtom = nsCSSPseudoElements::GetPseudoAtom(pseudo);
+ nsAutoString assertMsg(
+ NS_LITERAL_STRING("we should be in a pseudo-element that is expected to contain elements ("));
+ assertMsg.Append(nsDependentString(pseudoAtom->GetUTF16String()));
+ assertMsg.Append(')');
+ NS_ASSERTION(nsCSSPseudoElements::PseudoElementContainsElements(pseudo),
+ NS_LossyConvertUTF16toASCII(assertMsg).get());
+ }
+#endif
+ // Need to resolve a style context
+ RefPtr<nsStyleContext> resolvedStyleContext =
+ nsComputedDOMStyle::GetStyleContextForElementNoFlush(
+ mContent->AsElement(),
+ mPseudo,
+ presShellForContent ? presShellForContent.get() : mPresShell,
+ mStyleType);
+ if (!resolvedStyleContext) {
+ ClearStyleContext();
+ return;
+ }
+
+ // No need to re-get the generation, even though GetStyleContextForElement
+ // will flush, since we flushed style at the top of this function.
+ NS_ASSERTION(mPresShell &&
+ currentGeneration ==
+ mPresShell->GetPresContext()->GetRestyleGeneration(),
+ "why should we have flushed style again?");
+
+ SetResolvedStyleContext(Move(resolvedStyleContext));
+ NS_ASSERTION(mPseudo || !mStyleContext->HasPseudoElementData(),
+ "should not have pseudo-element data");
+ }
+
+ // mExposeVisitedStyle is set to true only by testing APIs that
+ // require chrome privilege.
+ MOZ_ASSERT(!mExposeVisitedStyle || nsContentUtils::IsCallerChrome(),
+ "mExposeVisitedStyle set incorrectly");
+ if (mExposeVisitedStyle && mStyleContext->RelevantLinkVisited()) {
+ nsStyleContext *styleIfVisited = mStyleContext->GetStyleIfVisited();
+ if (styleIfVisited) {
+ mStyleContext = styleIfVisited;
+ }
+ }
+}
+
+void
+nsComputedDOMStyle::ClearCurrentStyleSources()
+{
+ mOuterFrame = nullptr;
+ mInnerFrame = nullptr;
+ mPresShell = nullptr;
+
+ // Release the current style context if we got it off the frame.
+ // For a style context we resolved, keep it around so that we
+ // can re-use it next time this object is queried.
+ if (!mResolvedStyleContext) {
+ mStyleContext = nullptr;
+ }
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetPropertyCSSValue(const nsAString& aPropertyName, ErrorResult& aRv)
+{
+ nsCSSPropertyID prop =
+ nsCSSProps::LookupProperty(aPropertyName, CSSEnabledState::eForAllContent);
+
+ bool needsLayoutFlush;
+ nsComputedStyleMap::Entry::ComputeMethod getter;
+
+ if (prop == eCSSPropertyExtra_variable) {
+ needsLayoutFlush = false;
+ getter = nullptr;
+ } else {
+ // We don't (for now, anyway, though it may make sense to change it
+ // for all aliases, including those in nsCSSPropAliasList) want
+ // aliases to be enumerable (via GetLength and IndexedGetter), so
+ // handle them here rather than adding entries to
+ // GetQueryablePropertyMap.
+ if (prop != eCSSProperty_UNKNOWN &&
+ nsCSSProps::PropHasFlags(prop, CSS_PROPERTY_IS_ALIAS)) {
+ const nsCSSPropertyID* subprops = nsCSSProps::SubpropertyEntryFor(prop);
+ MOZ_ASSERT(subprops[1] == eCSSProperty_UNKNOWN,
+ "must have list of length 1");
+ prop = subprops[0];
+ }
+
+ const nsComputedStyleMap::Entry* propEntry =
+ GetComputedStyleMap()->FindEntryForProperty(prop);
+
+ if (!propEntry) {
+#ifdef DEBUG_ComputedDOMStyle
+ NS_WARNING(PromiseFlatCString(NS_ConvertUTF16toUTF8(aPropertyName) +
+ NS_LITERAL_CSTRING(" is not queryable!")).get());
+#endif
+
+ // NOTE: For branches, we should flush here for compatibility!
+ return nullptr;
+ }
+
+ needsLayoutFlush = propEntry->IsLayoutFlushNeeded();
+ getter = propEntry->mGetter;
+ }
+
+ UpdateCurrentStyleSources(needsLayoutFlush);
+ if (!mStyleContext) {
+ aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+ return nullptr;
+ }
+
+ RefPtr<CSSValue> val;
+ if (prop == eCSSPropertyExtra_variable) {
+ val = DoGetCustomProperty(aPropertyName);
+ } else {
+ // Call our pointer-to-member-function.
+ val = (this->*getter)();
+ }
+
+ ClearCurrentStyleSources();
+
+ return val.forget();
+}
+
+NS_IMETHODIMP
+nsComputedDOMStyle::RemoveProperty(const nsAString& aPropertyName,
+ nsAString& aReturn)
+{
+ return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+}
+
+
+NS_IMETHODIMP
+nsComputedDOMStyle::GetPropertyPriority(const nsAString& aPropertyName,
+ nsAString& aReturn)
+{
+ aReturn.Truncate();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComputedDOMStyle::SetProperty(const nsAString& aPropertyName,
+ const nsAString& aValue,
+ const nsAString& aPriority)
+{
+ return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+}
+
+NS_IMETHODIMP
+nsComputedDOMStyle::Item(uint32_t aIndex, nsAString& aReturn)
+{
+ return nsDOMCSSDeclaration::Item(aIndex, aReturn);
+}
+
+void
+nsComputedDOMStyle::IndexedGetter(uint32_t aIndex,
+ bool& aFound,
+ nsAString& aPropName)
+{
+ nsComputedStyleMap* map = GetComputedStyleMap();
+ uint32_t length = map->Length();
+
+ if (aIndex < length) {
+ aFound = true;
+ CopyASCIItoUTF16(nsCSSProps::GetStringValue(map->PropertyAt(aIndex)),
+ aPropName);
+ return;
+ }
+
+ // Custom properties are exposed with indexed properties just after all
+ // of the built-in properties.
+ UpdateCurrentStyleSources(false);
+ if (!mStyleContext) {
+ aFound = false;
+ return;
+ }
+
+ const nsStyleVariables* variables = StyleVariables();
+ if (aIndex - length < variables->mVariables.Count()) {
+ aFound = true;
+ nsString varName;
+ variables->mVariables.GetVariableAt(aIndex - length, varName);
+ aPropName.AssignLiteral("--");
+ aPropName.Append(varName);
+ } else {
+ aFound = false;
+ }
+
+ ClearCurrentStyleSources();
+}
+
+// Property getters...
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBinding()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleDisplay* display = StyleDisplay();
+
+ if (display->mBinding) {
+ val->SetURI(display->mBinding->GetURI());
+ } else {
+ val->SetIdent(eCSSKeyword_none);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetClear()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakType,
+ nsCSSProps::kClearKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFloat()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mFloat,
+ nsCSSProps::kFloatKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBottom()
+{
+ return GetOffsetWidthFor(NS_SIDE_BOTTOM);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetStackSizing()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(StyleXUL()->mStretchStack ? eCSSKeyword_stretch_to_fit :
+ eCSSKeyword_ignore);
+ return val.forget();
+}
+
+void
+nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue,
+ nscolor aColor)
+{
+ if (NS_GET_A(aColor) == 0) {
+ aValue->SetIdent(eCSSKeyword_transparent);
+ return;
+ }
+
+ nsROCSSPrimitiveValue *red = new nsROCSSPrimitiveValue;
+ nsROCSSPrimitiveValue *green = new nsROCSSPrimitiveValue;
+ nsROCSSPrimitiveValue *blue = new nsROCSSPrimitiveValue;
+ nsROCSSPrimitiveValue *alpha = new nsROCSSPrimitiveValue;
+
+ uint8_t a = NS_GET_A(aColor);
+ nsDOMCSSRGBColor *rgbColor =
+ new nsDOMCSSRGBColor(red, green, blue, alpha, a < 255);
+
+ red->SetNumber(NS_GET_R(aColor));
+ green->SetNumber(NS_GET_G(aColor));
+ blue->SetNumber(NS_GET_B(aColor));
+ alpha->SetNumber(nsStyleUtil::ColorComponentToFloat(a));
+
+ aValue->SetColor(rgbColor);
+}
+
+void
+nsComputedDOMStyle::SetValueFromComplexColor(nsROCSSPrimitiveValue* aValue,
+ const StyleComplexColor& aColor)
+{
+ SetToRGBAColor(aValue, StyleColor()->CalcComplexColor(aColor));
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetToRGBAColor(val, StyleColor()->mColor);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColorAdjust()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mColorAdjust,
+ nsCSSProps::kColorAdjustKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOpacity()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StyleEffects()->mOpacity);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColumnCount()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleColumn* column = StyleColumn();
+
+ if (column->mColumnCount == NS_STYLE_COLUMN_COUNT_AUTO) {
+ val->SetIdent(eCSSKeyword_auto);
+ } else {
+ val->SetNumber(column->mColumnCount);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColumnWidth()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ // XXX fix the auto case. When we actually have a column frame, I think
+ // we should return the computed column width.
+ SetValueToCoord(val, StyleColumn()->mColumnWidth, true);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColumnGap()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleColumn* column = StyleColumn();
+ if (column->mColumnGap.GetUnit() == eStyleUnit_Normal) {
+ val->SetAppUnits(StyleFont()->mFont.size);
+ } else {
+ SetValueToCoord(val, StyleColumn()->mColumnGap, true);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColumnFill()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnFill,
+ nsCSSProps::kColumnFillKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColumnRuleWidth()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetAppUnits(StyleColumn()->GetComputedColumnRuleWidth());
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColumnRuleStyle()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnRuleStyle,
+ nsCSSProps::kBorderStyleKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColumnRuleColor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueFromComplexColor(val, StyleColumn()->mColumnRuleColor);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetContent()
+{
+ const nsStyleContent *content = StyleContent();
+
+ if (content->ContentCount() == 0) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ }
+
+ if (content->ContentCount() == 1 &&
+ content->ContentAt(0).mType == eStyleContentType_AltContent) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword__moz_alt_content);
+ return val.forget();
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ for (uint32_t i = 0, i_end = content->ContentCount(); i < i_end; ++i) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleContentData &data = content->ContentAt(i);
+ switch (data.mType) {
+ case eStyleContentType_String:
+ {
+ nsAutoString str;
+ nsStyleUtil::AppendEscapedCSSString(
+ nsDependentString(data.mContent.mString), str);
+ val->SetString(str);
+ }
+ break;
+ case eStyleContentType_Image:
+ {
+ nsCOMPtr<nsIURI> uri;
+ if (data.mContent.mImage) {
+ data.mContent.mImage->GetURI(getter_AddRefs(uri));
+ }
+ val->SetURI(uri);
+ }
+ break;
+ case eStyleContentType_Attr:
+ {
+ nsAutoString str;
+ nsStyleUtil::AppendEscapedCSSIdent(
+ nsDependentString(data.mContent.mString), str);
+ val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_ATTR);
+ }
+ break;
+ case eStyleContentType_Counter:
+ case eStyleContentType_Counters:
+ {
+ /* FIXME: counters should really use an object */
+ nsAutoString str;
+ if (data.mType == eStyleContentType_Counter) {
+ str.AppendLiteral("counter(");
+ }
+ else {
+ str.AppendLiteral("counters(");
+ }
+ // WRITE ME
+ nsCSSValue::Array *a = data.mContent.mCounters;
+
+ nsStyleUtil::AppendEscapedCSSIdent(
+ nsDependentString(a->Item(0).GetStringBufferValue()), str);
+ int32_t typeItem = 1;
+ if (data.mType == eStyleContentType_Counters) {
+ typeItem = 2;
+ str.AppendLiteral(", ");
+ nsStyleUtil::AppendEscapedCSSString(
+ nsDependentString(a->Item(1).GetStringBufferValue()), str);
+ }
+ MOZ_ASSERT(eCSSUnit_None != a->Item(typeItem).GetUnit(),
+ "'none' should be handled as identifier value");
+ nsString type;
+ a->Item(typeItem).AppendToString(eCSSProperty_list_style_type,
+ type, nsCSSValue::eNormalized);
+ if (!type.LowerCaseEqualsLiteral("decimal")) {
+ str.AppendLiteral(", ");
+ str.Append(type);
+ }
+
+ str.Append(char16_t(')'));
+ val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_COUNTER);
+ }
+ break;
+ case eStyleContentType_OpenQuote:
+ val->SetIdent(eCSSKeyword_open_quote);
+ break;
+ case eStyleContentType_CloseQuote:
+ val->SetIdent(eCSSKeyword_close_quote);
+ break;
+ case eStyleContentType_NoOpenQuote:
+ val->SetIdent(eCSSKeyword_no_open_quote);
+ break;
+ case eStyleContentType_NoCloseQuote:
+ val->SetIdent(eCSSKeyword_no_close_quote);
+ break;
+ case eStyleContentType_AltContent:
+ default:
+ NS_NOTREACHED("unexpected type");
+ break;
+ }
+ valueList->AppendCSSValue(val.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetCounterIncrement()
+{
+ const nsStyleContent *content = StyleContent();
+
+ if (content->CounterIncrementCount() == 0) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ for (uint32_t i = 0, i_end = content->CounterIncrementCount(); i < i_end; ++i) {
+ RefPtr<nsROCSSPrimitiveValue> name = new nsROCSSPrimitiveValue;
+ RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
+
+ const nsStyleCounterData& data = content->CounterIncrementAt(i);
+ nsAutoString escaped;
+ nsStyleUtil::AppendEscapedCSSIdent(data.mCounter, escaped);
+ name->SetString(escaped);
+ value->SetNumber(data.mValue); // XXX This should really be integer
+
+ valueList->AppendCSSValue(name.forget());
+ valueList->AppendCSSValue(value.forget());
+ }
+
+ return valueList.forget();
+}
+
+/* Convert the stored representation into a list of two values and then hand
+ * it back.
+ */
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTransformOrigin()
+{
+ /* We need to build up a list of two values. We'll call them
+ * width and height.
+ */
+
+ /* Store things as a value list */
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ /* Now, get the values. */
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsROCSSPrimitiveValue> width = new nsROCSSPrimitiveValue;
+ SetValueToCoord(width, display->mTransformOrigin[0], false,
+ &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
+ valueList->AppendCSSValue(width.forget());
+
+ RefPtr<nsROCSSPrimitiveValue> height = new nsROCSSPrimitiveValue;
+ SetValueToCoord(height, display->mTransformOrigin[1], false,
+ &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
+ valueList->AppendCSSValue(height.forget());
+
+ if (display->mTransformOrigin[2].GetUnit() != eStyleUnit_Coord ||
+ display->mTransformOrigin[2].GetCoordValue() != 0) {
+ RefPtr<nsROCSSPrimitiveValue> depth = new nsROCSSPrimitiveValue;
+ SetValueToCoord(depth, display->mTransformOrigin[2], false,
+ nullptr);
+ valueList->AppendCSSValue(depth.forget());
+ }
+
+ return valueList.forget();
+}
+
+/* Convert the stored representation into a list of two values and then hand
+ * it back.
+ */
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPerspectiveOrigin()
+{
+ /* We need to build up a list of two values. We'll call them
+ * width and height.
+ */
+
+ /* Store things as a value list */
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ /* Now, get the values. */
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsROCSSPrimitiveValue> width = new nsROCSSPrimitiveValue;
+ SetValueToCoord(width, display->mPerspectiveOrigin[0], false,
+ &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
+ valueList->AppendCSSValue(width.forget());
+
+ RefPtr<nsROCSSPrimitiveValue> height = new nsROCSSPrimitiveValue;
+ SetValueToCoord(height, display->mPerspectiveOrigin[1], false,
+ &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
+ valueList->AppendCSSValue(height.forget());
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPerspective()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StyleDisplay()->mChildPerspective, false);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackfaceVisibility()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBackfaceVisibility,
+ nsCSSProps::kBackfaceVisibilityKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTransformStyle()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mTransformStyle,
+ nsCSSProps::kTransformStyleKTable));
+ return val.forget();
+}
+
+/* If the property is "none", hand back "none" wrapped in a value.
+ * Otherwise, compute the aggregate transform matrix and hands it back in a
+ * "matrix" wrapper.
+ */
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTransform()
+{
+ /* First, get the display data. We'll need it. */
+ const nsStyleDisplay* display = StyleDisplay();
+
+ /* If there are no transforms, then we should construct a single-element
+ * entry and hand it back.
+ */
+ if (!display->mSpecifiedTransform) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ /* Set it to "none." */
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ }
+
+ /* Otherwise, we need to compute the current value of the transform matrix,
+ * store it in a string, and hand it back to the caller.
+ */
+
+ /* Use the inner frame for the reference box. If we don't have an inner
+ * frame we use empty dimensions to allow us to continue (and percentage
+ * values in the transform will simply give broken results).
+ * TODO: There is no good way for us to represent the case where there's no
+ * frame, which is problematic. The reason is that when we have percentage
+ * transforms, there are a total of four stored matrix entries that influence
+ * the transform based on the size of the element. However, this poses a
+ * problem, because only two of these values can be explicitly referenced
+ * using the named transforms. Until a real solution is found, we'll just
+ * use this approach.
+ */
+ nsStyleTransformMatrix::TransformReferenceBox refBox(mInnerFrame,
+ nsSize(0, 0));
+
+ RuleNodeCacheConditions dummy;
+ bool dummyBool;
+ gfx::Matrix4x4 matrix =
+ nsStyleTransformMatrix::ReadTransforms(display->mSpecifiedTransform->mHead,
+ mStyleContext,
+ mStyleContext->PresContext(),
+ dummy,
+ refBox,
+ float(mozilla::AppUnitsPerCSSPixel()),
+ &dummyBool);
+
+ return MatrixToCSSValue(matrix);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTransformBox()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mTransformBox,
+ nsCSSProps::kTransformBoxKTable));
+ return val.forget();
+}
+
+/* static */ already_AddRefed<nsROCSSPrimitiveValue>
+nsComputedDOMStyle::MatrixToCSSValue(const mozilla::gfx::Matrix4x4& matrix)
+{
+ bool is3D = !matrix.Is2D();
+
+ nsAutoString resultString(NS_LITERAL_STRING("matrix"));
+ if (is3D) {
+ resultString.AppendLiteral("3d");
+ }
+
+ resultString.Append('(');
+ resultString.AppendFloat(matrix._11);
+ resultString.AppendLiteral(", ");
+ resultString.AppendFloat(matrix._12);
+ resultString.AppendLiteral(", ");
+ if (is3D) {
+ resultString.AppendFloat(matrix._13);
+ resultString.AppendLiteral(", ");
+ resultString.AppendFloat(matrix._14);
+ resultString.AppendLiteral(", ");
+ }
+ resultString.AppendFloat(matrix._21);
+ resultString.AppendLiteral(", ");
+ resultString.AppendFloat(matrix._22);
+ resultString.AppendLiteral(", ");
+ if (is3D) {
+ resultString.AppendFloat(matrix._23);
+ resultString.AppendLiteral(", ");
+ resultString.AppendFloat(matrix._24);
+ resultString.AppendLiteral(", ");
+ resultString.AppendFloat(matrix._31);
+ resultString.AppendLiteral(", ");
+ resultString.AppendFloat(matrix._32);
+ resultString.AppendLiteral(", ");
+ resultString.AppendFloat(matrix._33);
+ resultString.AppendLiteral(", ");
+ resultString.AppendFloat(matrix._34);
+ resultString.AppendLiteral(", ");
+ }
+ resultString.AppendFloat(matrix._41);
+ resultString.AppendLiteral(", ");
+ resultString.AppendFloat(matrix._42);
+ if (is3D) {
+ resultString.AppendLiteral(", ");
+ resultString.AppendFloat(matrix._43);
+ resultString.AppendLiteral(", ");
+ resultString.AppendFloat(matrix._44);
+ }
+ resultString.Append(')');
+
+ /* Create a value to hold our result. */
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ val->SetString(resultString);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetCounterReset()
+{
+ const nsStyleContent *content = StyleContent();
+
+ if (content->CounterResetCount() == 0) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ for (uint32_t i = 0, i_end = content->CounterResetCount(); i < i_end; ++i) {
+ RefPtr<nsROCSSPrimitiveValue> name = new nsROCSSPrimitiveValue;
+ RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
+
+ const nsStyleCounterData& data = content->CounterResetAt(i);
+ nsAutoString escaped;
+ nsStyleUtil::AppendEscapedCSSIdent(data.mCounter, escaped);
+ name->SetString(escaped);
+ value->SetNumber(data.mValue); // XXX This should really be integer
+
+ valueList->AppendCSSValue(name.forget());
+ valueList->AppendCSSValue(value.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetQuotes()
+{
+ const auto& quotePairs = StyleList()->GetQuotePairs();
+
+ if (quotePairs.IsEmpty()) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ for (const auto& quotePair : quotePairs) {
+ RefPtr<nsROCSSPrimitiveValue> openVal = new nsROCSSPrimitiveValue;
+ RefPtr<nsROCSSPrimitiveValue> closeVal = new nsROCSSPrimitiveValue;
+
+ nsAutoString s;
+ nsStyleUtil::AppendEscapedCSSString(quotePair.first, s);
+ openVal->SetString(s);
+ s.Truncate();
+ nsStyleUtil::AppendEscapedCSSString(quotePair.second, s);
+ closeVal->SetString(s);
+
+ valueList->AppendCSSValue(openVal.forget());
+ valueList->AppendCSSValue(closeVal.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontFamily()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleFont* font = StyleFont();
+ nsAutoString fontlistStr;
+ nsStyleUtil::AppendEscapedCSSFontFamilyList(font->mFont.fontlist,
+ fontlistStr);
+ val->SetString(fontlistStr);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontSize()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ // Note: StyleFont()->mSize is the 'computed size';
+ // StyleFont()->mFont.size is the 'actual size'
+ val->SetAppUnits(StyleFont()->mSize);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontSizeAdjust()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleFont *font = StyleFont();
+
+ if (font->mFont.sizeAdjust >= 0.0f) {
+ val->SetNumber(font->mFont.sizeAdjust);
+ } else {
+ val->SetIdent(eCSSKeyword_none);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOsxFontSmoothing()
+{
+ if (nsContentUtils::ShouldResistFingerprinting(
+ mPresShell->GetPresContext()->GetDocShell()))
+ return nullptr;
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.smoothing,
+ nsCSSProps::kFontSmoothingKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontStretch()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.stretch,
+ nsCSSProps::kFontStretchKTable));
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontStyle()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.style,
+ nsCSSProps::kFontStyleKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontWeight()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleFont* font = StyleFont();
+
+ uint16_t weight = font->mFont.weight;
+ NS_ASSERTION(weight % 100 == 0, "unexpected value of font-weight");
+ val->SetNumber(weight);
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontFeatureSettings()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleFont* font = StyleFont();
+ if (font->mFont.fontFeatureSettings.IsEmpty()) {
+ val->SetIdent(eCSSKeyword_normal);
+ } else {
+ nsAutoString result;
+ nsStyleUtil::AppendFontFeatureSettings(font->mFont.fontFeatureSettings,
+ result);
+ val->SetString(result);
+ }
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontKerning()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.kerning,
+ nsCSSProps::kFontKerningKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontLanguageOverride()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleFont* font = StyleFont();
+ if (font->mFont.languageOverride.IsEmpty()) {
+ val->SetIdent(eCSSKeyword_normal);
+ } else {
+ nsAutoString str;
+ nsStyleUtil::AppendEscapedCSSString(font->mFont.languageOverride, str);
+ val->SetString(str);
+ }
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontSynthesis()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ int32_t intValue = StyleFont()->mFont.synthesis;
+
+ if (0 == intValue) {
+ val->SetIdent(eCSSKeyword_none);
+ } else {
+ nsAutoString valueStr;
+
+ nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_synthesis,
+ intValue, NS_FONT_SYNTHESIS_WEIGHT,
+ NS_FONT_SYNTHESIS_STYLE, valueStr);
+ val->SetString(valueStr);
+ }
+
+ return val.forget();
+}
+
+// return a value *only* for valid longhand values from CSS 2.1, either
+// normal or small-caps only
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontVariant()
+{
+ const nsFont& f = StyleFont()->mFont;
+
+ // if any of the other font-variant subproperties other than
+ // font-variant-caps are not normal then can't calculate a computed value
+ if (f.variantAlternates || f.variantEastAsian || f.variantLigatures ||
+ f.variantNumeric || f.variantPosition) {
+ return nullptr;
+ }
+
+ nsCSSKeyword keyword;
+ switch (f.variantCaps) {
+ case 0:
+ keyword = eCSSKeyword_normal;
+ break;
+ case NS_FONT_VARIANT_CAPS_SMALLCAPS:
+ keyword = eCSSKeyword_small_caps;
+ break;
+ default:
+ return nullptr;
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(keyword);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontVariantAlternates()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ int32_t intValue = StyleFont()->mFont.variantAlternates;
+
+ if (0 == intValue) {
+ val->SetIdent(eCSSKeyword_normal);
+ return val.forget();
+ }
+
+ // first, include enumerated values
+ nsAutoString valueStr;
+
+ nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_alternates,
+ intValue & NS_FONT_VARIANT_ALTERNATES_ENUMERATED_MASK,
+ NS_FONT_VARIANT_ALTERNATES_HISTORICAL,
+ NS_FONT_VARIANT_ALTERNATES_HISTORICAL, valueStr);
+
+ // next, include functional values if present
+ if (intValue & NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK) {
+ nsStyleUtil::SerializeFunctionalAlternates(StyleFont()->mFont.alternateValues,
+ valueStr);
+ }
+
+ val->SetString(valueStr);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontVariantCaps()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ int32_t intValue = StyleFont()->mFont.variantCaps;
+
+ if (0 == intValue) {
+ val->SetIdent(eCSSKeyword_normal);
+ } else {
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(intValue,
+ nsCSSProps::kFontVariantCapsKTable));
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontVariantEastAsian()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ int32_t intValue = StyleFont()->mFont.variantEastAsian;
+
+ if (0 == intValue) {
+ val->SetIdent(eCSSKeyword_normal);
+ } else {
+ nsAutoString valueStr;
+
+ nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_east_asian,
+ intValue, NS_FONT_VARIANT_EAST_ASIAN_JIS78,
+ NS_FONT_VARIANT_EAST_ASIAN_RUBY, valueStr);
+ val->SetString(valueStr);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontVariantLigatures()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ int32_t intValue = StyleFont()->mFont.variantLigatures;
+
+ if (0 == intValue) {
+ val->SetIdent(eCSSKeyword_normal);
+ } else if (NS_FONT_VARIANT_LIGATURES_NONE == intValue) {
+ val->SetIdent(eCSSKeyword_none);
+ } else {
+ nsAutoString valueStr;
+
+ nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_ligatures,
+ intValue, NS_FONT_VARIANT_LIGATURES_NONE,
+ NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL, valueStr);
+ val->SetString(valueStr);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontVariantNumeric()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ int32_t intValue = StyleFont()->mFont.variantNumeric;
+
+ if (0 == intValue) {
+ val->SetIdent(eCSSKeyword_normal);
+ } else {
+ nsAutoString valueStr;
+
+ nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_numeric,
+ intValue, NS_FONT_VARIANT_NUMERIC_LINING,
+ NS_FONT_VARIANT_NUMERIC_ORDINAL, valueStr);
+ val->SetString(valueStr);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFontVariantPosition()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ int32_t intValue = StyleFont()->mFont.variantPosition;
+
+ if (0 == intValue) {
+ val->SetIdent(eCSSKeyword_normal);
+ } else {
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(intValue,
+ nsCSSProps::kFontVariantPositionKTable));
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetBackgroundList(uint8_t nsStyleImageLayers::Layer::* aMember,
+ uint32_t nsStyleImageLayers::* aCount,
+ const nsStyleImageLayers& aLayers,
+ const KTableEntry aTable[])
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ for (uint32_t i = 0, i_end = aLayers.*aCount; i < i_end; ++i) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(aLayers.mLayers[i].*aMember,
+ aTable));
+ valueList->AppendCSSValue(val.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackgroundAttachment()
+{
+ return GetBackgroundList(&nsStyleImageLayers::Layer::mAttachment,
+ &nsStyleImageLayers::mAttachmentCount,
+ StyleBackground()->mImage,
+ nsCSSProps::kImageLayerAttachmentKTable);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackgroundClip()
+{
+ return GetBackgroundList(&nsStyleImageLayers::Layer::mClip,
+ &nsStyleImageLayers::mClipCount,
+ StyleBackground()->mImage,
+ nsCSSProps::kBackgroundClipKTable);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackgroundColor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetToRGBAColor(val, StyleBackground()->mBackgroundColor);
+ return val.forget();
+}
+
+static void
+SetValueToCalc(const nsStyleCoord::CalcValue* aCalc,
+ nsROCSSPrimitiveValue* aValue)
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString tmp, result;
+
+ result.AppendLiteral("calc(");
+
+ val->SetAppUnits(aCalc->mLength);
+ val->GetCssText(tmp);
+ result.Append(tmp);
+
+ if (aCalc->mHasPercent) {
+ result.AppendLiteral(" + ");
+
+ val->SetPercent(aCalc->mPercent);
+ val->GetCssText(tmp);
+ result.Append(tmp);
+ }
+
+ result.Append(')');
+
+ aValue->SetString(result); // not really SetString
+}
+
+static void
+AppendCSSGradientLength(const nsStyleCoord& aValue,
+ nsROCSSPrimitiveValue* aPrimitive,
+ nsAString& aString)
+{
+ nsAutoString tokenString;
+ if (aValue.IsCalcUnit())
+ SetValueToCalc(aValue.GetCalcValue(), aPrimitive);
+ else if (aValue.GetUnit() == eStyleUnit_Coord)
+ aPrimitive->SetAppUnits(aValue.GetCoordValue());
+ else
+ aPrimitive->SetPercent(aValue.GetPercentValue());
+ aPrimitive->GetCssText(tokenString);
+ aString.Append(tokenString);
+}
+
+static void
+AppendCSSGradientToBoxPosition(const nsStyleGradient* aGradient,
+ nsAString& aString,
+ bool& aNeedSep)
+{
+ float xValue = aGradient->mBgPosX.GetPercentValue();
+ float yValue = aGradient->mBgPosY.GetPercentValue();
+
+ if (yValue == 1.0f && xValue == 0.5f) {
+ // omit "to bottom"
+ return;
+ }
+ NS_ASSERTION(yValue != 0.5f || xValue != 0.5f, "invalid box position");
+
+ aString.AppendLiteral("to");
+
+ if (yValue == 0.0f) {
+ aString.AppendLiteral(" top");
+ } else if (yValue == 1.0f) {
+ aString.AppendLiteral(" bottom");
+ } else if (yValue != 0.5f) { // do not write "center" keyword
+ NS_NOTREACHED("invalid box position");
+ }
+
+ if (xValue == 0.0f) {
+ aString.AppendLiteral(" left");
+ } else if (xValue == 1.0f) {
+ aString.AppendLiteral(" right");
+ } else if (xValue != 0.5f) { // do not write "center" keyword
+ NS_NOTREACHED("invalid box position");
+ }
+
+ aNeedSep = true;
+}
+
+void
+nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient,
+ nsAString& aString)
+{
+ if (!aGradient->mLegacySyntax) {
+ aString.Truncate();
+ } else {
+ aString.AssignLiteral("-moz-");
+ }
+ if (aGradient->mRepeating) {
+ aString.AppendLiteral("repeating-");
+ }
+ bool isRadial = aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR;
+ if (isRadial) {
+ aString.AppendLiteral("radial-gradient(");
+ } else {
+ aString.AppendLiteral("linear-gradient(");
+ }
+
+ bool needSep = false;
+ nsAutoString tokenString;
+ RefPtr<nsROCSSPrimitiveValue> tmpVal = new nsROCSSPrimitiveValue;
+
+ if (isRadial && !aGradient->mLegacySyntax) {
+ if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE) {
+ if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
+ aString.AppendLiteral("circle");
+ needSep = true;
+ }
+ if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) {
+ if (needSep) {
+ aString.Append(' ');
+ }
+ AppendASCIItoUTF16(nsCSSProps::
+ ValueToKeyword(aGradient->mSize,
+ nsCSSProps::kRadialGradientSizeKTable),
+ aString);
+ needSep = true;
+ }
+ } else {
+ AppendCSSGradientLength(aGradient->mRadiusX, tmpVal, aString);
+ if (aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
+ aString.Append(' ');
+ AppendCSSGradientLength(aGradient->mRadiusY, tmpVal, aString);
+ }
+ needSep = true;
+ }
+ }
+ if (aGradient->mBgPosX.GetUnit() != eStyleUnit_None) {
+ MOZ_ASSERT(aGradient->mBgPosY.GetUnit() != eStyleUnit_None);
+ if (!isRadial && !aGradient->mLegacySyntax) {
+ AppendCSSGradientToBoxPosition(aGradient, aString, needSep);
+ } else if (aGradient->mBgPosX.GetUnit() != eStyleUnit_Percent ||
+ aGradient->mBgPosX.GetPercentValue() != 0.5f ||
+ aGradient->mBgPosY.GetUnit() != eStyleUnit_Percent ||
+ aGradient->mBgPosY.GetPercentValue() != (isRadial ? 0.5f : 1.0f)) {
+ if (isRadial && !aGradient->mLegacySyntax) {
+ if (needSep) {
+ aString.Append(' ');
+ }
+ aString.AppendLiteral("at ");
+ needSep = false;
+ }
+ AppendCSSGradientLength(aGradient->mBgPosX, tmpVal, aString);
+ if (aGradient->mBgPosY.GetUnit() != eStyleUnit_None) {
+ aString.Append(' ');
+ AppendCSSGradientLength(aGradient->mBgPosY, tmpVal, aString);
+ }
+ needSep = true;
+ }
+ }
+ if (aGradient->mAngle.GetUnit() != eStyleUnit_None) {
+ MOZ_ASSERT(!isRadial || aGradient->mLegacySyntax);
+ if (needSep) {
+ aString.Append(' ');
+ }
+ nsStyleUtil::AppendAngleValue(aGradient->mAngle, aString);
+ needSep = true;
+ }
+
+ if (isRadial && aGradient->mLegacySyntax &&
+ (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR ||
+ aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)) {
+ MOZ_ASSERT(aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE);
+ if (needSep) {
+ aString.AppendLiteral(", ");
+ needSep = false;
+ }
+ if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
+ aString.AppendLiteral("circle");
+ needSep = true;
+ }
+ if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) {
+ if (needSep) {
+ aString.Append(' ');
+ }
+ AppendASCIItoUTF16(nsCSSProps::
+ ValueToKeyword(aGradient->mSize,
+ nsCSSProps::kRadialGradientSizeKTable),
+ aString);
+ }
+ needSep = true;
+ }
+
+
+ // color stops
+ for (uint32_t i = 0; i < aGradient->mStops.Length(); ++i) {
+ if (needSep) {
+ aString.AppendLiteral(", ");
+ }
+
+ const auto& stop = aGradient->mStops[i];
+ if (!stop.mIsInterpolationHint) {
+ SetToRGBAColor(tmpVal, stop.mColor);
+ tmpVal->GetCssText(tokenString);
+ aString.Append(tokenString);
+ }
+
+ if (stop.mLocation.GetUnit() != eStyleUnit_None) {
+ if (!stop.mIsInterpolationHint) {
+ aString.Append(' ');
+ }
+ AppendCSSGradientLength(stop.mLocation, tmpVal, aString);
+ }
+ needSep = true;
+ }
+
+ aString.Append(')');
+}
+
+// -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
+void
+nsComputedDOMStyle::GetImageRectString(nsIURI* aURI,
+ const nsStyleSides& aCropRect,
+ nsString& aString)
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ // <uri>
+ RefPtr<nsROCSSPrimitiveValue> valURI = new nsROCSSPrimitiveValue;
+ valURI->SetURI(aURI);
+ valueList->AppendCSSValue(valURI.forget());
+
+ // <top>, <right>, <bottom>, <left>
+ NS_FOR_CSS_SIDES(side) {
+ RefPtr<nsROCSSPrimitiveValue> valSide = new nsROCSSPrimitiveValue;
+ SetValueToCoord(valSide, aCropRect.Get(side), false);
+ valueList->AppendCSSValue(valSide.forget());
+ }
+
+ nsAutoString argumentString;
+ valueList->GetCssText(argumentString);
+
+ aString = NS_LITERAL_STRING("-moz-image-rect(") +
+ argumentString +
+ NS_LITERAL_STRING(")");
+}
+
+void
+nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage,
+ nsROCSSPrimitiveValue* aValue)
+{
+ switch (aStyleImage.GetType()) {
+ case eStyleImageType_Image:
+ {
+ imgIRequest* req = aStyleImage.GetImageData();
+ if (!req) {
+ // XXXheycam If we had some problem resolving the imgRequestProxy,
+ // maybe we should just use the URL stored in the nsStyleImage's
+ // mImageValue? (Similarly in DoGetListStyleImage.)
+ aValue->SetIdent(eCSSKeyword_none);
+ break;
+ }
+
+ nsCOMPtr<nsIURI> uri;
+ req->GetURI(getter_AddRefs(uri));
+
+ const UniquePtr<nsStyleSides>& cropRect = aStyleImage.GetCropRect();
+ if (cropRect) {
+ nsAutoString imageRectString;
+ GetImageRectString(uri, *cropRect, imageRectString);
+ aValue->SetString(imageRectString);
+ } else {
+ aValue->SetURI(uri);
+ }
+ break;
+ }
+ case eStyleImageType_Gradient:
+ {
+ nsAutoString gradientString;
+ GetCSSGradientString(aStyleImage.GetGradientData(),
+ gradientString);
+ aValue->SetString(gradientString);
+ break;
+ }
+ case eStyleImageType_Element:
+ {
+ nsAutoString elementId;
+ nsStyleUtil::AppendEscapedCSSIdent(
+ nsDependentString(aStyleImage.GetElementId()), elementId);
+ nsAutoString elementString = NS_LITERAL_STRING("-moz-element(#") +
+ elementId +
+ NS_LITERAL_STRING(")");
+ aValue->SetString(elementString);
+ break;
+ }
+ case eStyleImageType_Null:
+ aValue->SetIdent(eCSSKeyword_none);
+ break;
+ default:
+ NS_NOTREACHED("unexpected image type");
+ break;
+ }
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetImageLayerImage(const nsStyleImageLayers& aLayers)
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ for (uint32_t i = 0, i_end = aLayers.mImageCount; i < i_end; ++i) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleImage& image = aLayers.mLayers[i].mImage;
+ // Layer::mImage::GetType() returns eStyleImageType_Null in two conditions:
+ // 1. The value of mask-image/bg-image is 'none'.
+ // Since this layer does not refer to any source, Layer::mSourceURI must
+ // be nullptr too.
+ // 2. This layer refers to a local resource, e.g. mask-image:url(#mymask).
+ // For local references, there is no need to download any external
+ // resource, so Layer::mImage is not used.
+ // Instead, we store the local URI in one place -- on Layer::mSourceURI.
+ // Hence, we must serialize using mSourceURI (instead of
+ // SetValueToStyleImage()/mImage) in this case.
+ if (aLayers.mLayers[i].mSourceURI &&
+ aLayers.mLayers[i].mSourceURI->IsLocalRef()) {
+ // This is how we represent a 'mask-image' reference for a local URI,
+ // such as 'mask-image:url(#mymask)' or 'mask:url(#mymask)'
+ SetValueToURLValue(aLayers.mLayers[i].mSourceURI, val);
+ } else {
+ SetValueToStyleImage(image, val);
+ }
+
+ valueList->AppendCSSValue(val.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetImageLayerPosition(const nsStyleImageLayers& aLayers)
+{
+ if (aLayers.mPositionXCount != aLayers.mPositionYCount) {
+ // No value to return. We can't express this combination of
+ // values as a shorthand.
+ return nullptr;
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+ for (uint32_t i = 0, i_end = aLayers.mPositionXCount; i < i_end; ++i) {
+ RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
+
+ SetValueToPosition(aLayers.mLayers[i].mPosition, itemList);
+ valueList->AppendCSSValue(itemList.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetImageLayerPositionX(const nsStyleImageLayers& aLayers)
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+ for (uint32_t i = 0, i_end = aLayers.mPositionXCount; i < i_end; ++i) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToPositionCoord(aLayers.mLayers[i].mPosition.mXPosition, val);
+ valueList->AppendCSSValue(val.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetImageLayerPositionY(const nsStyleImageLayers& aLayers)
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+ for (uint32_t i = 0, i_end = aLayers.mPositionYCount; i < i_end; ++i) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToPositionCoord(aLayers.mLayers[i].mPosition.mYPosition, val);
+ valueList->AppendCSSValue(val.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetImageLayerRepeat(const nsStyleImageLayers& aLayers)
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ for (uint32_t i = 0, i_end = aLayers.mRepeatCount; i < i_end; ++i) {
+ RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
+ RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
+
+ const uint8_t& xRepeat = aLayers.mLayers[i].mRepeat.mXRepeat;
+ const uint8_t& yRepeat = aLayers.mLayers[i].mRepeat.mYRepeat;
+
+ bool hasContraction = true;
+ unsigned contraction;
+ if (xRepeat == yRepeat) {
+ contraction = xRepeat;
+ } else if (xRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT &&
+ yRepeat == NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT) {
+ contraction = NS_STYLE_IMAGELAYER_REPEAT_REPEAT_X;
+ } else if (xRepeat == NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT &&
+ yRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT) {
+ contraction = NS_STYLE_IMAGELAYER_REPEAT_REPEAT_Y;
+ } else {
+ hasContraction = false;
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> valY;
+ if (hasContraction) {
+ valX->SetIdent(nsCSSProps::ValueToKeywordEnum(contraction,
+ nsCSSProps::kImageLayerRepeatKTable));
+ } else {
+ valY = new nsROCSSPrimitiveValue;
+
+ valX->SetIdent(nsCSSProps::ValueToKeywordEnum(xRepeat,
+ nsCSSProps::kImageLayerRepeatKTable));
+ valY->SetIdent(nsCSSProps::ValueToKeywordEnum(yRepeat,
+ nsCSSProps::kImageLayerRepeatKTable));
+ }
+ itemList->AppendCSSValue(valX.forget());
+ if (valY) {
+ itemList->AppendCSSValue(valY.forget());
+ }
+ valueList->AppendCSSValue(itemList.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetImageLayerSize(const nsStyleImageLayers& aLayers)
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ for (uint32_t i = 0, i_end = aLayers.mSizeCount; i < i_end; ++i) {
+ const nsStyleImageLayers::Size &size = aLayers.mLayers[i].mSize;
+
+ switch (size.mWidthType) {
+ case nsStyleImageLayers::Size::eContain:
+ case nsStyleImageLayers::Size::eCover: {
+ MOZ_ASSERT(size.mWidthType == size.mHeightType,
+ "unsynced types");
+ nsCSSKeyword keyword = size.mWidthType == nsStyleImageLayers::Size::eContain
+ ? eCSSKeyword_contain
+ : eCSSKeyword_cover;
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(keyword);
+ valueList->AppendCSSValue(val.forget());
+ break;
+ }
+ default: {
+ RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
+
+ RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
+ RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
+
+ if (size.mWidthType == nsStyleImageLayers::Size::eAuto) {
+ valX->SetIdent(eCSSKeyword_auto);
+ } else {
+ MOZ_ASSERT(size.mWidthType ==
+ nsStyleImageLayers::Size::eLengthPercentage,
+ "bad mWidthType");
+ if (!size.mWidth.mHasPercent &&
+ // negative values must have come from calc()
+ size.mWidth.mLength >= 0) {
+ MOZ_ASSERT(size.mWidth.mPercent == 0.0f,
+ "Shouldn't have mPercent");
+ valX->SetAppUnits(size.mWidth.mLength);
+ } else if (size.mWidth.mLength == 0 &&
+ // negative values must have come from calc()
+ size.mWidth.mPercent >= 0.0f) {
+ valX->SetPercent(size.mWidth.mPercent);
+ } else {
+ SetValueToCalc(&size.mWidth, valX);
+ }
+ }
+
+ if (size.mHeightType == nsStyleImageLayers::Size::eAuto) {
+ valY->SetIdent(eCSSKeyword_auto);
+ } else {
+ MOZ_ASSERT(size.mHeightType ==
+ nsStyleImageLayers::Size::eLengthPercentage,
+ "bad mHeightType");
+ if (!size.mHeight.mHasPercent &&
+ // negative values must have come from calc()
+ size.mHeight.mLength >= 0) {
+ MOZ_ASSERT(size.mHeight.mPercent == 0.0f,
+ "Shouldn't have mPercent");
+ valY->SetAppUnits(size.mHeight.mLength);
+ } else if (size.mHeight.mLength == 0 &&
+ // negative values must have come from calc()
+ size.mHeight.mPercent >= 0.0f) {
+ valY->SetPercent(size.mHeight.mPercent);
+ } else {
+ SetValueToCalc(&size.mHeight, valY);
+ }
+ }
+ itemList->AppendCSSValue(valX.forget());
+ itemList->AppendCSSValue(valY.forget());
+ valueList->AppendCSSValue(itemList.forget());
+ break;
+ }
+ }
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackgroundImage()
+{
+ const nsStyleImageLayers& layers = StyleBackground()->mImage;
+ return DoGetImageLayerImage(layers);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackgroundBlendMode()
+{
+ return GetBackgroundList(&nsStyleImageLayers::Layer::mBlendMode,
+ &nsStyleImageLayers::mBlendModeCount,
+ StyleBackground()->mImage,
+ nsCSSProps::kBlendModeKTable);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackgroundOrigin()
+{
+ return GetBackgroundList(&nsStyleImageLayers::Layer::mOrigin,
+ &nsStyleImageLayers::mOriginCount,
+ StyleBackground()->mImage,
+ nsCSSProps::kImageLayerOriginKTable);
+}
+
+void
+nsComputedDOMStyle::SetValueToPositionCoord(
+ const Position::Coord& aCoord,
+ nsROCSSPrimitiveValue* aValue)
+{
+ if (!aCoord.mHasPercent) {
+ MOZ_ASSERT(aCoord.mPercent == 0.0f,
+ "Shouldn't have mPercent!");
+ aValue->SetAppUnits(aCoord.mLength);
+ } else if (aCoord.mLength == 0) {
+ aValue->SetPercent(aCoord.mPercent);
+ } else {
+ SetValueToCalc(&aCoord, aValue);
+ }
+}
+
+void
+nsComputedDOMStyle::SetValueToPosition(
+ const Position& aPosition,
+ nsDOMCSSValueList* aValueList)
+{
+ RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
+ SetValueToPositionCoord(aPosition.mXPosition, valX);
+ aValueList->AppendCSSValue(valX.forget());
+
+ RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
+ SetValueToPositionCoord(aPosition.mYPosition, valY);
+ aValueList->AppendCSSValue(valY.forget());
+}
+
+
+void
+nsComputedDOMStyle::SetValueToURLValue(const css::URLValueData* aURL,
+ nsROCSSPrimitiveValue* aValue)
+{
+ if (aURL && aURL->IsLocalRef()) {
+ nsString fragment;
+ aURL->GetSourceString(fragment);
+ fragment.Insert(u"url(\"", 0);
+ fragment.Append(u"\")");
+ aValue->SetString(fragment);
+ } else {
+ nsCOMPtr<nsIURI> url;
+ if (aURL && (url = aURL->GetURI())) {
+ aValue->SetURI(url);
+ } else {
+ aValue->SetIdent(eCSSKeyword_none);
+ }
+ }
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackgroundPosition()
+{
+ const nsStyleImageLayers& layers = StyleBackground()->mImage;
+ return DoGetImageLayerPosition(layers);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackgroundPositionX()
+{
+ const nsStyleImageLayers& layers = StyleBackground()->mImage;
+ return DoGetImageLayerPositionX(layers);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackgroundPositionY()
+{
+ const nsStyleImageLayers& layers = StyleBackground()->mImage;
+ return DoGetImageLayerPositionY(layers);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackgroundRepeat()
+{
+ const nsStyleImageLayers& layers = StyleBackground()->mImage;
+ return DoGetImageLayerRepeat(layers);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBackgroundSize()
+{
+ const nsStyleImageLayers& layers = StyleBackground()->mImage;
+ return DoGetImageLayerSize(layers);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridTemplateAreas()
+{
+ const css::GridTemplateAreasValue* areas =
+ StylePosition()->mGridTemplateAreas;
+ if (!areas) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ }
+
+ MOZ_ASSERT(!areas->mTemplates.IsEmpty(),
+ "Unexpected empty array in GridTemplateAreasValue");
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ for (uint32_t i = 0; i < areas->mTemplates.Length(); i++) {
+ nsAutoString str;
+ nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[i], str);
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetString(str);
+ valueList->AppendCSSValue(val.forget());
+ }
+ return valueList.forget();
+}
+
+void
+nsComputedDOMStyle::AppendGridLineNames(nsString& aResult,
+ const nsTArray<nsString>& aLineNames)
+{
+ uint32_t numLines = aLineNames.Length();
+ if (numLines == 0) {
+ return;
+ }
+ for (uint32_t i = 0;;) {
+ nsStyleUtil::AppendEscapedCSSIdent(aLineNames[i], aResult);
+ if (++i == numLines) {
+ break;
+ }
+ aResult.Append(' ');
+ }
+}
+
+void
+nsComputedDOMStyle::AppendGridLineNames(nsDOMCSSValueList* aValueList,
+ const nsTArray<nsString>& aLineNames,
+ bool aSuppressEmptyList)
+{
+ if (aLineNames.IsEmpty() && aSuppressEmptyList) {
+ return;
+ }
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString lineNamesString;
+ lineNamesString.Assign('[');
+ AppendGridLineNames(lineNamesString, aLineNames);
+ lineNamesString.Append(']');
+ val->SetString(lineNamesString);
+ aValueList->AppendCSSValue(val.forget());
+}
+
+void
+nsComputedDOMStyle::AppendGridLineNames(nsDOMCSSValueList* aValueList,
+ const nsTArray<nsString>& aLineNames1,
+ const nsTArray<nsString>& aLineNames2)
+{
+ if (aLineNames1.IsEmpty() && aLineNames2.IsEmpty()) {
+ return;
+ }
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString lineNamesString;
+ lineNamesString.Assign('[');
+ if (!aLineNames1.IsEmpty()) {
+ AppendGridLineNames(lineNamesString, aLineNames1);
+ }
+ if (!aLineNames2.IsEmpty()) {
+ if (!aLineNames1.IsEmpty()) {
+ lineNamesString.Append(' ');
+ }
+ AppendGridLineNames(lineNamesString, aLineNames2);
+ }
+ lineNamesString.Append(']');
+ val->SetString(lineNamesString);
+ aValueList->AppendCSSValue(val.forget());
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue,
+ const nsStyleCoord& aMaxValue)
+{
+ if (aMinValue.GetUnit() == eStyleUnit_None) {
+ // A fit-content() function.
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString argumentStr, fitContentStr;
+ fitContentStr.AppendLiteral("fit-content(");
+ MOZ_ASSERT(aMaxValue.IsCoordPercentCalcUnit(),
+ "unexpected unit for fit-content() argument value");
+ SetValueToCoord(val, aMaxValue, true);
+ val->GetCssText(argumentStr);
+ fitContentStr.Append(argumentStr);
+ fitContentStr.Append(char16_t(')'));
+ val->SetString(fitContentStr);
+ return val.forget();
+ }
+
+ if (aMinValue == aMaxValue) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, aMinValue, true,
+ nullptr, nsCSSProps::kGridTrackBreadthKTable);
+ return val.forget();
+ }
+
+ // minmax(auto, <flex>) is equivalent to (and is our internal representation
+ // of) <flex>, and both compute to <flex>
+ if (aMinValue.GetUnit() == eStyleUnit_Auto &&
+ aMaxValue.GetUnit() == eStyleUnit_FlexFraction) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, aMaxValue, true);
+ return val.forget();
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString argumentStr, minmaxStr;
+ minmaxStr.AppendLiteral("minmax(");
+
+ SetValueToCoord(val, aMinValue, true,
+ nullptr, nsCSSProps::kGridTrackBreadthKTable);
+ val->GetCssText(argumentStr);
+ minmaxStr.Append(argumentStr);
+
+ minmaxStr.AppendLiteral(", ");
+
+ SetValueToCoord(val, aMaxValue, true,
+ nullptr, nsCSSProps::kGridTrackBreadthKTable);
+ val->GetCssText(argumentStr);
+ minmaxStr.Append(argumentStr);
+
+ minmaxStr.Append(char16_t(')'));
+ val->SetString(minmaxStr);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetGridTemplateColumnsRows(
+ const nsStyleGridTemplate& aTrackList,
+ const ComputedGridTrackInfo* aTrackInfo)
+{
+ if (aTrackList.mIsSubgrid) {
+ // XXX TODO: add support for repeat(auto-fill) for 'subgrid' (bug 1234311)
+ NS_ASSERTION(aTrackList.mMinTrackSizingFunctions.IsEmpty() &&
+ aTrackList.mMaxTrackSizingFunctions.IsEmpty(),
+ "Unexpected sizing functions with subgrid");
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ RefPtr<nsROCSSPrimitiveValue> subgridKeyword = new nsROCSSPrimitiveValue;
+ subgridKeyword->SetIdent(eCSSKeyword_subgrid);
+ valueList->AppendCSSValue(subgridKeyword.forget());
+
+ for (uint32_t i = 0, len = aTrackList.mLineNameLists.Length(); ; ++i) {
+ if (MOZ_UNLIKELY(aTrackList.IsRepeatAutoIndex(i))) {
+ MOZ_ASSERT(aTrackList.mIsAutoFill, "subgrid can only have 'auto-fill'");
+ MOZ_ASSERT(aTrackList.mRepeatAutoLineNameListAfter.IsEmpty(),
+ "mRepeatAutoLineNameListAfter isn't used for subgrid");
+ RefPtr<nsROCSSPrimitiveValue> start = new nsROCSSPrimitiveValue;
+ start->SetString(NS_LITERAL_STRING("repeat(auto-fill,"));
+ valueList->AppendCSSValue(start.forget());
+ AppendGridLineNames(valueList, aTrackList.mRepeatAutoLineNameListBefore,
+ /*aSuppressEmptyList*/ false);
+ RefPtr<nsROCSSPrimitiveValue> end = new nsROCSSPrimitiveValue;
+ end->SetString(NS_LITERAL_STRING(")"));
+ valueList->AppendCSSValue(end.forget());
+ }
+ if (i == len) {
+ break;
+ }
+ AppendGridLineNames(valueList, aTrackList.mLineNameLists[i],
+ /*aSuppressEmptyList*/ false);
+ }
+ return valueList.forget();
+ }
+
+ uint32_t numSizes = aTrackList.mMinTrackSizingFunctions.Length();
+ MOZ_ASSERT(aTrackList.mMaxTrackSizingFunctions.Length() == numSizes,
+ "Different number of min and max track sizing functions");
+ if (aTrackInfo) {
+ DebugOnly<bool> isAutoFill =
+ aTrackList.HasRepeatAuto() && aTrackList.mIsAutoFill;
+ DebugOnly<bool> isAutoFit =
+ aTrackList.HasRepeatAuto() && !aTrackList.mIsAutoFill;
+ DebugOnly<uint32_t> numExplicitTracks = aTrackInfo->mNumExplicitTracks;
+ MOZ_ASSERT(numExplicitTracks == numSizes ||
+ (isAutoFill && numExplicitTracks >= numSizes) ||
+ (isAutoFit && numExplicitTracks + 1 >= numSizes),
+ "expected all explicit tracks (or possibly one less, if there's "
+ "an 'auto-fit' track, since that can collapse away)");
+ numSizes = aTrackInfo->mSizes.Length();
+ }
+
+ // An empty <track-list> without repeats is represented as "none" in syntax.
+ if (numSizes == 0 && !aTrackList.HasRepeatAuto()) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ if (aTrackInfo) {
+ // We've done layout on the grid and have resolved the sizes of its tracks,
+ // so we'll return those sizes here. The grid spec says we MAY use
+ // repeat(<positive-integer>, Npx) here for consecutive tracks with the same
+ // size, but that doesn't seem worth doing since even for repeat(auto-*)
+ // the resolved size might differ for the repeated tracks.
+ const nsTArray<nscoord>& trackSizes = aTrackInfo->mSizes;
+ const uint32_t numExplicitTracks = aTrackInfo->mNumExplicitTracks;
+ const uint32_t numLeadingImplicitTracks = aTrackInfo->mNumLeadingImplicitTracks;
+ MOZ_ASSERT(numSizes >= numLeadingImplicitTracks + numExplicitTracks);
+
+ // Add any leading implicit tracks.
+ for (uint32_t i = 0; i < numLeadingImplicitTracks; ++i) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetAppUnits(trackSizes[i]);
+ valueList->AppendCSSValue(val.forget());
+ }
+
+ // Then add any explicit tracks and removed auto-fit tracks.
+ if (numExplicitTracks || aTrackList.HasRepeatAuto()) {
+ int32_t endOfRepeat = 0; // first index after any repeat() tracks
+ int32_t offsetToLastRepeat = 0;
+ if (aTrackList.HasRepeatAuto()) {
+ // offsetToLastRepeat is -1 if all repeat(auto-fit) tracks are empty
+ offsetToLastRepeat = numExplicitTracks + 1 - aTrackList.mLineNameLists.Length();
+ endOfRepeat = aTrackList.mRepeatAutoIndex + offsetToLastRepeat + 1;
+ }
+
+ uint32_t repeatIndex = 0;
+ uint32_t numRepeatTracks = aTrackInfo->mRemovedRepeatTracks.Length();
+ enum LinePlacement { LinesPrecede, LinesFollow, LinesBetween };
+ auto AppendRemovedAutoFits = [this, aTrackInfo, &valueList, aTrackList,
+ &repeatIndex,
+ numRepeatTracks](LinePlacement aPlacement)
+ {
+ // Add in removed auto-fit tracks and lines here, if necessary
+ bool atLeastOneTrackReported = false;
+ while (repeatIndex < numRepeatTracks &&
+ aTrackInfo->mRemovedRepeatTracks[repeatIndex]) {
+ if ((aPlacement == LinesPrecede) ||
+ ((aPlacement == LinesBetween) && atLeastOneTrackReported)) {
+ // Precede it with the lines between repeats.
+ AppendGridLineNames(valueList,
+ aTrackList.mRepeatAutoLineNameListAfter,
+ aTrackList.mRepeatAutoLineNameListBefore);
+ }
+
+ // Removed 'auto-fit' tracks are reported as 0px.
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetAppUnits(0);
+ valueList->AppendCSSValue(val.forget());
+ atLeastOneTrackReported = true;
+
+ if (aPlacement == LinesFollow) {
+ // Follow it with the lines between repeats.
+ AppendGridLineNames(valueList,
+ aTrackList.mRepeatAutoLineNameListAfter,
+ aTrackList.mRepeatAutoLineNameListBefore);
+ }
+ repeatIndex++;
+ }
+ repeatIndex++;
+ };
+
+ for (int32_t i = 0;; i++) {
+ if (aTrackList.HasRepeatAuto()) {
+ if (i == aTrackList.mRepeatAutoIndex) {
+ const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[i];
+ if (i == endOfRepeat) {
+ // All auto-fit tracks are empty, but we report them anyway.
+ AppendGridLineNames(valueList, lineNames,
+ aTrackList.mRepeatAutoLineNameListBefore);
+
+ AppendRemovedAutoFits(LinesBetween);
+
+ AppendGridLineNames(valueList,
+ aTrackList.mRepeatAutoLineNameListAfter,
+ aTrackList.mLineNameLists[i + 1]);
+ } else {
+ AppendGridLineNames(valueList, lineNames,
+ aTrackList.mRepeatAutoLineNameListBefore);
+ AppendRemovedAutoFits(LinesFollow);
+ }
+ } else if (i == endOfRepeat) {
+ // Before appending the last line, finish off any removed auto-fits.
+ AppendRemovedAutoFits(LinesPrecede);
+
+ const nsTArray<nsString>& lineNames =
+ aTrackList.mLineNameLists[aTrackList.mRepeatAutoIndex + 1];
+ AppendGridLineNames(valueList,
+ aTrackList.mRepeatAutoLineNameListAfter,
+ lineNames);
+ } else if (i > aTrackList.mRepeatAutoIndex && i < endOfRepeat) {
+ AppendGridLineNames(valueList,
+ aTrackList.mRepeatAutoLineNameListAfter,
+ aTrackList.mRepeatAutoLineNameListBefore);
+ AppendRemovedAutoFits(LinesFollow);
+ } else {
+ uint32_t j = i > endOfRepeat ? i - offsetToLastRepeat : i;
+ const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[j];
+ AppendGridLineNames(valueList, lineNames);
+ }
+ } else {
+ const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[i];
+ AppendGridLineNames(valueList, lineNames);
+ }
+ if (uint32_t(i) == numExplicitTracks) {
+ break;
+ }
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetAppUnits(trackSizes[i + numLeadingImplicitTracks]);
+ valueList->AppendCSSValue(val.forget());
+ }
+ }
+
+ // Add any trailing implicit tracks.
+ for (uint32_t i = numLeadingImplicitTracks + numExplicitTracks;
+ i < numSizes; ++i) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetAppUnits(trackSizes[i]);
+ valueList->AppendCSSValue(val.forget());
+ }
+ } else {
+ // We don't have a frame. So, we'll just return a serialization of
+ // the tracks from the style (without resolved sizes).
+ for (uint32_t i = 0;; i++) {
+ const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[i];
+ if (!lineNames.IsEmpty()) {
+ AppendGridLineNames(valueList, lineNames);
+ }
+ if (i == numSizes) {
+ break;
+ }
+ if (MOZ_UNLIKELY(aTrackList.IsRepeatAutoIndex(i))) {
+ RefPtr<nsROCSSPrimitiveValue> start = new nsROCSSPrimitiveValue;
+ start->SetString(aTrackList.mIsAutoFill ? NS_LITERAL_STRING("repeat(auto-fill,")
+ : NS_LITERAL_STRING("repeat(auto-fit,"));
+ valueList->AppendCSSValue(start.forget());
+ if (!aTrackList.mRepeatAutoLineNameListBefore.IsEmpty()) {
+ AppendGridLineNames(valueList, aTrackList.mRepeatAutoLineNameListBefore);
+ }
+
+ valueList->AppendCSSValue(
+ GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i],
+ aTrackList.mMaxTrackSizingFunctions[i]));
+ if (!aTrackList.mRepeatAutoLineNameListAfter.IsEmpty()) {
+ AppendGridLineNames(valueList, aTrackList.mRepeatAutoLineNameListAfter);
+ }
+ RefPtr<nsROCSSPrimitiveValue> end = new nsROCSSPrimitiveValue;
+ end->SetString(NS_LITERAL_STRING(")"));
+ valueList->AppendCSSValue(end.forget());
+ } else {
+ valueList->AppendCSSValue(
+ GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i],
+ aTrackList.mMaxTrackSizingFunctions[i]));
+ }
+ }
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridAutoFlow()
+{
+ nsAutoString str;
+ nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_grid_auto_flow,
+ StylePosition()->mGridAutoFlow,
+ NS_STYLE_GRID_AUTO_FLOW_ROW,
+ NS_STYLE_GRID_AUTO_FLOW_DENSE,
+ str);
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetString(str);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridAutoColumns()
+{
+ return GetGridTrackSize(StylePosition()->mGridAutoColumnsMin,
+ StylePosition()->mGridAutoColumnsMax);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridAutoRows()
+{
+ return GetGridTrackSize(StylePosition()->mGridAutoRowsMin,
+ StylePosition()->mGridAutoRowsMax);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridTemplateColumns()
+{
+ const ComputedGridTrackInfo* info = nullptr;
+
+ nsGridContainerFrame* gridFrame =
+ nsGridContainerFrame::GetGridFrameWithComputedInfo(
+ mContent->GetPrimaryFrame());
+
+ if (gridFrame) {
+ info = gridFrame->GetComputedTemplateColumns();
+ }
+
+ return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns, info);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridTemplateRows()
+{
+ const ComputedGridTrackInfo* info = nullptr;
+
+ nsGridContainerFrame* gridFrame =
+ nsGridContainerFrame::GetGridFrameWithComputedInfo(
+ mContent->GetPrimaryFrame());
+
+ if (gridFrame) {
+ info = gridFrame->GetComputedTemplateRows();
+ }
+
+ return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows, info);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetGridLine(const nsStyleGridLine& aGridLine)
+{
+ if (aGridLine.IsAuto()) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_auto);
+ return val.forget();
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ if (aGridLine.mHasSpan) {
+ RefPtr<nsROCSSPrimitiveValue> span = new nsROCSSPrimitiveValue;
+ span->SetIdent(eCSSKeyword_span);
+ valueList->AppendCSSValue(span.forget());
+ }
+
+ if (aGridLine.mInteger != 0) {
+ RefPtr<nsROCSSPrimitiveValue> integer = new nsROCSSPrimitiveValue;
+ integer->SetNumber(aGridLine.mInteger);
+ valueList->AppendCSSValue(integer.forget());
+ }
+
+ if (!aGridLine.mLineName.IsEmpty()) {
+ RefPtr<nsROCSSPrimitiveValue> lineName = new nsROCSSPrimitiveValue;
+ nsString escapedLineName;
+ nsStyleUtil::AppendEscapedCSSIdent(aGridLine.mLineName, escapedLineName);
+ lineName->SetString(escapedLineName);
+ valueList->AppendCSSValue(lineName.forget());
+ }
+
+ NS_ASSERTION(valueList->Length() > 0,
+ "Should have appended at least one value");
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridColumnStart()
+{
+ return GetGridLine(StylePosition()->mGridColumnStart);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridColumnEnd()
+{
+ return GetGridLine(StylePosition()->mGridColumnEnd);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridRowStart()
+{
+ return GetGridLine(StylePosition()->mGridRowStart);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridRowEnd()
+{
+ return GetGridLine(StylePosition()->mGridRowEnd);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridColumnGap()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StylePosition()->mGridColumnGap, true);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetGridRowGap()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StylePosition()->mGridRowGap, true);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPaddingTop()
+{
+ return GetPaddingWidthFor(NS_SIDE_TOP);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPaddingBottom()
+{
+ return GetPaddingWidthFor(NS_SIDE_BOTTOM);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPaddingLeft()
+{
+ return GetPaddingWidthFor(NS_SIDE_LEFT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPaddingRight()
+{
+ return GetPaddingWidthFor(NS_SIDE_RIGHT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderCollapse()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mBorderCollapse,
+ nsCSSProps::kBorderCollapseKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderSpacing()
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ RefPtr<nsROCSSPrimitiveValue> xSpacing = new nsROCSSPrimitiveValue;
+ RefPtr<nsROCSSPrimitiveValue> ySpacing = new nsROCSSPrimitiveValue;
+
+ const nsStyleTableBorder *border = StyleTableBorder();
+ xSpacing->SetAppUnits(border->mBorderSpacingCol);
+ ySpacing->SetAppUnits(border->mBorderSpacingRow);
+
+ valueList->AppendCSSValue(xSpacing.forget());
+ valueList->AppendCSSValue(ySpacing.forget());
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetCaptionSide()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mCaptionSide,
+ nsCSSProps::kCaptionSideKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetEmptyCells()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mEmptyCells,
+ nsCSSProps::kEmptyCellsKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTableLayout()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleTable()->mLayoutStrategy,
+ nsCSSProps::kTableLayoutKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderTopStyle()
+{
+ return GetBorderStyleFor(NS_SIDE_TOP);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderBottomStyle()
+{
+ return GetBorderStyleFor(NS_SIDE_BOTTOM);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderLeftStyle()
+{
+ return GetBorderStyleFor(NS_SIDE_LEFT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderRightStyle()
+{
+ return GetBorderStyleFor(NS_SIDE_RIGHT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderBottomColors()
+{
+ return GetBorderColorsFor(NS_SIDE_BOTTOM);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderLeftColors()
+{
+ return GetBorderColorsFor(NS_SIDE_LEFT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderRightColors()
+{
+ return GetBorderColorsFor(NS_SIDE_RIGHT);
+}
+
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderTopColors()
+{
+ return GetBorderColorsFor(NS_SIDE_TOP);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderBottomLeftRadius()
+{
+ return GetEllipseRadii(StyleBorder()->mBorderRadius,
+ NS_CORNER_BOTTOM_LEFT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderBottomRightRadius()
+{
+ return GetEllipseRadii(StyleBorder()->mBorderRadius,
+ NS_CORNER_BOTTOM_RIGHT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderTopLeftRadius()
+{
+ return GetEllipseRadii(StyleBorder()->mBorderRadius,
+ NS_CORNER_TOP_LEFT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderTopRightRadius()
+{
+ return GetEllipseRadii(StyleBorder()->mBorderRadius,
+ NS_CORNER_TOP_RIGHT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderTopWidth()
+{
+ return GetBorderWidthFor(NS_SIDE_TOP);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderBottomWidth()
+{
+ return GetBorderWidthFor(NS_SIDE_BOTTOM);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderLeftWidth()
+{
+ return GetBorderWidthFor(NS_SIDE_LEFT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderRightWidth()
+{
+ return GetBorderWidthFor(NS_SIDE_RIGHT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderTopColor()
+{
+ return GetBorderColorFor(NS_SIDE_TOP);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderBottomColor()
+{
+ return GetBorderColorFor(NS_SIDE_BOTTOM);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderLeftColor()
+{
+ return GetBorderColorFor(NS_SIDE_LEFT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderRightColor()
+{
+ return GetBorderColorFor(NS_SIDE_RIGHT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMarginTopWidth()
+{
+ return GetMarginWidthFor(NS_SIDE_TOP);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMarginBottomWidth()
+{
+ return GetMarginWidthFor(NS_SIDE_BOTTOM);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMarginLeftWidth()
+{
+ return GetMarginWidthFor(NS_SIDE_LEFT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMarginRightWidth()
+{
+ return GetMarginWidthFor(NS_SIDE_RIGHT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOrient()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOrient,
+ nsCSSProps::kOrientKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetScrollBehavior()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollBehavior,
+ nsCSSProps::kScrollBehaviorKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetScrollSnapType()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+ if (display->mScrollSnapTypeX != display->mScrollSnapTypeY) {
+ // No value to return. We can't express this combination of
+ // values as a shorthand.
+ return nullptr;
+ }
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollSnapTypeX,
+ nsCSSProps::kScrollSnapTypeKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetScrollSnapTypeX()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollSnapTypeX,
+ nsCSSProps::kScrollSnapTypeKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetScrollSnapTypeY()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollSnapTypeY,
+ nsCSSProps::kScrollSnapTypeKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetScrollSnapPoints(const nsStyleCoord& aCoord)
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ if (aCoord.GetUnit() == eStyleUnit_None) {
+ val->SetIdent(eCSSKeyword_none);
+ } else {
+ nsAutoString argumentString;
+ SetCssTextToCoord(argumentString, aCoord);
+ nsAutoString tmp;
+ tmp.AppendLiteral("repeat(");
+ tmp.Append(argumentString);
+ tmp.Append(')');
+ val->SetString(tmp);
+ }
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetScrollSnapPointsX()
+{
+ return GetScrollSnapPoints(StyleDisplay()->mScrollSnapPointsX);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetScrollSnapPointsY()
+{
+ return GetScrollSnapPoints(StyleDisplay()->mScrollSnapPointsY);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetScrollSnapDestination()
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ SetValueToPosition(StyleDisplay()->mScrollSnapDestination, valueList);
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetScrollSnapCoordinate()
+{
+ const nsStyleDisplay* sd = StyleDisplay();
+ if (sd->mScrollSnapCoordinate.IsEmpty()) {
+ // Having no snap coordinates is interpreted as "none"
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ } else {
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+ for (size_t i = 0, i_end = sd->mScrollSnapCoordinate.Length(); i < i_end; ++i) {
+ RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
+ SetValueToPosition(sd->mScrollSnapCoordinate[i], itemList);
+ valueList->AppendCSSValue(itemList.forget());
+ }
+ return valueList.forget();
+ }
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOutlineWidth()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleOutline* outline = StyleOutline();
+
+ nscoord width;
+ if (outline->mOutlineStyle == NS_STYLE_BORDER_STYLE_NONE) {
+ NS_ASSERTION(outline->GetOutlineWidth() == 0, "unexpected width");
+ width = 0;
+ } else {
+ width = outline->GetOutlineWidth();
+ }
+ val->SetAppUnits(width);
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOutlineStyle()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleOutline()->mOutlineStyle,
+ nsCSSProps::kOutlineStyleKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOutlineOffset()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetAppUnits(StyleOutline()->mOutlineOffset);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOutlineRadiusBottomLeft()
+{
+ return GetEllipseRadii(StyleOutline()->mOutlineRadius,
+ NS_CORNER_BOTTOM_LEFT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOutlineRadiusBottomRight()
+{
+ return GetEllipseRadii(StyleOutline()->mOutlineRadius,
+ NS_CORNER_BOTTOM_RIGHT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOutlineRadiusTopLeft()
+{
+ return GetEllipseRadii(StyleOutline()->mOutlineRadius,
+ NS_CORNER_TOP_LEFT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOutlineRadiusTopRight()
+{
+ return GetEllipseRadii(StyleOutline()->mOutlineRadius,
+ NS_CORNER_TOP_RIGHT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOutlineColor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueFromComplexColor(val, StyleOutline()->mOutlineColor);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetEllipseRadii(const nsStyleCorners& aRadius,
+ uint8_t aFullCorner)
+{
+ nsStyleCoord radiusX = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, false));
+ nsStyleCoord radiusY = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, true));
+
+ // for compatibility, return a single value if X and Y are equal
+ if (radiusX == radiusY) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, radiusX, true);
+ return val.forget();
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
+ RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
+
+ SetValueToCoord(valX, radiusX, true);
+ SetValueToCoord(valY, radiusY, true);
+
+ valueList->AppendCSSValue(valX.forget());
+ valueList->AppendCSSValue(valY.forget());
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray,
+ const nscolor& aDefaultColor,
+ bool aIsBoxShadow)
+{
+ if (!aArray) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ }
+
+ static nscoord nsCSSShadowItem::* const shadowValuesNoSpread[] = {
+ &nsCSSShadowItem::mXOffset,
+ &nsCSSShadowItem::mYOffset,
+ &nsCSSShadowItem::mRadius
+ };
+
+ static nscoord nsCSSShadowItem::* const shadowValuesWithSpread[] = {
+ &nsCSSShadowItem::mXOffset,
+ &nsCSSShadowItem::mYOffset,
+ &nsCSSShadowItem::mRadius,
+ &nsCSSShadowItem::mSpread
+ };
+
+ nscoord nsCSSShadowItem::* const * shadowValues;
+ uint32_t shadowValuesLength;
+ if (aIsBoxShadow) {
+ shadowValues = shadowValuesWithSpread;
+ shadowValuesLength = ArrayLength(shadowValuesWithSpread);
+ } else {
+ shadowValues = shadowValuesNoSpread;
+ shadowValuesLength = ArrayLength(shadowValuesNoSpread);
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ for (nsCSSShadowItem *item = aArray->ShadowAt(0),
+ *item_end = item + aArray->Length();
+ item < item_end; ++item) {
+ RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
+
+ // Color is either the specified shadow color or the foreground color
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nscolor shadowColor;
+ if (item->mHasColor) {
+ shadowColor = item->mColor;
+ } else {
+ shadowColor = aDefaultColor;
+ }
+ SetToRGBAColor(val, shadowColor);
+ itemList->AppendCSSValue(val.forget());
+
+ // Set the offsets, blur radius, and spread if available
+ for (uint32_t i = 0; i < shadowValuesLength; ++i) {
+ val = new nsROCSSPrimitiveValue;
+ val->SetAppUnits(item->*(shadowValues[i]));
+ itemList->AppendCSSValue(val.forget());
+ }
+
+ if (item->mInset && aIsBoxShadow) {
+ // This is an inset box-shadow
+ val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(
+ uint8_t(StyleBoxShadowType::Inset),
+ nsCSSProps::kBoxShadowTypeKTable));
+ itemList->AppendCSSValue(val.forget());
+ }
+ valueList->AppendCSSValue(itemList.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBoxDecorationBreak()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleBorder()->mBoxDecorationBreak,
+ nsCSSProps::kBoxDecorationBreakKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBoxShadow()
+{
+ return GetCSSShadowArray(StyleEffects()->mBoxShadow,
+ StyleColor()->mColor,
+ true);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetZIndex()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StylePosition()->mZIndex, false);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetListStyleImage()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleList* list = StyleList();
+
+ // XXXheycam As in SetValueToStyleImage, we might want to use the
+ // URL stored in the nsStyleImageRequest's mImageValue if we
+ // failed to resolve the imgRequestProxy.
+
+ imgRequestProxy* image = list->GetListStyleImage();
+ if (!image) {
+ val->SetIdent(eCSSKeyword_none);
+ } else {
+ nsCOMPtr<nsIURI> uri;
+ image->GetURI(getter_AddRefs(uri));
+ val->SetURI(uri);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetListStylePosition()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleList()->mListStylePosition,
+ nsCSSProps::kListStylePositionKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetListStyleType()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ CounterStyle* style = StyleList()->GetCounterStyle();
+ AnonymousCounterStyle* anonymous = style->AsAnonymous();
+ nsAutoString tmp;
+ if (!anonymous) {
+ // want SetIdent
+ nsString type;
+ StyleList()->GetListStyleType(type);
+ nsStyleUtil::AppendEscapedCSSIdent(type, tmp);
+ } else if (anonymous->IsSingleString()) {
+ const nsTArray<nsString>& symbols = anonymous->GetSymbols();
+ MOZ_ASSERT(symbols.Length() == 1);
+ nsStyleUtil::AppendEscapedCSSString(symbols[0], tmp);
+ } else {
+ tmp.AppendLiteral("symbols(");
+
+ uint8_t system = anonymous->GetSystem();
+ NS_ASSERTION(system == NS_STYLE_COUNTER_SYSTEM_CYCLIC ||
+ system == NS_STYLE_COUNTER_SYSTEM_NUMERIC ||
+ system == NS_STYLE_COUNTER_SYSTEM_ALPHABETIC ||
+ system == NS_STYLE_COUNTER_SYSTEM_SYMBOLIC ||
+ system == NS_STYLE_COUNTER_SYSTEM_FIXED,
+ "Invalid system for anonymous counter style.");
+ if (system != NS_STYLE_COUNTER_SYSTEM_SYMBOLIC) {
+ AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(
+ system, nsCSSProps::kCounterSystemKTable), tmp);
+ tmp.Append(' ');
+ }
+
+ const nsTArray<nsString>& symbols = anonymous->GetSymbols();
+ NS_ASSERTION(symbols.Length() > 0,
+ "No symbols in the anonymous counter style");
+ for (size_t i = 0, iend = symbols.Length(); i < iend; i++) {
+ nsStyleUtil::AppendEscapedCSSString(symbols[i], tmp);
+ tmp.Append(' ');
+ }
+ tmp.Replace(tmp.Length() - 1, 1, char16_t(')'));
+ }
+ val->SetString(tmp);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetImageRegion()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleList* list = StyleList();
+
+ if (list->mImageRegion.width <= 0 || list->mImageRegion.height <= 0) {
+ val->SetIdent(eCSSKeyword_auto);
+ } else {
+ // create the cssvalues for the sides, stick them in the rect object
+ nsROCSSPrimitiveValue *topVal = new nsROCSSPrimitiveValue;
+ nsROCSSPrimitiveValue *rightVal = new nsROCSSPrimitiveValue;
+ nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue;
+ nsROCSSPrimitiveValue *leftVal = new nsROCSSPrimitiveValue;
+ nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
+ bottomVal, leftVal);
+ topVal->SetAppUnits(list->mImageRegion.y);
+ rightVal->SetAppUnits(list->mImageRegion.width + list->mImageRegion.x);
+ bottomVal->SetAppUnits(list->mImageRegion.height + list->mImageRegion.y);
+ leftVal->SetAppUnits(list->mImageRegion.x);
+ val->SetRect(domRect);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetInitialLetter()
+{
+ const nsStyleTextReset* textReset = StyleTextReset();
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ if (textReset->mInitialLetterSink == 0) {
+ val->SetIdent(eCSSKeyword_normal);
+ return val.forget();
+ } else {
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ val->SetNumber(textReset->mInitialLetterSize);
+ valueList->AppendCSSValue(val.forget());
+ RefPtr<nsROCSSPrimitiveValue> second = new nsROCSSPrimitiveValue;
+ second->SetNumber(textReset->mInitialLetterSink);
+ valueList->AppendCSSValue(second.forget());
+ return valueList.forget();
+ }
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetLineHeight()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ nscoord lineHeight;
+ if (GetLineHeightCoord(lineHeight)) {
+ val->SetAppUnits(lineHeight);
+ } else {
+ SetValueToCoord(val, StyleText()->mLineHeight, true,
+ nullptr, nsCSSProps::kLineHeightKTable);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetRubyAlign()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(
+ StyleText()->mRubyAlign, nsCSSProps::kRubyAlignKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetRubyPosition()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(
+ StyleText()->mRubyPosition, nsCSSProps::kRubyPositionKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetVerticalAlign()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StyleDisplay()->mVerticalAlign, false,
+ nullptr, nsCSSProps::kVerticalAlignKTable);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::CreateTextAlignValue(uint8_t aAlign, bool aAlignTrue,
+ const KTableEntry aTable[])
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(aAlign, aTable));
+ if (!aAlignTrue) {
+ return val.forget();
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> first = new nsROCSSPrimitiveValue;
+ first->SetIdent(eCSSKeyword_unsafe);
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ valueList->AppendCSSValue(first.forget());
+ valueList->AppendCSSValue(val.forget());
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextAlign()
+{
+ const nsStyleText* style = StyleText();
+ return CreateTextAlignValue(style->mTextAlign, style->mTextAlignTrue,
+ nsCSSProps::kTextAlignKTable);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextAlignLast()
+{
+ const nsStyleText* style = StyleText();
+ return CreateTextAlignValue(style->mTextAlignLast, style->mTextAlignLastTrue,
+ nsCSSProps::kTextAlignLastKTable);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextCombineUpright()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ uint8_t tch = StyleText()->mTextCombineUpright;
+
+ if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(tch,
+ nsCSSProps::kTextCombineUprightKTable));
+ } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2) {
+ val->SetString(NS_LITERAL_STRING("digits 2"));
+ } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3) {
+ val->SetString(NS_LITERAL_STRING("digits 3"));
+ } else {
+ val->SetString(NS_LITERAL_STRING("digits 4"));
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextDecoration()
+{
+ const nsStyleTextReset* textReset = StyleTextReset();
+
+ bool isInitialStyle =
+ textReset->mTextDecorationStyle == NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
+ StyleComplexColor color = textReset->mTextDecorationColor;
+
+ if (isInitialStyle && color.IsCurrentColor()) {
+ return DoGetTextDecorationLine();
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ valueList->AppendCSSValue(DoGetTextDecorationLine());
+ if (!isInitialStyle) {
+ valueList->AppendCSSValue(DoGetTextDecorationStyle());
+ }
+ if (!color.IsCurrentColor()) {
+ valueList->AppendCSSValue(DoGetTextDecorationColor());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextDecorationColor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueFromComplexColor(val, StyleTextReset()->mTextDecorationColor);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextDecorationLine()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ int32_t intValue = StyleTextReset()->mTextDecorationLine;
+
+ if (NS_STYLE_TEXT_DECORATION_LINE_NONE == intValue) {
+ val->SetIdent(eCSSKeyword_none);
+ } else {
+ nsAutoString decorationLineString;
+ // Clear the -moz-anchor-decoration bit and the OVERRIDE_ALL bits -- we
+ // don't want these to appear in the computed style.
+ intValue &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS |
+ NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL);
+ nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
+ intValue, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
+ NS_STYLE_TEXT_DECORATION_LINE_BLINK, decorationLineString);
+ val->SetString(decorationLineString);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextDecorationStyle()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleTextReset()->mTextDecorationStyle,
+ nsCSSProps::kTextDecorationStyleKTable));
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextEmphasisColor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueFromComplexColor(val, StyleText()->mTextEmphasisColor);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextEmphasisPosition()
+{
+ auto position = StyleText()->mTextEmphasisPosition;
+
+ MOZ_ASSERT(!(position & NS_STYLE_TEXT_EMPHASIS_POSITION_OVER) !=
+ !(position & NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER));
+ RefPtr<nsROCSSPrimitiveValue> first = new nsROCSSPrimitiveValue;
+ first->SetIdent((position & NS_STYLE_TEXT_EMPHASIS_POSITION_OVER) ?
+ eCSSKeyword_over : eCSSKeyword_under);
+
+ MOZ_ASSERT(!(position & NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT) !=
+ !(position & NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT));
+ RefPtr<nsROCSSPrimitiveValue> second = new nsROCSSPrimitiveValue;
+ second->SetIdent((position & NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT) ?
+ eCSSKeyword_left : eCSSKeyword_right);
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ valueList->AppendCSSValue(first.forget());
+ valueList->AppendCSSValue(second.forget());
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextEmphasisStyle()
+{
+ auto style = StyleText()->mTextEmphasisStyle;
+ if (style == NS_STYLE_TEXT_EMPHASIS_STYLE_NONE) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ }
+ if (style == NS_STYLE_TEXT_EMPHASIS_STYLE_STRING) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString tmp;
+ nsStyleUtil::AppendEscapedCSSString(
+ StyleText()->mTextEmphasisStyleString, tmp);
+ val->SetString(tmp);
+ return val.forget();
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> fillVal = new nsROCSSPrimitiveValue;
+ if ((style & NS_STYLE_TEXT_EMPHASIS_STYLE_FILL_MASK) ==
+ NS_STYLE_TEXT_EMPHASIS_STYLE_FILLED) {
+ fillVal->SetIdent(eCSSKeyword_filled);
+ } else {
+ MOZ_ASSERT((style & NS_STYLE_TEXT_EMPHASIS_STYLE_FILL_MASK) ==
+ NS_STYLE_TEXT_EMPHASIS_STYLE_OPEN);
+ fillVal->SetIdent(eCSSKeyword_open);
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> shapeVal = new nsROCSSPrimitiveValue;
+ shapeVal->SetIdent(nsCSSProps::ValueToKeywordEnum(
+ style & NS_STYLE_TEXT_EMPHASIS_STYLE_SHAPE_MASK,
+ nsCSSProps::kTextEmphasisStyleShapeKTable));
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ valueList->AppendCSSValue(fillVal.forget());
+ valueList->AppendCSSValue(shapeVal.forget());
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextIndent()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StyleText()->mTextIndent, false);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextOrientation()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mTextOrientation,
+ nsCSSProps::kTextOrientationKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextOverflow()
+{
+ const nsStyleTextReset *style = StyleTextReset();
+ RefPtr<nsROCSSPrimitiveValue> first = new nsROCSSPrimitiveValue;
+ const nsStyleTextOverflowSide *side = style->mTextOverflow.GetFirstValue();
+ if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
+ nsAutoString str;
+ nsStyleUtil::AppendEscapedCSSString(side->mString, str);
+ first->SetString(str);
+ } else {
+ first->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(side->mType,
+ nsCSSProps::kTextOverflowKTable));
+ }
+ side = style->mTextOverflow.GetSecondValue();
+ if (!side) {
+ return first.forget();
+ }
+ RefPtr<nsROCSSPrimitiveValue> second = new nsROCSSPrimitiveValue;
+ if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
+ nsAutoString str;
+ nsStyleUtil::AppendEscapedCSSString(side->mString, str);
+ second->SetString(str);
+ } else {
+ second->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(side->mType,
+ nsCSSProps::kTextOverflowKTable));
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ valueList->AppendCSSValue(first.forget());
+ valueList->AppendCSSValue(second.forget());
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextShadow()
+{
+ return GetCSSShadowArray(StyleText()->mTextShadow,
+ StyleColor()->mColor,
+ false);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextTransform()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleText()->mTextTransform,
+ nsCSSProps::kTextTransformKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTabSize()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StyleText()->mTabSize);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetLetterSpacing()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StyleText()->mLetterSpacing, false);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetWordSpacing()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StyleText()->mWordSpacing, false);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetWhiteSpace()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleText()->mWhiteSpace,
+ nsCSSProps::kWhitespaceKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetWindowDragging()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mWindowDragging,
+ nsCSSProps::kWindowDraggingKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetWindowShadow()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mWindowShadow,
+ nsCSSProps::kWindowShadowKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetWordBreak()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleText()->mWordBreak,
+ nsCSSProps::kWordBreakKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOverflowWrap()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleText()->mOverflowWrap,
+ nsCSSProps::kOverflowWrapKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetHyphens()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleText()->mHyphens,
+ nsCSSProps::kHyphensKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextSizeAdjust()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ switch (StyleText()->mTextSizeAdjust) {
+ default:
+ NS_NOTREACHED("unexpected value");
+ MOZ_FALLTHROUGH;
+ case NS_STYLE_TEXT_SIZE_ADJUST_AUTO:
+ val->SetIdent(eCSSKeyword_auto);
+ break;
+ case NS_STYLE_TEXT_SIZE_ADJUST_NONE:
+ val->SetIdent(eCSSKeyword_none);
+ break;
+ }
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetWebkitTextFillColor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueFromComplexColor(val, StyleText()->mWebkitTextFillColor);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetWebkitTextStrokeColor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueFromComplexColor(val, StyleText()->mWebkitTextStrokeColor);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetWebkitTextStrokeWidth()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetAppUnits(StyleText()->mWebkitTextStrokeWidth.GetCoordValue());
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPointerEvents()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mPointerEvents,
+ nsCSSProps::kPointerEventsKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetVisibility()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mVisible,
+ nsCSSProps::kVisibilityKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetWritingMode()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mWritingMode,
+ nsCSSProps::kWritingModeKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetDirection()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mDirection,
+ nsCSSProps::kDirectionKTable));
+ return val.forget();
+}
+
+static_assert(NS_STYLE_UNICODE_BIDI_NORMAL == 0,
+ "unicode-bidi style constants not as expected");
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetUnicodeBidi()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleTextReset()->mUnicodeBidi,
+ nsCSSProps::kUnicodeBidiKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetCursor()
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ const nsStyleUserInterface *ui = StyleUserInterface();
+
+ for (const nsCursorImage& item : ui->mCursorImages) {
+ RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
+
+ nsCOMPtr<nsIURI> uri;
+ item.GetImage()->GetURI(getter_AddRefs(uri));
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetURI(uri);
+ itemList->AppendCSSValue(val.forget());
+
+ if (item.mHaveHotspot) {
+ RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
+ RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
+
+ valX->SetNumber(item.mHotspotX);
+ valY->SetNumber(item.mHotspotY);
+
+ itemList->AppendCSSValue(valX.forget());
+ itemList->AppendCSSValue(valY.forget());
+ }
+ valueList->AppendCSSValue(itemList.forget());
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(ui->mCursor,
+ nsCSSProps::kCursorKTable));
+ valueList->AppendCSSValue(val.forget());
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAppearance()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mAppearance,
+ nsCSSProps::kAppearanceKTable));
+ return val.forget();
+}
+
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBoxAlign()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxAlign,
+ nsCSSProps::kBoxAlignKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBoxDirection()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxDirection,
+ nsCSSProps::kBoxDirectionKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBoxFlex()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StyleXUL()->mBoxFlex);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBoxOrdinalGroup()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StyleXUL()->mBoxOrdinal);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBoxOrient()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxOrient,
+ nsCSSProps::kBoxOrientKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBoxPack()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxPack,
+ nsCSSProps::kBoxPackKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBoxSizing()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StylePosition()->mBoxSizing,
+ nsCSSProps::kBoxSizingKTable));
+ return val.forget();
+}
+
+/* Border image properties */
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderImageSource()
+{
+ const nsStyleBorder* border = StyleBorder();
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ const nsStyleImage& image = border->mBorderImageSource;
+ SetValueToStyleImage(image, val);
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderImageSlice()
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ const nsStyleBorder* border = StyleBorder();
+ // Four slice numbers.
+ NS_FOR_CSS_SIDES (side) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, border->mBorderImageSlice.Get(side), true, nullptr);
+ valueList->AppendCSSValue(val.forget());
+ }
+
+ // Fill keyword.
+ if (NS_STYLE_BORDER_IMAGE_SLICE_FILL == border->mBorderImageFill) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_fill);
+ valueList->AppendCSSValue(val.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderImageWidth()
+{
+ const nsStyleBorder* border = StyleBorder();
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ NS_FOR_CSS_SIDES (side) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, border->mBorderImageWidth.Get(side),
+ true, nullptr);
+ valueList->AppendCSSValue(val.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderImageOutset()
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ const nsStyleBorder* border = StyleBorder();
+ // four slice numbers
+ NS_FOR_CSS_SIDES (side) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, border->mBorderImageOutset.Get(side),
+ true, nullptr);
+ valueList->AppendCSSValue(val.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetBorderImageRepeat()
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ const nsStyleBorder* border = StyleBorder();
+
+ // horizontal repeat
+ RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
+ valX->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatH,
+ nsCSSProps::kBorderImageRepeatKTable));
+ valueList->AppendCSSValue(valX.forget());
+
+ // vertical repeat
+ RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
+ valY->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatV,
+ nsCSSProps::kBorderImageRepeatKTable));
+ valueList->AppendCSSValue(valY.forget());
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFlexBasis()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ // XXXdholbert We could make this more automagic and resolve percentages
+ // if we wanted, by passing in a PercentageBaseGetter instead of nullptr
+ // below. Logic would go like this:
+ // if (i'm a flex item) {
+ // if (my flex container is horizontal) {
+ // percentageBaseGetter = &nsComputedDOMStyle::GetCBContentWidth;
+ // } else {
+ // percentageBaseGetter = &nsComputedDOMStyle::GetCBContentHeight;
+ // }
+ // }
+
+ SetValueToCoord(val, StylePosition()->mFlexBasis, true,
+ nullptr, nsCSSProps::kWidthKTable);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFlexDirection()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexDirection,
+ nsCSSProps::kFlexDirectionKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFlexGrow()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StylePosition()->mFlexGrow);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFlexShrink()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StylePosition()->mFlexShrink);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFlexWrap()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexWrap,
+ nsCSSProps::kFlexWrapKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOrder()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StylePosition()->mOrder);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAlignContent()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString str;
+ auto align = StylePosition()->mAlignContent;
+ nsCSSValue::AppendAlignJustifyValueToString(align & NS_STYLE_ALIGN_ALL_BITS, str);
+ auto fallback = align >> NS_STYLE_ALIGN_ALL_SHIFT;
+ if (fallback) {
+ str.Append(' ');
+ nsCSSValue::AppendAlignJustifyValueToString(fallback, str);
+ }
+ val->SetString(str);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAlignItems()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString str;
+ auto align = StylePosition()->mAlignItems;
+ nsCSSValue::AppendAlignJustifyValueToString(align, str);
+ val->SetString(str);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAlignSelf()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString str;
+ auto align = StylePosition()->mAlignSelf;
+ nsCSSValue::AppendAlignJustifyValueToString(align, str);
+ val->SetString(str);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetJustifyContent()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString str;
+ auto justify = StylePosition()->mJustifyContent;
+ nsCSSValue::AppendAlignJustifyValueToString(justify & NS_STYLE_JUSTIFY_ALL_BITS, str);
+ auto fallback = justify >> NS_STYLE_JUSTIFY_ALL_SHIFT;
+ if (fallback) {
+ MOZ_ASSERT(nsCSSProps::ValueToKeywordEnum(fallback & ~NS_STYLE_JUSTIFY_FLAG_BITS,
+ nsCSSProps::kAlignSelfPosition)
+ != eCSSKeyword_UNKNOWN, "unknown fallback value");
+ str.Append(' ');
+ nsCSSValue::AppendAlignJustifyValueToString(fallback, str);
+ }
+ val->SetString(str);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetJustifyItems()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString str;
+ auto justify =
+ StylePosition()->ComputedJustifyItems(mStyleContext->GetParent());
+ nsCSSValue::AppendAlignJustifyValueToString(justify, str);
+ val->SetString(str);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetJustifySelf()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString str;
+ auto justify = StylePosition()->mJustifySelf;
+ nsCSSValue::AppendAlignJustifyValueToString(justify, str);
+ val->SetString(str);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFloatEdge()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(uint8_t(StyleBorder()->mFloatEdge),
+ nsCSSProps::kFloatEdgeKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetForceBrokenImageIcon()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StyleUIReset()->mForceBrokenImageIcon);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetImageOrientation()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString string;
+ nsStyleImageOrientation orientation = StyleVisibility()->mImageOrientation;
+
+ if (orientation.IsFromImage()) {
+ string.AppendLiteral("from-image");
+ } else {
+ nsStyleUtil::AppendAngleValue(orientation.AngleAsCoord(), string);
+
+ if (orientation.IsFlipped()) {
+ string.AppendLiteral(" flip");
+ }
+ }
+
+ val->SetString(string);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetIMEMode()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mIMEMode,
+ nsCSSProps::kIMEModeKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetUserFocus()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(uint8_t(StyleUserInterface()->mUserFocus),
+ nsCSSProps::kUserFocusKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetUserInput()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserInput,
+ nsCSSProps::kUserInputKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetUserModify()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserModify,
+ nsCSSProps::kUserModifyKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetUserSelect()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mUserSelect,
+ nsCSSProps::kUserSelectKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetDisplay()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mDisplay,
+ nsCSSProps::kDisplayKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetContain()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ int32_t mask = StyleDisplay()->mContain;
+
+ if (mask == 0) {
+ val->SetIdent(eCSSKeyword_none);
+ } else if (mask & NS_STYLE_CONTAIN_STRICT) {
+ NS_ASSERTION(mask == (NS_STYLE_CONTAIN_STRICT | NS_STYLE_CONTAIN_ALL_BITS),
+ "contain: strict should imply contain: layout style paint");
+ val->SetIdent(eCSSKeyword_strict);
+ } else {
+ nsAutoString valueStr;
+
+ nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_contain,
+ mask, NS_STYLE_CONTAIN_LAYOUT,
+ NS_STYLE_CONTAIN_PAINT, valueStr);
+ val->SetString(valueStr);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPosition()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mPosition,
+ nsCSSProps::kPositionKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetClip()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleEffects* effects = StyleEffects();
+
+ if (effects->mClipFlags == NS_STYLE_CLIP_AUTO) {
+ val->SetIdent(eCSSKeyword_auto);
+ } else {
+ // create the cssvalues for the sides, stick them in the rect object
+ nsROCSSPrimitiveValue *topVal = new nsROCSSPrimitiveValue;
+ nsROCSSPrimitiveValue *rightVal = new nsROCSSPrimitiveValue;
+ nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue;
+ nsROCSSPrimitiveValue *leftVal = new nsROCSSPrimitiveValue;
+ nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
+ bottomVal, leftVal);
+ if (effects->mClipFlags & NS_STYLE_CLIP_TOP_AUTO) {
+ topVal->SetIdent(eCSSKeyword_auto);
+ } else {
+ topVal->SetAppUnits(effects->mClip.y);
+ }
+
+ if (effects->mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO) {
+ rightVal->SetIdent(eCSSKeyword_auto);
+ } else {
+ rightVal->SetAppUnits(effects->mClip.width + effects->mClip.x);
+ }
+
+ if (effects->mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO) {
+ bottomVal->SetIdent(eCSSKeyword_auto);
+ } else {
+ bottomVal->SetAppUnits(effects->mClip.height + effects->mClip.y);
+ }
+
+ if (effects->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) {
+ leftVal->SetIdent(eCSSKeyword_auto);
+ } else {
+ leftVal->SetAppUnits(effects->mClip.x);
+ }
+ val->SetRect(domRect);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetWillChange()
+{
+ const nsTArray<nsString>& willChange = StyleDisplay()->mWillChange;
+
+ if (willChange.IsEmpty()) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_auto);
+ return val.forget();
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+ for (size_t i = 0; i < willChange.Length(); i++) {
+ const nsString& willChangeIdentifier = willChange[i];
+ RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
+ property->SetString(willChangeIdentifier);
+ valueList->AppendCSSValue(property.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOverflow()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ if (display->mOverflowX != display->mOverflowY) {
+ // No value to return. We can't express this combination of
+ // values as a shorthand.
+ return nullptr;
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(display->mOverflowX,
+ nsCSSProps::kOverflowKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOverflowX()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowX,
+ nsCSSProps::kOverflowSubKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOverflowY()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowY,
+ nsCSSProps::kOverflowSubKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetOverflowClipBox()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBox,
+ nsCSSProps::kOverflowClipBoxKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetResize()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mResize,
+ nsCSSProps::kResizeKTable));
+ return val.forget();
+}
+
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPageBreakAfter()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleDisplay *display = StyleDisplay();
+
+ if (display->mBreakAfter) {
+ val->SetIdent(eCSSKeyword_always);
+ } else {
+ val->SetIdent(eCSSKeyword_auto);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPageBreakBefore()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleDisplay *display = StyleDisplay();
+
+ if (display->mBreakBefore) {
+ val->SetIdent(eCSSKeyword_always);
+ } else {
+ val->SetIdent(eCSSKeyword_auto);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPageBreakInside()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakInside,
+ nsCSSProps::kPageBreakInsideKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTouchAction()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ int32_t intValue = StyleDisplay()->mTouchAction;
+
+ // None and Auto and Manipulation values aren't allowed
+ // to be in conjunction with other values.
+ // But there are all checks in CSSParserImpl::ParseTouchAction
+ nsAutoString valueStr;
+ nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_touch_action, intValue,
+ NS_STYLE_TOUCH_ACTION_NONE, NS_STYLE_TOUCH_ACTION_MANIPULATION,
+ valueStr);
+ val->SetString(valueStr);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetHeight()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ bool calcHeight = false;
+
+ if (mInnerFrame) {
+ calcHeight = true;
+
+ const nsStyleDisplay* displayData = StyleDisplay();
+ if (displayData->mDisplay == mozilla::StyleDisplay::Inline &&
+ !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
+ // An outer SVG frame should behave the same as eReplaced in this case
+ mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) {
+
+ calcHeight = false;
+ }
+ }
+
+ if (calcHeight) {
+ AssertFlushedPendingReflows();
+ nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
+ val->SetAppUnits(mInnerFrame->GetContentRect().height +
+ adjustedValues.TopBottom());
+ } else {
+ const nsStylePosition *positionData = StylePosition();
+
+ nscoord minHeight =
+ StyleCoordToNSCoord(positionData->mMinHeight,
+ &nsComputedDOMStyle::GetCBContentHeight, 0, true);
+
+ nscoord maxHeight =
+ StyleCoordToNSCoord(positionData->mMaxHeight,
+ &nsComputedDOMStyle::GetCBContentHeight,
+ nscoord_MAX, true);
+
+ SetValueToCoord(val, positionData->mHeight, true, nullptr,
+ nsCSSProps::kWidthKTable, minHeight, maxHeight);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetWidth()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ bool calcWidth = false;
+
+ if (mInnerFrame) {
+ calcWidth = true;
+
+ const nsStyleDisplay *displayData = StyleDisplay();
+ if (displayData->mDisplay == mozilla::StyleDisplay::Inline &&
+ !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
+ // An outer SVG frame should behave the same as eReplaced in this case
+ mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) {
+
+ calcWidth = false;
+ }
+ }
+
+ if (calcWidth) {
+ AssertFlushedPendingReflows();
+ nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
+ val->SetAppUnits(mInnerFrame->GetContentRect().width +
+ adjustedValues.LeftRight());
+ } else {
+ const nsStylePosition *positionData = StylePosition();
+
+ nscoord minWidth =
+ StyleCoordToNSCoord(positionData->mMinWidth,
+ &nsComputedDOMStyle::GetCBContentWidth, 0, true);
+
+ nscoord maxWidth =
+ StyleCoordToNSCoord(positionData->mMaxWidth,
+ &nsComputedDOMStyle::GetCBContentWidth,
+ nscoord_MAX, true);
+
+ SetValueToCoord(val, positionData->mWidth, true, nullptr,
+ nsCSSProps::kWidthKTable, minWidth, maxWidth);
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaxHeight()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StylePosition()->mMaxHeight, true,
+ nullptr, nsCSSProps::kWidthKTable);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaxWidth()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StylePosition()->mMaxWidth, true,
+ nullptr, nsCSSProps::kWidthKTable);
+ return val.forget();
+}
+
+bool
+nsComputedDOMStyle::ShouldHonorMinSizeAutoInAxis(PhysicalAxis aAxis)
+{
+ // A {flex,grid} item's min-{width|height} "auto" value gets special
+ // treatment in getComputedStyle().
+ // https://drafts.csswg.org/css-flexbox-1/#valdef-min-width-auto
+ // https://drafts.csswg.org/css-grid/#min-size-auto
+ // In most cases, "min-{width|height}: auto" is mapped to "0px", unless
+ // we're a flex item (and the min-size is in the flex container's main
+ // axis), or we're a grid item, AND we also have overflow:visible.
+
+ // Note: We only need to bother checking one "overflow" subproperty for
+ // "visible", because a non-"visible" value in either axis would force the
+ // other axis to also be non-"visible" as well.
+
+ if (mOuterFrame) {
+ nsIFrame* containerFrame = mOuterFrame->GetParent();
+ if (containerFrame &&
+ StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE) {
+ auto containerType = containerFrame->GetType();
+ if (containerType == nsGkAtoms::flexContainerFrame &&
+ (static_cast<nsFlexContainerFrame*>(containerFrame)->IsHorizontal() ==
+ (aAxis == eAxisHorizontal))) {
+ return true;
+ }
+ if (containerType == nsGkAtoms::gridContainerFrame) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMinHeight()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsStyleCoord minHeight = StylePosition()->mMinHeight;
+
+ if (eStyleUnit_Auto == minHeight.GetUnit() &&
+ !ShouldHonorMinSizeAutoInAxis(eAxisVertical)) {
+ minHeight.SetCoordValue(0);
+ }
+
+ SetValueToCoord(val, minHeight, true, nullptr, nsCSSProps::kWidthKTable);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMinWidth()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ nsStyleCoord minWidth = StylePosition()->mMinWidth;
+
+ if (eStyleUnit_Auto == minWidth.GetUnit() &&
+ !ShouldHonorMinSizeAutoInAxis(eAxisHorizontal)) {
+ minWidth.SetCoordValue(0);
+ }
+
+ SetValueToCoord(val, minWidth, true, nullptr, nsCSSProps::kWidthKTable);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMixBlendMode()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleEffects()->mMixBlendMode,
+ nsCSSProps::kBlendModeKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetIsolation()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mIsolation,
+ nsCSSProps::kIsolationKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetObjectFit()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StylePosition()->mObjectFit,
+ nsCSSProps::kObjectFitKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetObjectPosition()
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ SetValueToPosition(StylePosition()->mObjectPosition, valueList);
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetLeft()
+{
+ return GetOffsetWidthFor(NS_SIDE_LEFT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetRight()
+{
+ return GetOffsetWidthFor(NS_SIDE_RIGHT);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTop()
+{
+ return GetOffsetWidthFor(NS_SIDE_TOP);
+}
+
+nsDOMCSSValueList*
+nsComputedDOMStyle::GetROCSSValueList(bool aCommaDelimited)
+{
+ return new nsDOMCSSValueList(aCommaDelimited, true);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetOffsetWidthFor(mozilla::css::Side aSide)
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ AssertFlushedPendingReflows();
+
+ uint8_t position = display->mPosition;
+ if (!mOuterFrame) {
+ // GetRelativeOffset and GetAbsoluteOffset don't handle elements
+ // without frames in any sensible way. GetStaticOffset, however,
+ // is perfect for that case.
+ position = NS_STYLE_POSITION_STATIC;
+ }
+
+ switch (position) {
+ case NS_STYLE_POSITION_STATIC:
+ return GetStaticOffset(aSide);
+ case NS_STYLE_POSITION_RELATIVE:
+ return GetRelativeOffset(aSide);
+ case NS_STYLE_POSITION_STICKY:
+ return GetStickyOffset(aSide);
+ case NS_STYLE_POSITION_ABSOLUTE:
+ case NS_STYLE_POSITION_FIXED:
+ return GetAbsoluteOffset(aSide);
+ default:
+ NS_ERROR("Invalid position");
+ return nullptr;
+ }
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetAbsoluteOffset(mozilla::css::Side aSide)
+{
+ MOZ_ASSERT(mOuterFrame, "need a frame, so we can call GetContainingBlock()");
+
+ nsIFrame* container = mOuterFrame->GetContainingBlock();
+ nsMargin margin = mOuterFrame->GetUsedMargin();
+ nsMargin border = container->GetUsedBorder();
+ nsMargin scrollbarSizes(0, 0, 0, 0);
+ nsRect rect = mOuterFrame->GetRect();
+ nsRect containerRect = container->GetRect();
+
+ if (container->GetType() == nsGkAtoms::viewportFrame) {
+ // For absolutely positioned frames scrollbars are taken into
+ // account by virtue of getting a containing block that does
+ // _not_ include the scrollbars. For fixed positioned frames,
+ // the containing block is the viewport, which _does_ include
+ // scrollbars. We have to do some extra work.
+ // the first child in the default frame list is what we want
+ nsIFrame* scrollingChild = container->PrincipalChildList().FirstChild();
+ nsIScrollableFrame *scrollFrame = do_QueryFrame(scrollingChild);
+ if (scrollFrame) {
+ scrollbarSizes = scrollFrame->GetActualScrollbarSizes();
+ }
+ }
+
+ nscoord offset = 0;
+ switch (aSide) {
+ case NS_SIDE_TOP:
+ offset = rect.y - margin.top - border.top - scrollbarSizes.top;
+
+ break;
+ case NS_SIDE_RIGHT:
+ offset = containerRect.width - rect.width -
+ rect.x - margin.right - border.right - scrollbarSizes.right;
+
+ break;
+ case NS_SIDE_BOTTOM:
+ offset = containerRect.height - rect.height -
+ rect.y - margin.bottom - border.bottom - scrollbarSizes.bottom;
+
+ break;
+ case NS_SIDE_LEFT:
+ offset = rect.x - margin.left - border.left - scrollbarSizes.left;
+
+ break;
+ default:
+ NS_ERROR("Invalid side");
+ break;
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetAppUnits(offset);
+ return val.forget();
+}
+
+static_assert(NS_SIDE_TOP == 0 && NS_SIDE_RIGHT == 1 &&
+ NS_SIDE_BOTTOM == 2 && NS_SIDE_LEFT == 3,
+ "box side constants not as expected for NS_OPPOSITE_SIDE");
+#define NS_OPPOSITE_SIDE(s_) mozilla::css::Side(((s_) + 2) & 3)
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetRelativeOffset(mozilla::css::Side aSide)
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStylePosition* positionData = StylePosition();
+ int32_t sign = 1;
+ nsStyleCoord coord = positionData->mOffset.Get(aSide);
+
+ NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
+ coord.GetUnit() == eStyleUnit_Percent ||
+ coord.GetUnit() == eStyleUnit_Auto ||
+ coord.IsCalcUnit(),
+ "Unexpected unit");
+
+ if (coord.GetUnit() == eStyleUnit_Auto) {
+ coord = positionData->mOffset.Get(NS_OPPOSITE_SIDE(aSide));
+ sign = -1;
+ }
+ PercentageBaseGetter baseGetter;
+ if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) {
+ baseGetter = &nsComputedDOMStyle::GetCBContentWidth;
+ } else {
+ baseGetter = &nsComputedDOMStyle::GetCBContentHeight;
+ }
+
+ val->SetAppUnits(sign * StyleCoordToNSCoord(coord, baseGetter, 0, false));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetStickyOffset(mozilla::css::Side aSide)
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStylePosition* positionData = StylePosition();
+ nsStyleCoord coord = positionData->mOffset.Get(aSide);
+
+ NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
+ coord.GetUnit() == eStyleUnit_Percent ||
+ coord.GetUnit() == eStyleUnit_Auto ||
+ coord.IsCalcUnit(),
+ "Unexpected unit");
+
+ if (coord.GetUnit() == eStyleUnit_Auto) {
+ val->SetIdent(eCSSKeyword_auto);
+ return val.forget();
+ }
+ PercentageBaseGetter baseGetter;
+ if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) {
+ baseGetter = &nsComputedDOMStyle::GetScrollFrameContentWidth;
+ } else {
+ baseGetter = &nsComputedDOMStyle::GetScrollFrameContentHeight;
+ }
+
+ val->SetAppUnits(StyleCoordToNSCoord(coord, baseGetter, 0, false));
+ return val.forget();
+}
+
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetStaticOffset(mozilla::css::Side aSide)
+
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StylePosition()->mOffset.Get(aSide), false);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetPaddingWidthFor(mozilla::css::Side aSide)
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ if (!mInnerFrame) {
+ SetValueToCoord(val, StylePadding()->mPadding.Get(aSide), true);
+ } else {
+ AssertFlushedPendingReflows();
+
+ val->SetAppUnits(mInnerFrame->GetUsedPadding().Side(aSide));
+ }
+
+ return val.forget();
+}
+
+bool
+nsComputedDOMStyle::GetLineHeightCoord(nscoord& aCoord)
+{
+ AssertFlushedPendingReflows();
+
+ nscoord blockHeight = NS_AUTOHEIGHT;
+ if (StyleText()->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
+ if (!mInnerFrame)
+ return false;
+
+ if (nsLayoutUtils::IsNonWrapperBlock(mInnerFrame)) {
+ blockHeight = mInnerFrame->GetContentRect().height;
+ } else {
+ GetCBContentHeight(blockHeight);
+ }
+ }
+
+ // lie about font size inflation since we lie about font size (since
+ // the inflation only applies to text)
+ aCoord = ReflowInput::CalcLineHeight(mContent, mStyleContext,
+ blockHeight, 1.0f);
+
+ // CalcLineHeight uses font->mFont.size, but we want to use
+ // font->mSize as the font size. Adjust for that. Also adjust for
+ // the text zoom, if any.
+ const nsStyleFont* font = StyleFont();
+ float fCoord = float(aCoord);
+ if (font->mAllowZoom) {
+ fCoord /= mPresShell->GetPresContext()->TextZoom();
+ }
+ if (font->mFont.size != font->mSize) {
+ fCoord = fCoord * (float(font->mSize) / float(font->mFont.size));
+ }
+ aCoord = NSToCoordRound(fCoord);
+
+ return true;
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetBorderColorsFor(mozilla::css::Side aSide)
+{
+ const nsStyleBorder *border = StyleBorder();
+
+ if (border->mBorderColors) {
+ nsBorderColors* borderColors = border->mBorderColors[aSide];
+ if (borderColors) {
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+ do {
+ RefPtr<nsROCSSPrimitiveValue> primitive = new nsROCSSPrimitiveValue;
+
+ SetToRGBAColor(primitive, borderColors->mColor);
+
+ valueList->AppendCSSValue(primitive.forget());
+ borderColors = borderColors->mNext;
+ } while (borderColors);
+
+ return valueList.forget();
+ }
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetBorderWidthFor(mozilla::css::Side aSide)
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ nscoord width;
+ if (mInnerFrame) {
+ AssertFlushedPendingReflows();
+ width = mInnerFrame->GetUsedBorder().Side(aSide);
+ } else {
+ width = StyleBorder()->GetComputedBorderWidth(aSide);
+ }
+ val->SetAppUnits(width);
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetBorderColorFor(mozilla::css::Side aSide)
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueFromComplexColor(val, StyleBorder()->mBorderColor[aSide]);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetMarginWidthFor(mozilla::css::Side aSide)
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ if (!mInnerFrame) {
+ SetValueToCoord(val, StyleMargin()->mMargin.Get(aSide), false);
+ } else {
+ AssertFlushedPendingReflows();
+
+ // For tables, GetUsedMargin always returns an empty margin, so we
+ // should read the margin from the table wrapper frame instead.
+ val->SetAppUnits(mOuterFrame->GetUsedMargin().Side(aSide));
+ NS_ASSERTION(mOuterFrame == mInnerFrame ||
+ mInnerFrame->GetUsedMargin() == nsMargin(0, 0, 0, 0),
+ "Inner tables must have zero margins");
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetBorderStyleFor(mozilla::css::Side aSide)
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleBorder()->GetBorderStyle(aSide),
+ nsCSSProps::kBorderStyleKTable));
+ return val.forget();
+}
+
+void
+nsComputedDOMStyle::SetValueToCoord(nsROCSSPrimitiveValue* aValue,
+ const nsStyleCoord& aCoord,
+ bool aClampNegativeCalc,
+ PercentageBaseGetter aPercentageBaseGetter,
+ const KTableEntry aTable[],
+ nscoord aMinAppUnits,
+ nscoord aMaxAppUnits)
+{
+ NS_PRECONDITION(aValue, "Must have a value to work with");
+
+ switch (aCoord.GetUnit()) {
+ case eStyleUnit_Normal:
+ aValue->SetIdent(eCSSKeyword_normal);
+ break;
+
+ case eStyleUnit_Auto:
+ aValue->SetIdent(eCSSKeyword_auto);
+ break;
+
+ case eStyleUnit_Percent:
+ {
+ nscoord percentageBase;
+ if (aPercentageBaseGetter &&
+ (this->*aPercentageBaseGetter)(percentageBase)) {
+ nscoord val = NSCoordSaturatingMultiply(percentageBase,
+ aCoord.GetPercentValue());
+ aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
+ } else {
+ aValue->SetPercent(aCoord.GetPercentValue());
+ }
+ }
+ break;
+
+ case eStyleUnit_Factor:
+ aValue->SetNumber(aCoord.GetFactorValue());
+ break;
+
+ case eStyleUnit_Coord:
+ {
+ nscoord val = aCoord.GetCoordValue();
+ aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
+ }
+ break;
+
+ case eStyleUnit_Integer:
+ aValue->SetNumber(aCoord.GetIntValue());
+ break;
+
+ case eStyleUnit_Enumerated:
+ NS_ASSERTION(aTable, "Must have table to handle this case");
+ aValue->SetIdent(nsCSSProps::ValueToKeywordEnum(aCoord.GetIntValue(),
+ aTable));
+ break;
+
+ case eStyleUnit_None:
+ aValue->SetIdent(eCSSKeyword_none);
+ break;
+
+ case eStyleUnit_Calc:
+ nscoord percentageBase;
+ if (!aCoord.CalcHasPercent()) {
+ nscoord val = nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
+ if (aClampNegativeCalc && val < 0) {
+ MOZ_ASSERT(aCoord.IsCalcUnit(),
+ "parser should have rejected value");
+ val = 0;
+ }
+ aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
+ } else if (aPercentageBaseGetter &&
+ (this->*aPercentageBaseGetter)(percentageBase)) {
+ nscoord val =
+ nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase);
+ if (aClampNegativeCalc && val < 0) {
+ MOZ_ASSERT(aCoord.IsCalcUnit(),
+ "parser should have rejected value");
+ val = 0;
+ }
+ aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
+ } else {
+ nsStyleCoord::Calc *calc = aCoord.GetCalcValue();
+ SetValueToCalc(calc, aValue);
+ }
+ break;
+
+ case eStyleUnit_Degree:
+ aValue->SetDegree(aCoord.GetAngleValue());
+ break;
+
+ case eStyleUnit_Grad:
+ aValue->SetGrad(aCoord.GetAngleValue());
+ break;
+
+ case eStyleUnit_Radian:
+ aValue->SetRadian(aCoord.GetAngleValue());
+ break;
+
+ case eStyleUnit_Turn:
+ aValue->SetTurn(aCoord.GetAngleValue());
+ break;
+
+ case eStyleUnit_FlexFraction: {
+ nsAutoString tmpStr;
+ nsStyleUtil::AppendCSSNumber(aCoord.GetFlexFractionValue(), tmpStr);
+ tmpStr.AppendLiteral("fr");
+ aValue->SetString(tmpStr);
+ break;
+ }
+
+ default:
+ NS_ERROR("Can't handle this unit");
+ break;
+ }
+}
+
+nscoord
+nsComputedDOMStyle::StyleCoordToNSCoord(const nsStyleCoord& aCoord,
+ PercentageBaseGetter aPercentageBaseGetter,
+ nscoord aDefaultValue,
+ bool aClampNegativeCalc)
+{
+ NS_PRECONDITION(aPercentageBaseGetter, "Must have a percentage base getter");
+ if (aCoord.GetUnit() == eStyleUnit_Coord) {
+ return aCoord.GetCoordValue();
+ }
+ if (aCoord.GetUnit() == eStyleUnit_Percent || aCoord.IsCalcUnit()) {
+ nscoord percentageBase;
+ if ((this->*aPercentageBaseGetter)(percentageBase)) {
+ nscoord result =
+ nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase);
+ if (aClampNegativeCalc && result < 0) {
+ // It's expected that we can get a negative value here with calc().
+ // We can also get a negative value with a percentage value if
+ // percentageBase is negative; this isn't expected, but can happen
+ // when large length values overflow.
+ NS_WARNING_ASSERTION(
+ percentageBase >= 0,
+ "percentage base value overflowed to become negative for a property "
+ "that disallows negative values");
+ MOZ_ASSERT(aCoord.IsCalcUnit() ||
+ (aCoord.HasPercent() && percentageBase < 0),
+ "parser should have rejected value");
+ result = 0;
+ }
+ return result;
+ }
+ // Fall through to returning aDefaultValue if we have no percentage base.
+ }
+
+ return aDefaultValue;
+}
+
+bool
+nsComputedDOMStyle::GetCBContentWidth(nscoord& aWidth)
+{
+ if (!mOuterFrame) {
+ return false;
+ }
+
+ AssertFlushedPendingReflows();
+
+ nsIFrame* container = mOuterFrame->GetContainingBlock();
+ aWidth = container->GetContentRect().width;
+ return true;
+}
+
+bool
+nsComputedDOMStyle::GetCBContentHeight(nscoord& aHeight)
+{
+ if (!mOuterFrame) {
+ return false;
+ }
+
+ AssertFlushedPendingReflows();
+
+ nsIFrame* container = mOuterFrame->GetContainingBlock();
+ aHeight = container->GetContentRect().height;
+ return true;
+}
+
+bool
+nsComputedDOMStyle::GetScrollFrameContentWidth(nscoord& aWidth)
+{
+ if (!mOuterFrame) {
+ return false;
+ }
+
+ AssertFlushedPendingReflows();
+
+ nsIScrollableFrame* scrollableFrame =
+ nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(),
+ nsLayoutUtils::SCROLLABLE_SAME_DOC |
+ nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
+
+ if (!scrollableFrame) {
+ return false;
+ }
+ aWidth =
+ scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().width;
+ return true;
+}
+
+bool
+nsComputedDOMStyle::GetScrollFrameContentHeight(nscoord& aHeight)
+{
+ if (!mOuterFrame) {
+ return false;
+ }
+
+ AssertFlushedPendingReflows();
+
+ nsIScrollableFrame* scrollableFrame =
+ nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(),
+ nsLayoutUtils::SCROLLABLE_SAME_DOC |
+ nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
+
+ if (!scrollableFrame) {
+ return false;
+ }
+ aHeight =
+ scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().height;
+ return true;
+}
+
+bool
+nsComputedDOMStyle::GetFrameBorderRectWidth(nscoord& aWidth)
+{
+ if (!mInnerFrame) {
+ return false;
+ }
+
+ AssertFlushedPendingReflows();
+
+ aWidth = mInnerFrame->GetSize().width;
+ return true;
+}
+
+bool
+nsComputedDOMStyle::GetFrameBorderRectHeight(nscoord& aHeight)
+{
+ if (!mInnerFrame) {
+ return false;
+ }
+
+ AssertFlushedPendingReflows();
+
+ aHeight = mInnerFrame->GetSize().height;
+ return true;
+}
+
+bool
+nsComputedDOMStyle::GetFrameBoundsWidthForTransform(nscoord& aWidth)
+{
+ // We need a frame to work with.
+ if (!mInnerFrame) {
+ return false;
+ }
+
+ AssertFlushedPendingReflows();
+
+ aWidth = nsStyleTransformMatrix::TransformReferenceBox(mInnerFrame).Width();
+ return true;
+}
+
+bool
+nsComputedDOMStyle::GetFrameBoundsHeightForTransform(nscoord& aHeight)
+{
+ // We need a frame to work with.
+ if (!mInnerFrame) {
+ return false;
+ }
+
+ AssertFlushedPendingReflows();
+
+ aHeight = nsStyleTransformMatrix::TransformReferenceBox(mInnerFrame).Height();
+ return true;
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetSVGPaintFor(bool aFill)
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ const nsStyleSVG* svg = StyleSVG();
+ const nsStyleSVGPaint* paint = nullptr;
+
+ if (aFill)
+ paint = &svg->mFill;
+ else
+ paint = &svg->mStroke;
+
+ nsAutoString paintString;
+
+ switch (paint->Type()) {
+ case eStyleSVGPaintType_None:
+ val->SetIdent(eCSSKeyword_none);
+ break;
+ case eStyleSVGPaintType_Color:
+ SetToRGBAColor(val, paint->GetColor());
+ break;
+ case eStyleSVGPaintType_Server: {
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ RefPtr<nsROCSSPrimitiveValue> fallback = new nsROCSSPrimitiveValue;
+ SetValueToURLValue(paint->GetPaintServer(), val);
+ SetToRGBAColor(fallback, paint->GetFallbackColor());
+
+ valueList->AppendCSSValue(val.forget());
+ valueList->AppendCSSValue(fallback.forget());
+ return valueList.forget();
+ }
+ case eStyleSVGPaintType_ContextFill:
+ val->SetIdent(eCSSKeyword_context_fill);
+ // XXXheycam context-fill and context-stroke can have fallback colors,
+ // so they should be serialized here too
+ break;
+ case eStyleSVGPaintType_ContextStroke:
+ val->SetIdent(eCSSKeyword_context_stroke);
+ break;
+ }
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFill()
+{
+ return GetSVGPaintFor(true);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetStroke()
+{
+ return GetSVGPaintFor(false);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMarkerEnd()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToURLValue(StyleSVG()->mMarkerEnd, val);
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMarkerMid()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToURLValue(StyleSVG()->mMarkerMid, val);
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMarkerStart()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToURLValue(StyleSVG()->mMarkerStart, val);
+
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetStrokeDasharray()
+{
+ const nsStyleSVG* svg = StyleSVG();
+
+ if (svg->mStrokeDasharray.IsEmpty()) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ for (uint32_t i = 0; i < svg->mStrokeDasharray.Length(); i++) {
+ RefPtr<nsROCSSPrimitiveValue> dash = new nsROCSSPrimitiveValue;
+ SetValueToCoord(dash, svg->mStrokeDasharray[i], true);
+ valueList->AppendCSSValue(dash.forget());
+ }
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetStrokeDashoffset()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StyleSVG()->mStrokeDashoffset, false);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetStrokeWidth()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToCoord(val, StyleSVG()->mStrokeWidth, true);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetVectorEffect()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mVectorEffect,
+ nsCSSProps::kVectorEffectKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFillOpacity()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StyleSVG()->mFillOpacity);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFloodOpacity()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StyleSVGReset()->mFloodOpacity);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetStopOpacity()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StyleSVGReset()->mStopOpacity);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetStrokeMiterlimit()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StyleSVG()->mStrokeMiterlimit);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetStrokeOpacity()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetNumber(StyleSVG()->mStrokeOpacity);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetClipRule()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(
+ StyleSVG()->mClipRule, nsCSSProps::kFillRuleKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFillRule()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(
+ StyleSVG()->mFillRule, nsCSSProps::kFillRuleKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetStrokeLinecap()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinecap,
+ nsCSSProps::kStrokeLinecapKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetStrokeLinejoin()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinejoin,
+ nsCSSProps::kStrokeLinejoinKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextAnchor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleSVG()->mTextAnchor,
+ nsCSSProps::kTextAnchorKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColorInterpolation()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolation,
+ nsCSSProps::kColorInterpolationKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetColorInterpolationFilters()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolationFilters,
+ nsCSSProps::kColorInterpolationKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetDominantBaseline()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mDominantBaseline,
+ nsCSSProps::kDominantBaselineKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetImageRendering()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mImageRendering,
+ nsCSSProps::kImageRenderingKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetShapeRendering()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleSVG()->mShapeRendering,
+ nsCSSProps::kShapeRenderingKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTextRendering()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleText()->mTextRendering,
+ nsCSSProps::kTextRenderingKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFloodColor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetToRGBAColor(val, StyleSVGReset()->mFloodColor);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetLightingColor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetToRGBAColor(val, StyleSVGReset()->mLightingColor);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetStopColor()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetToRGBAColor(val, StyleSVGReset()->mStopColor);
+ return val.forget();
+}
+
+void
+nsComputedDOMStyle::BoxValuesToString(nsAString& aString,
+ const nsTArray<nsStyleCoord>& aBoxValues)
+{
+ MOZ_ASSERT(aBoxValues.Length() == 4, "wrong number of box values");
+ nsAutoString value1, value2, value3, value4;
+ SetCssTextToCoord(value1, aBoxValues[0]);
+ SetCssTextToCoord(value2, aBoxValues[1]);
+ SetCssTextToCoord(value3, aBoxValues[2]);
+ SetCssTextToCoord(value4, aBoxValues[3]);
+
+ // nsROCSSPrimitiveValue do not have binary comparison operators.
+ // Compare string results instead.
+ aString.Append(value1);
+ if (value1 != value2 || value1 != value3 || value1 != value4) {
+ aString.Append(' ');
+ aString.Append(value2);
+ if (value1 != value3 || value2 != value4) {
+ aString.Append(' ');
+ aString.Append(value3);
+ if (value2 != value4) {
+ aString.Append(' ');
+ aString.Append(value4);
+ }
+ }
+ }
+}
+
+void
+nsComputedDOMStyle::BasicShapeRadiiToString(nsAString& aCssText,
+ const nsStyleCorners& aCorners)
+{
+ nsTArray<nsStyleCoord> horizontal, vertical;
+ nsAutoString horizontalString, verticalString;
+ NS_FOR_CSS_FULL_CORNERS(corner) {
+ horizontal.AppendElement(
+ aCorners.Get(NS_FULL_TO_HALF_CORNER(corner, false)));
+ vertical.AppendElement(
+ aCorners.Get(NS_FULL_TO_HALF_CORNER(corner, true)));
+ }
+ BoxValuesToString(horizontalString, horizontal);
+ BoxValuesToString(verticalString, vertical);
+ aCssText.Append(horizontalString);
+ if (horizontalString == verticalString) {
+ return;
+ }
+ aCssText.AppendLiteral(" / ");
+ aCssText.Append(verticalString);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::CreatePrimitiveValueForBasicShape(
+ const StyleBasicShape* aStyleBasicShape)
+{
+ MOZ_ASSERT(aStyleBasicShape, "Expect a valid basic shape pointer!");
+
+ StyleBasicShapeType type = aStyleBasicShape->GetShapeType();
+ // Shape function name and opening parenthesis.
+ nsAutoString shapeFunctionString;
+ AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(
+ aStyleBasicShape->GetShapeTypeName()),
+ shapeFunctionString);
+ shapeFunctionString.Append('(');
+ switch (type) {
+ case StyleBasicShapeType::Polygon: {
+ bool hasEvenOdd = aStyleBasicShape->GetFillRule() ==
+ StyleFillRule::Evenodd;
+ if (hasEvenOdd) {
+ shapeFunctionString.AppendLiteral("evenodd");
+ }
+ for (size_t i = 0;
+ i < aStyleBasicShape->Coordinates().Length(); i += 2) {
+ nsAutoString coordString;
+ if (i > 0 || hasEvenOdd) {
+ shapeFunctionString.AppendLiteral(", ");
+ }
+ SetCssTextToCoord(coordString,
+ aStyleBasicShape->Coordinates()[i]);
+ shapeFunctionString.Append(coordString);
+ shapeFunctionString.Append(' ');
+ SetCssTextToCoord(coordString,
+ aStyleBasicShape->Coordinates()[i + 1]);
+ shapeFunctionString.Append(coordString);
+ }
+ break;
+ }
+ case StyleBasicShapeType::Circle:
+ case StyleBasicShapeType::Ellipse: {
+ const nsTArray<nsStyleCoord>& radii = aStyleBasicShape->Coordinates();
+ MOZ_ASSERT(radii.Length() ==
+ (type == StyleBasicShapeType::Circle ? 1 : 2),
+ "wrong number of radii");
+ for (size_t i = 0; i < radii.Length(); ++i) {
+ nsAutoString radius;
+ RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
+ bool clampNegativeCalc = true;
+ SetValueToCoord(value, radii[i], clampNegativeCalc, nullptr,
+ nsCSSProps::kShapeRadiusKTable);
+ value->GetCssText(radius);
+ shapeFunctionString.Append(radius);
+ shapeFunctionString.Append(' ');
+ }
+ shapeFunctionString.AppendLiteral("at ");
+
+ RefPtr<nsDOMCSSValueList> position = GetROCSSValueList(false);
+ nsAutoString positionString;
+ SetValueToPosition(aStyleBasicShape->GetPosition(), position);
+ position->GetCssText(positionString);
+ shapeFunctionString.Append(positionString);
+ break;
+ }
+ case StyleBasicShapeType::Inset: {
+ BoxValuesToString(shapeFunctionString, aStyleBasicShape->Coordinates());
+ if (aStyleBasicShape->HasRadius()) {
+ shapeFunctionString.AppendLiteral(" round ");
+ nsAutoString radiiString;
+ BasicShapeRadiiToString(radiiString, aStyleBasicShape->GetRadius());
+ shapeFunctionString.Append(radiiString);
+ }
+ break;
+ }
+ default:
+ NS_NOTREACHED("unexpected type");
+ }
+ shapeFunctionString.Append(')');
+ RefPtr<nsROCSSPrimitiveValue> functionValue = new nsROCSSPrimitiveValue;
+ functionValue->SetString(shapeFunctionString);
+ return functionValue.forget();
+}
+
+template<typename ReferenceBox>
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::CreatePrimitiveValueForShapeSource(
+ const StyleBasicShape* aStyleBasicShape,
+ ReferenceBox aReferenceBox,
+ const KTableEntry aBoxKeywordTable[])
+{
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ if (aStyleBasicShape) {
+ valueList->AppendCSSValue(
+ CreatePrimitiveValueForBasicShape(aStyleBasicShape));
+ }
+
+ if (aReferenceBox == ReferenceBox::NoBox) {
+ return valueList.forget();
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(nsCSSProps::ValueToKeywordEnum(aReferenceBox, aBoxKeywordTable));
+ valueList->AppendCSSValue(val.forget());
+
+ return valueList.forget();
+}
+
+template<typename ReferenceBox>
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::GetShapeSource(
+ const StyleShapeSource<ReferenceBox>& aShapeSource,
+ const KTableEntry aBoxKeywordTable[])
+{
+ switch (aShapeSource.GetType()) {
+ case StyleShapeSourceType::Shape:
+ return CreatePrimitiveValueForShapeSource(aShapeSource.GetBasicShape(),
+ aShapeSource.GetReferenceBox(),
+ aBoxKeywordTable);
+ case StyleShapeSourceType::Box:
+ return CreatePrimitiveValueForShapeSource(nullptr,
+ aShapeSource.GetReferenceBox(),
+ aBoxKeywordTable);
+ case StyleShapeSourceType::URL: {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToURLValue(aShapeSource.GetURL(), val);
+ return val.forget();
+ }
+ case StyleShapeSourceType::None: {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(eCSSKeyword_none);
+ return val.forget();
+ }
+ default:
+ NS_NOTREACHED("unexpected type");
+ }
+ return nullptr;
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetClipPath()
+{
+ return GetShapeSource(StyleSVGReset()->mClipPath,
+ nsCSSProps::kClipPathGeometryBoxKTable);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetShapeOutside()
+{
+ return GetShapeSource(StyleDisplay()->mShapeOutside,
+ nsCSSProps::kShapeOutsideShapeBoxKTable);
+}
+
+void
+nsComputedDOMStyle::SetCssTextToCoord(nsAString& aCssText,
+ const nsStyleCoord& aCoord)
+{
+ RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
+ bool clampNegativeCalc = true;
+ SetValueToCoord(value, aCoord, clampNegativeCalc);
+ value->GetCssText(aCssText);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::CreatePrimitiveValueForStyleFilter(
+ const nsStyleFilter& aStyleFilter)
+{
+ RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
+ // Handle url().
+ if (aStyleFilter.GetType() == NS_STYLE_FILTER_URL) {
+ MOZ_ASSERT(aStyleFilter.GetURL() &&
+ aStyleFilter.GetURL()->GetURI());
+ SetValueToURLValue(aStyleFilter.GetURL(), value);
+ return value.forget();
+ }
+
+ // Filter function name and opening parenthesis.
+ nsAutoString filterFunctionString;
+ AppendASCIItoUTF16(
+ nsCSSProps::ValueToKeyword(aStyleFilter.GetType(),
+ nsCSSProps::kFilterFunctionKTable),
+ filterFunctionString);
+ filterFunctionString.Append('(');
+
+ nsAutoString argumentString;
+ if (aStyleFilter.GetType() == NS_STYLE_FILTER_DROP_SHADOW) {
+ // Handle drop-shadow()
+ RefPtr<CSSValue> shadowValue =
+ GetCSSShadowArray(aStyleFilter.GetDropShadow(),
+ StyleColor()->mColor,
+ false);
+ ErrorResult dummy;
+ shadowValue->GetCssText(argumentString, dummy);
+ } else {
+ // Filter function argument.
+ SetCssTextToCoord(argumentString, aStyleFilter.GetFilterParameter());
+ }
+ filterFunctionString.Append(argumentString);
+
+ // Filter function closing parenthesis.
+ filterFunctionString.Append(')');
+
+ value->SetString(filterFunctionString);
+ return value.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetFilter()
+{
+ const nsTArray<nsStyleFilter>& filters = StyleEffects()->mFilters;
+
+ if (filters.IsEmpty()) {
+ RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
+ value->SetIdent(eCSSKeyword_none);
+ return value.forget();
+ }
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+ for(uint32_t i = 0; i < filters.Length(); i++) {
+ RefPtr<CSSValue> value = CreatePrimitiveValueForStyleFilter(filters[i]);
+ valueList->AppendCSSValue(value.forget());
+ }
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMask()
+{
+ const nsStyleSVGReset* svg = StyleSVGReset();
+ const nsStyleImageLayers::Layer& firstLayer = svg->mMask.mLayers[0];
+
+ // Mask is now a shorthand, but it used to be a longhand, so that we
+ // need to support computed style for the cases where it used to be
+ // a longhand.
+ if (svg->mMask.mImageCount > 1 ||
+ firstLayer.mClip != NS_STYLE_IMAGELAYER_CLIP_BORDER ||
+ firstLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_BORDER ||
+ firstLayer.mComposite != NS_STYLE_MASK_COMPOSITE_ADD ||
+ firstLayer.mMaskMode != NS_STYLE_MASK_MODE_MATCH_SOURCE ||
+ !nsStyleImageLayers::IsInitialPositionForLayerType(
+ firstLayer.mPosition, nsStyleImageLayers::LayerType::Mask) ||
+ !firstLayer.mRepeat.IsInitialValue() ||
+ !firstLayer.mSize.IsInitialValue() ||
+ !(firstLayer.mImage.GetType() == eStyleImageType_Null ||
+ firstLayer.mImage.GetType() == eStyleImageType_Image)) {
+ return nullptr;
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+
+ SetValueToURLValue(firstLayer.mSourceURI, val);
+
+ return val.forget();
+}
+
+#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaskClip()
+{
+ return GetBackgroundList(&nsStyleImageLayers::Layer::mClip,
+ &nsStyleImageLayers::mClipCount,
+ StyleSVGReset()->mMask,
+ nsCSSProps::kImageLayerOriginKTable);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaskComposite()
+{
+ return GetBackgroundList(&nsStyleImageLayers::Layer::mComposite,
+ &nsStyleImageLayers::mCompositeCount,
+ StyleSVGReset()->mMask,
+ nsCSSProps::kImageLayerCompositeKTable);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaskImage()
+{
+ const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
+ return DoGetImageLayerImage(layers);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaskMode()
+{
+ return GetBackgroundList(&nsStyleImageLayers::Layer::mMaskMode,
+ &nsStyleImageLayers::mMaskModeCount,
+ StyleSVGReset()->mMask,
+ nsCSSProps::kImageLayerModeKTable);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaskOrigin()
+{
+ return GetBackgroundList(&nsStyleImageLayers::Layer::mOrigin,
+ &nsStyleImageLayers::mOriginCount,
+ StyleSVGReset()->mMask,
+ nsCSSProps::kImageLayerOriginKTable);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaskPosition()
+{
+ const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
+ return DoGetImageLayerPosition(layers);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaskPositionX()
+{
+ const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
+ return DoGetImageLayerPositionX(layers);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaskPositionY()
+{
+ const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
+ return DoGetImageLayerPositionY(layers);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaskRepeat()
+{
+ const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
+ return DoGetImageLayerRepeat(layers);
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaskSize()
+{
+ const nsStyleImageLayers& layers = StyleSVGReset()->mMask;
+ return DoGetImageLayerSize(layers);
+}
+#endif
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetMaskType()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mMaskType,
+ nsCSSProps::kMaskTypeKTable));
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetPaintOrder()
+{
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ nsAutoString string;
+ uint8_t paintOrder = StyleSVG()->mPaintOrder;
+ nsStyleUtil::AppendPaintOrderValue(paintOrder, string);
+ val->SetString(string);
+ return val.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTransitionDelay()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mTransitionDelayCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ const StyleTransition *transition = &display->mTransitions[i];
+ RefPtr<nsROCSSPrimitiveValue> delay = new nsROCSSPrimitiveValue;
+ delay->SetTime((float)transition->GetDelay() / (float)PR_MSEC_PER_SEC);
+ valueList->AppendCSSValue(delay.forget());
+ } while (++i < display->mTransitionDelayCount);
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTransitionDuration()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mTransitionDurationCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ const StyleTransition *transition = &display->mTransitions[i];
+ RefPtr<nsROCSSPrimitiveValue> duration = new nsROCSSPrimitiveValue;
+
+ duration->SetTime((float)transition->GetDuration() / (float)PR_MSEC_PER_SEC);
+ valueList->AppendCSSValue(duration.forget());
+ } while (++i < display->mTransitionDurationCount);
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTransitionProperty()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mTransitionPropertyCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ const StyleTransition *transition = &display->mTransitions[i];
+ RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
+ nsCSSPropertyID cssprop = transition->GetProperty();
+ if (cssprop == eCSSPropertyExtra_all_properties)
+ property->SetIdent(eCSSKeyword_all);
+ else if (cssprop == eCSSPropertyExtra_no_properties)
+ property->SetIdent(eCSSKeyword_none);
+ else if (cssprop == eCSSProperty_UNKNOWN ||
+ cssprop == eCSSPropertyExtra_variable)
+ {
+ nsAutoString escaped;
+ nsStyleUtil::AppendEscapedCSSIdent(
+ nsDependentAtomString(transition->GetUnknownProperty()), escaped);
+ property->SetString(escaped); // really want SetIdent
+ }
+ else
+ property->SetString(nsCSSProps::GetStringValue(cssprop));
+
+ valueList->AppendCSSValue(property.forget());
+ } while (++i < display->mTransitionPropertyCount);
+
+ return valueList.forget();
+}
+
+void
+nsComputedDOMStyle::AppendTimingFunction(nsDOMCSSValueList *aValueList,
+ const nsTimingFunction& aTimingFunction)
+{
+ RefPtr<nsROCSSPrimitiveValue> timingFunction = new nsROCSSPrimitiveValue;
+
+ nsAutoString tmp;
+ switch (aTimingFunction.mType) {
+ case nsTimingFunction::Type::CubicBezier:
+ nsStyleUtil::AppendCubicBezierTimingFunction(aTimingFunction.mFunc.mX1,
+ aTimingFunction.mFunc.mY1,
+ aTimingFunction.mFunc.mX2,
+ aTimingFunction.mFunc.mY2,
+ tmp);
+ break;
+ case nsTimingFunction::Type::StepStart:
+ case nsTimingFunction::Type::StepEnd:
+ nsStyleUtil::AppendStepsTimingFunction(aTimingFunction.mType,
+ aTimingFunction.mSteps,
+ tmp);
+ break;
+ default:
+ nsStyleUtil::AppendCubicBezierKeywordTimingFunction(aTimingFunction.mType,
+ tmp);
+ break;
+ }
+ timingFunction->SetString(tmp);
+ aValueList->AppendCSSValue(timingFunction.forget());
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetTransitionTimingFunction()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mTransitionTimingFunctionCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ AppendTimingFunction(valueList,
+ display->mTransitions[i].GetTimingFunction());
+ } while (++i < display->mTransitionTimingFunctionCount);
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAnimationName()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mAnimationNameCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ const StyleAnimation *animation = &display->mAnimations[i];
+ RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
+
+ const nsString& name = animation->GetName();
+ if (name.IsEmpty()) {
+ property->SetIdent(eCSSKeyword_none);
+ } else {
+ nsAutoString escaped;
+ nsStyleUtil::AppendEscapedCSSIdent(animation->GetName(), escaped);
+ property->SetString(escaped); // really want SetIdent
+ }
+ valueList->AppendCSSValue(property.forget());
+ } while (++i < display->mAnimationNameCount);
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAnimationDelay()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mAnimationDelayCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ const StyleAnimation *animation = &display->mAnimations[i];
+ RefPtr<nsROCSSPrimitiveValue> delay = new nsROCSSPrimitiveValue;
+ delay->SetTime((float)animation->GetDelay() / (float)PR_MSEC_PER_SEC);
+ valueList->AppendCSSValue(delay.forget());
+ } while (++i < display->mAnimationDelayCount);
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAnimationDuration()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mAnimationDurationCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ const StyleAnimation *animation = &display->mAnimations[i];
+ RefPtr<nsROCSSPrimitiveValue> duration = new nsROCSSPrimitiveValue;
+
+ duration->SetTime((float)animation->GetDuration() / (float)PR_MSEC_PER_SEC);
+ valueList->AppendCSSValue(duration.forget());
+ } while (++i < display->mAnimationDurationCount);
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAnimationTimingFunction()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mAnimationTimingFunctionCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ AppendTimingFunction(valueList,
+ display->mAnimations[i].GetTimingFunction());
+ } while (++i < display->mAnimationTimingFunctionCount);
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAnimationDirection()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mAnimationDirectionCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ const StyleAnimation *animation = &display->mAnimations[i];
+ RefPtr<nsROCSSPrimitiveValue> direction = new nsROCSSPrimitiveValue;
+ direction->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(
+ static_cast<int32_t>(animation->GetDirection()),
+ nsCSSProps::kAnimationDirectionKTable));
+
+ valueList->AppendCSSValue(direction.forget());
+ } while (++i < display->mAnimationDirectionCount);
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAnimationFillMode()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mAnimationFillModeCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ const StyleAnimation *animation = &display->mAnimations[i];
+ RefPtr<nsROCSSPrimitiveValue> fillMode = new nsROCSSPrimitiveValue;
+ fillMode->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(
+ static_cast<int32_t>(animation->GetFillMode()),
+ nsCSSProps::kAnimationFillModeKTable));
+
+ valueList->AppendCSSValue(fillMode.forget());
+ } while (++i < display->mAnimationFillModeCount);
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAnimationIterationCount()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mAnimationIterationCountCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ const StyleAnimation *animation = &display->mAnimations[i];
+ RefPtr<nsROCSSPrimitiveValue> iterationCount = new nsROCSSPrimitiveValue;
+
+ float f = animation->GetIterationCount();
+ /* Need a nasty hack here to work around an optimizer bug in gcc
+ 4.2 on Mac, which somehow gets confused when directly comparing
+ a float to the return value of NS_IEEEPositiveInfinity when
+ building 32-bit builds. */
+#ifdef XP_MACOSX
+ volatile
+#endif
+ float inf = NS_IEEEPositiveInfinity();
+ if (f == inf) {
+ iterationCount->SetIdent(eCSSKeyword_infinite);
+ } else {
+ iterationCount->SetNumber(f);
+ }
+ valueList->AppendCSSValue(iterationCount.forget());
+ } while (++i < display->mAnimationIterationCountCount);
+
+ return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetAnimationPlayState()
+{
+ const nsStyleDisplay* display = StyleDisplay();
+
+ RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
+
+ MOZ_ASSERT(display->mAnimationPlayStateCount > 0,
+ "first item must be explicit");
+ uint32_t i = 0;
+ do {
+ const StyleAnimation *animation = &display->mAnimations[i];
+ RefPtr<nsROCSSPrimitiveValue> playState = new nsROCSSPrimitiveValue;
+ playState->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(animation->GetPlayState(),
+ nsCSSProps::kAnimationPlayStateKTable));
+ valueList->AppendCSSValue(playState.forget());
+ } while (++i < display->mAnimationPlayStateCount);
+
+ return valueList.forget();
+}
+
+static void
+MarkComputedStyleMapDirty(const char* aPref, void* aData)
+{
+ static_cast<nsComputedStyleMap*>(aData)->MarkDirty();
+}
+
+already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetCustomProperty(const nsAString& aPropertyName)
+{
+ MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
+
+ const nsStyleVariables* variables = StyleVariables();
+
+ nsString variableValue;
+ const nsAString& name = Substring(aPropertyName,
+ CSS_CUSTOM_NAME_PREFIX_LENGTH);
+ if (!variables->mVariables.Get(name, variableValue)) {
+ return nullptr;
+ }
+
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ val->SetString(variableValue);
+
+ return val.forget();
+}
+
+void
+nsComputedDOMStyle::ParentChainChanged(nsIContent* aContent)
+{
+ NS_ASSERTION(mContent == aContent, "didn't we register mContent?");
+ NS_ASSERTION(mResolvedStyleContext,
+ "should have only registered an observer when "
+ "mResolvedStyleContext is true");
+
+ ClearStyleContext();
+}
+
+/* static */ nsComputedStyleMap*
+nsComputedDOMStyle::GetComputedStyleMap()
+{
+ static nsComputedStyleMap map = {
+ {
+#define COMPUTED_STYLE_PROP(prop_, method_) \
+ { eCSSProperty_##prop_, &nsComputedDOMStyle::DoGet##method_ },
+#include "nsComputedDOMStylePropertyList.h"
+#undef COMPUTED_STYLE_PROP
+ }
+ };
+ return &map;
+}
+
+/* static */ void
+nsComputedDOMStyle::RegisterPrefChangeCallbacks()
+{
+ // Note that this will register callbacks for all properties with prefs, not
+ // just those that are implemented on computed style objects, as it's not
+ // easy to grab specific property data from nsCSSPropList.h based on the
+ // entries iterated in nsComputedDOMStylePropertyList.h.
+ nsComputedStyleMap* data = GetComputedStyleMap();
+#define REGISTER_CALLBACK(pref_) \
+ if (pref_[0]) { \
+ Preferences::RegisterCallback(MarkComputedStyleMapDirty, pref_, data); \
+ }
+#define CSS_PROP(prop_, id_, method_, flags_, pref_, parsevariant_, \
+ kwtable_, stylestruct_, stylestructoffset_, animtype_) \
+ REGISTER_CALLBACK(pref_)
+#define CSS_PROP_LIST_INCLUDE_LOGICAL
+#include "nsCSSPropList.h"
+#undef CSS_PROP_LIST_INCLUDE_LOGICAL
+#undef CSS_PROP
+#undef REGISTER_CALLBACK
+}
+
+/* static */ void
+nsComputedDOMStyle::UnregisterPrefChangeCallbacks()
+{
+ nsComputedStyleMap* data = GetComputedStyleMap();
+#define UNREGISTER_CALLBACK(pref_) \
+ if (pref_[0]) { \
+ Preferences::UnregisterCallback(MarkComputedStyleMapDirty, pref_, data); \
+ }
+#define CSS_PROP(prop_, id_, method_, flags_, pref_, parsevariant_, \
+ kwtable_, stylestruct_, stylestructoffset_, animtype_) \
+ UNREGISTER_CALLBACK(pref_)
+#define CSS_PROP_LIST_INCLUDE_LOGICAL
+#include "nsCSSPropList.h"
+#undef CSS_PROP_LIST_INCLUDE_LOGICAL
+#undef CSS_PROP
+#undef UNREGISTER_CALLBACK
+}