layout/style/nsComputedDOMStyle.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set tw=78 expandtab softtabstop=2 ts=2 sw=2: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* DOM object returned from element.getComputedStyle() */
     9 #include "nsComputedDOMStyle.h"
    11 #include "mozilla/ArrayUtils.h"
    12 #include "mozilla/Preferences.h"
    14 #include "nsError.h"
    15 #include "nsDOMString.h"
    16 #include "nsIDOMCSSPrimitiveValue.h"
    17 #include "nsStyleContext.h"
    18 #include "nsIScrollableFrame.h"
    19 #include "nsContentUtils.h"
    20 #include "nsIContent.h"
    22 #include "nsDOMCSSRect.h"
    23 #include "nsDOMCSSRGBColor.h"
    24 #include "nsDOMCSSValueList.h"
    25 #include "nsGkAtoms.h"
    26 #include "nsHTMLReflowState.h"
    27 #include "nsStyleUtil.h"
    28 #include "nsStyleStructInlines.h"
    29 #include "nsROCSSPrimitiveValue.h"
    31 #include "nsPresContext.h"
    32 #include "nsIDocument.h"
    34 #include "nsCSSPseudoElements.h"
    35 #include "nsStyleSet.h"
    36 #include "imgIRequest.h"
    37 #include "nsLayoutUtils.h"
    38 #include "nsCSSKeywords.h"
    39 #include "nsStyleCoord.h"
    40 #include "nsDisplayList.h"
    41 #include "nsDOMCSSDeclaration.h"
    42 #include "nsStyleTransformMatrix.h"
    43 #include "mozilla/dom/Element.h"
    44 #include "prtime.h"
    45 #include "nsWrapperCacheInlines.h"
    46 #include "mozilla/AppUnits.h"
    47 #include <algorithm>
    49 using namespace mozilla;
    50 using namespace mozilla::dom;
    52 #if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
    53 #define DEBUG_ComputedDOMStyle
    54 #endif
    56 /*
    57  * This is the implementation of the readonly CSSStyleDeclaration that is
    58  * returned by the getComputedStyle() function.
    59  */
    61 static nsComputedDOMStyle *sCachedComputedDOMStyle;
    63 already_AddRefed<nsComputedDOMStyle>
    64 NS_NewComputedDOMStyle(dom::Element* aElement, const nsAString& aPseudoElt,
    65                        nsIPresShell* aPresShell,
    66                        nsComputedDOMStyle::StyleType aStyleType)
    67 {
    68   nsRefPtr<nsComputedDOMStyle> computedStyle;
    69   if (sCachedComputedDOMStyle) {
    70     // There's an unused nsComputedDOMStyle cached, use it.
    71     // But before we use it, re-initialize the object.
    73     // Oh yeah baby, placement new!
    74     computedStyle = new (sCachedComputedDOMStyle)
    75       nsComputedDOMStyle(aElement, aPseudoElt, aPresShell, aStyleType);
    77     sCachedComputedDOMStyle = nullptr;
    78   } else {
    79     // No nsComputedDOMStyle cached, create a new one.
    81     computedStyle = new nsComputedDOMStyle(aElement, aPseudoElt, aPresShell,
    82                                            aStyleType);
    83   }
    85   return computedStyle.forget();
    86 }
    88 /**
    89  * An object that represents the ordered set of properties that are exposed on
    90  * an nsComputedDOMStyle object and how their computed values can be obtained.
    91  */
    92 struct nsComputedStyleMap
    93 {
    94   friend class nsComputedDOMStyle;
    96   struct Entry
    97   {
    98     // Create a pointer-to-member-function type.
    99     typedef mozilla::dom::CSSValue* (nsComputedDOMStyle::*ComputeMethod)();
   101     nsCSSProperty mProperty;
   102     ComputeMethod mGetter;
   104     bool IsLayoutFlushNeeded() const
   105     {
   106       return nsCSSProps::PropHasFlags(mProperty,
   107                                       CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH);
   108     }
   110     bool IsEnabled() const
   111     {
   112       return nsCSSProps::IsEnabled(mProperty);
   113     }
   114   };
   116   // We define this enum just to count the total number of properties that can
   117   // be exposed on an nsComputedDOMStyle, including properties that may be
   118   // disabled.
   119   enum {
   120 #define COMPUTED_STYLE_PROP(prop_, method_) \
   121     eComputedStyleProperty_##prop_,
   122 #include "nsComputedDOMStylePropertyList.h"
   123 #undef COMPUTED_STYLE_PROP
   124     eComputedStyleProperty_COUNT
   125   };
   127   /**
   128    * Returns the number of properties that should be exposed on an
   129    * nsComputedDOMStyle, ecxluding any disabled properties.
   130    */
   131   uint32_t Length()
   132   {
   133     Update();
   134     return mExposedPropertyCount;
   135   }
   137   /**
   138    * Returns the property at the given index in the list of properties
   139    * that should be exposed on an nsComputedDOMStyle, excluding any
   140    * disabled properties.
   141    */
   142   nsCSSProperty PropertyAt(uint32_t aIndex)
   143   {
   144     Update();
   145     return kEntries[EntryIndex(aIndex)].mProperty;
   146   }
   148   /**
   149    * Searches for and returns the computed style map entry for the given
   150    * property, or nullptr if the property is not exposed on nsComputedDOMStyle
   151    * or is currently disabled.
   152    */
   153   const Entry* FindEntryForProperty(nsCSSProperty aPropID)
   154   {
   155     Update();
   156     for (uint32_t i = 0; i < mExposedPropertyCount; i++) {
   157       const Entry* entry = &kEntries[EntryIndex(i)];
   158       if (entry->mProperty == aPropID) {
   159         return entry;
   160       }
   161     }
   162     return nullptr;
   163   }
   165   /**
   166    * Records that mIndexMap needs updating, due to prefs changing that could
   167    * affect the set of properties exposed on an nsComputedDOMStyle.
   168    */
   169   void MarkDirty() { mExposedPropertyCount = 0; }
   171   // The member variables are public so that we can use an initializer in
   172   // nsComputedDOMStyle::GetComputedStyleMap.  Use the member functions
   173   // above to get information from this object.
   175   /**
   176    * An entry for each property that can be exposed on an nsComputedDOMStyle.
   177    */
   178   const Entry kEntries[eComputedStyleProperty_COUNT];
   180   /**
   181    * The number of properties that should be exposed on an nsComputedDOMStyle.
   182    * This will be less than eComputedStyleProperty_COUNT if some property
   183    * prefs are disabled.  A value of 0 indicates that it and mIndexMap are out
   184    * of date.
   185    */
   186   uint32_t mExposedPropertyCount;
   188   /**
   189    * A map of indexes on the nsComputedDOMStyle object to indexes into kEntries.
   190    */
   191   uint32_t mIndexMap[eComputedStyleProperty_COUNT];
   193 private:
   194   /**
   195    * Returns whether mExposedPropertyCount and mIndexMap are out of date.
   196    */
   197   bool IsDirty() { return mExposedPropertyCount == 0; }
   199   /**
   200    * Updates mExposedPropertyCount and mIndexMap to take into account properties
   201    * whose prefs are currently disabled.
   202    */
   203   void Update();
   205   /**
   206    * Maps an nsComputedDOMStyle indexed getter index to an index into kEntries.
   207    */
   208   uint32_t EntryIndex(uint32_t aIndex) const
   209   {
   210     MOZ_ASSERT(aIndex < mExposedPropertyCount);
   211     return mIndexMap[aIndex];
   212   }
   213 };
   215 void
   216 nsComputedStyleMap::Update()
   217 {
   218   if (!IsDirty()) {
   219     return;
   220   }
   222   uint32_t index = 0;
   223   for (uint32_t i = 0; i < eComputedStyleProperty_COUNT; i++) {
   224     if (kEntries[i].IsEnabled()) {
   225       mIndexMap[index++] = i;
   226     }
   227   }
   228   mExposedPropertyCount = index;
   229 }
   231 nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement,
   232                                        const nsAString& aPseudoElt,
   233                                        nsIPresShell* aPresShell,
   234                                        StyleType aStyleType)
   235   : mDocumentWeak(nullptr), mOuterFrame(nullptr),
   236     mInnerFrame(nullptr), mPresShell(nullptr),
   237     mStyleType(aStyleType),
   238     mExposeVisitedStyle(false)
   239 {
   240   MOZ_ASSERT(aElement && aPresShell);
   242   mDocumentWeak = do_GetWeakReference(aPresShell->GetDocument());
   244   mContent = aElement;
   246   if (!DOMStringIsNull(aPseudoElt) && !aPseudoElt.IsEmpty() &&
   247       aPseudoElt.First() == char16_t(':')) {
   248     // deal with two-colon forms of aPseudoElt
   249     nsAString::const_iterator start, end;
   250     aPseudoElt.BeginReading(start);
   251     aPseudoElt.EndReading(end);
   252     NS_ASSERTION(start != end, "aPseudoElt is not empty!");
   253     ++start;
   254     bool haveTwoColons = true;
   255     if (start == end || *start != char16_t(':')) {
   256       --start;
   257       haveTwoColons = false;
   258     }
   259     mPseudo = do_GetAtom(Substring(start, end));
   260     MOZ_ASSERT(mPseudo);
   262     // There aren't any non-CSS2 pseudo-elements with a single ':'
   263     if (!haveTwoColons &&
   264         (!nsCSSPseudoElements::IsPseudoElement(mPseudo) ||
   265          !nsCSSPseudoElements::IsCSS2PseudoElement(mPseudo))) {
   266       // XXXbz I'd really rather we threw an exception or something, but
   267       // the DOM spec sucks.
   268       mPseudo = nullptr;
   269     }
   270   }
   272   MOZ_ASSERT(aPresShell->GetPresContext());
   273 }
   276 nsComputedDOMStyle::~nsComputedDOMStyle()
   277 {
   278 }
   280 void
   281 nsComputedDOMStyle::Shutdown()
   282 {
   283   // We want to de-allocate without calling the dtor since we
   284   // already did that manually in doDestroyComputedDOMStyle(),
   285   // so cast our cached object to something that doesn't know
   286   // about our dtor.
   287   delete reinterpret_cast<char*>(sCachedComputedDOMStyle);
   288   sCachedComputedDOMStyle = nullptr;
   289 }
   292 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsComputedDOMStyle, mContent)
   294 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle)
   295   return tmp->IsBlack();
   296 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
   298 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsComputedDOMStyle)
   299   return tmp->IsBlack();
   300 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
   302 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsComputedDOMStyle)
   303   return tmp->IsBlack();
   304 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
   306 // QueryInterface implementation for nsComputedDOMStyle
   307 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsComputedDOMStyle)
   308   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   309 NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
   312 static void doDestroyComputedDOMStyle(nsComputedDOMStyle *aComputedStyle)
   313 {
   314   if (!sCachedComputedDOMStyle) {
   315     // The cache is empty, store aComputedStyle in the cache.
   317     sCachedComputedDOMStyle = aComputedStyle;
   318     sCachedComputedDOMStyle->~nsComputedDOMStyle();
   319   } else {
   320     // The cache is full, delete aComputedStyle
   322     delete aComputedStyle;
   323   }
   324 }
   326 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsComputedDOMStyle)
   327 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsComputedDOMStyle,
   328                                               doDestroyComputedDOMStyle(this))
   331 NS_IMETHODIMP
   332 nsComputedDOMStyle::GetPropertyValue(const nsCSSProperty aPropID,
   333                                      nsAString& aValue)
   334 {
   335   // This is mostly to avoid code duplication with GetPropertyCSSValue(); if
   336   // perf ever becomes an issue here (doubtful), we can look into changing
   337   // this.
   338   return GetPropertyValue(
   339     NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(aPropID)),
   340     aValue);
   341 }
   343 NS_IMETHODIMP
   344 nsComputedDOMStyle::SetPropertyValue(const nsCSSProperty aPropID,
   345                                      const nsAString& aValue)
   346 {
   347   return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
   348 }
   351 NS_IMETHODIMP
   352 nsComputedDOMStyle::GetCssText(nsAString& aCssText)
   353 {
   354   aCssText.Truncate();
   356   return NS_OK;
   357 }
   360 NS_IMETHODIMP
   361 nsComputedDOMStyle::SetCssText(const nsAString& aCssText)
   362 {
   363   return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
   364 }
   367 NS_IMETHODIMP
   368 nsComputedDOMStyle::GetLength(uint32_t* aLength)
   369 {
   370   NS_PRECONDITION(aLength, "Null aLength!  Prepare to die!");
   372   uint32_t length = GetComputedStyleMap()->Length();
   374   // Make sure we have up to date style so that we can include custom
   375   // properties.
   376   UpdateCurrentStyleSources(false);
   377   if (mStyleContextHolder) {
   378     length += StyleVariables()->mVariables.Count();
   379   }
   381   *aLength = length;
   383   ClearCurrentStyleSources();
   385   return NS_OK;
   386 }
   389 NS_IMETHODIMP
   390 nsComputedDOMStyle::GetParentRule(nsIDOMCSSRule** aParentRule)
   391 {
   392   *aParentRule = nullptr;
   394   return NS_OK;
   395 }
   398 NS_IMETHODIMP
   399 nsComputedDOMStyle::GetPropertyValue(const nsAString& aPropertyName,
   400                                      nsAString& aReturn)
   401 {
   402   aReturn.Truncate();
   404   ErrorResult error;
   405   nsRefPtr<CSSValue> val = GetPropertyCSSValue(aPropertyName, error);
   406   if (error.Failed()) {
   407     return error.ErrorCode();
   408   }
   410   if (val) {
   411     nsString text;
   412     val->GetCssText(text, error);
   413     aReturn.Assign(text);
   414     return error.ErrorCode();
   415   }
   417   return NS_OK;
   418 }
   420 NS_IMETHODIMP
   421 nsComputedDOMStyle::GetAuthoredPropertyValue(const nsAString& aPropertyName,
   422                                              nsAString& aReturn)
   423 {
   424   // Authored style doesn't make sense to return from computed DOM style,
   425   // so just return whatever GetPropertyValue() returns.
   426   return GetPropertyValue(aPropertyName, aReturn);
   427 }
   429 /* static */
   430 already_AddRefed<nsStyleContext>
   431 nsComputedDOMStyle::GetStyleContextForElement(Element* aElement,
   432                                               nsIAtom* aPseudo,
   433                                               nsIPresShell* aPresShell,
   434                                               StyleType aStyleType)
   435 {
   436   // If the content has a pres shell, we must use it.  Otherwise we'd
   437   // potentially mix rule trees by using the wrong pres shell's style
   438   // set.  Using the pres shell from the content also means that any
   439   // content that's actually *in* a document will get the style from the
   440   // correct document.
   441   nsCOMPtr<nsIPresShell> presShell = GetPresShellForContent(aElement);
   442   if (!presShell) {
   443     presShell = aPresShell;
   444     if (!presShell)
   445       return nullptr;
   446   }
   448   presShell->FlushPendingNotifications(Flush_Style);
   450   return GetStyleContextForElementNoFlush(aElement, aPseudo, presShell,
   451                                           aStyleType);
   452 }
   454 /* static */
   455 already_AddRefed<nsStyleContext>
   456 nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
   457                                                      nsIAtom* aPseudo,
   458                                                      nsIPresShell* aPresShell,
   459                                                      StyleType aStyleType)
   460 {
   461   NS_ABORT_IF_FALSE(aElement, "NULL element");
   462   // If the content has a pres shell, we must use it.  Otherwise we'd
   463   // potentially mix rule trees by using the wrong pres shell's style
   464   // set.  Using the pres shell from the content also means that any
   465   // content that's actually *in* a document will get the style from the
   466   // correct document.
   467   nsIPresShell *presShell = GetPresShellForContent(aElement);
   468   if (!presShell) {
   469     presShell = aPresShell;
   470     if (!presShell)
   471       return nullptr;
   472   }
   474   if (!aPseudo && aStyleType == eAll) {
   475     nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
   476     if (frame) {
   477       nsStyleContext* result = frame->StyleContext();
   478       // Don't use the style context if it was influenced by
   479       // pseudo-elements, since then it's not the primary style
   480       // for this element.
   481       if (!result->HasPseudoElementData()) {
   482         // this function returns an addrefed style context
   483         nsRefPtr<nsStyleContext> ret = result;
   484         return ret.forget();
   485       }
   486     }
   487   }
   489   // No frame has been created, or we have a pseudo, or we're looking
   490   // for the default style, so resolve the style ourselves.
   491   nsRefPtr<nsStyleContext> parentContext;
   492   nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
   493   // Don't resolve parent context for document fragments.
   494   if (parent && parent->IsElement())
   495     parentContext = GetStyleContextForElementNoFlush(parent->AsElement(),
   496                                                      nullptr, presShell,
   497                                                      aStyleType);
   499   nsPresContext *presContext = presShell->GetPresContext();
   500   if (!presContext)
   501     return nullptr;
   503   nsStyleSet *styleSet = presShell->StyleSet();
   505   nsRefPtr<nsStyleContext> sc;
   506   if (aPseudo) {
   507     nsCSSPseudoElements::Type type = nsCSSPseudoElements::GetPseudoType(aPseudo);
   508     if (type >= nsCSSPseudoElements::ePseudo_PseudoElementCount) {
   509       return nullptr;
   510     }
   511     nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
   512     Element* pseudoElement = frame ? frame->GetPseudoElement(type) : nullptr;
   513     sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext,
   514                                              pseudoElement);
   515   } else {
   516     sc = styleSet->ResolveStyleFor(aElement, parentContext);
   517   }
   519   if (aStyleType == eDefaultOnly) {
   520     // We really only want the user and UA rules.  Filter out the other ones.
   521     nsTArray< nsCOMPtr<nsIStyleRule> > rules;
   522     for (nsRuleNode* ruleNode = sc->RuleNode();
   523          !ruleNode->IsRoot();
   524          ruleNode = ruleNode->GetParent()) {
   525       if (ruleNode->GetLevel() == nsStyleSet::eAgentSheet ||
   526           ruleNode->GetLevel() == nsStyleSet::eUserSheet) {
   527         rules.AppendElement(ruleNode->GetRule());
   528       }
   529     }
   531     // We want to build a list of user/ua rules that is in order from least to
   532     // most important, so we have to reverse the list.
   533     // Integer division to get "stop" is purposeful here: if length is odd, we
   534     // don't have to do anything with the middle element of the array.
   535     for (uint32_t i = 0, length = rules.Length(), stop = length / 2;
   536          i < stop; ++i) {
   537       rules[i].swap(rules[length - i - 1]);
   538     }
   540     sc = styleSet->ResolveStyleForRules(parentContext, rules);
   541   }
   543   return sc.forget();
   544 }
   546 nsMargin
   547 nsComputedDOMStyle::GetAdjustedValuesForBoxSizing()
   548 {
   549   // We want the width/height of whatever parts 'width' or 'height' controls,
   550   // which can be different depending on the value of the 'box-sizing' property.
   551   const nsStylePosition* stylePos = StylePosition();
   553   nsMargin adjustment;
   554   switch(stylePos->mBoxSizing) {
   555     case NS_STYLE_BOX_SIZING_BORDER:
   556       adjustment += mInnerFrame->GetUsedBorder();
   557       // fall through
   559     case NS_STYLE_BOX_SIZING_PADDING:
   560       adjustment += mInnerFrame->GetUsedPadding();
   561   }
   563   return adjustment;
   564 }
   566 /* static */
   567 nsIPresShell*
   568 nsComputedDOMStyle::GetPresShellForContent(nsIContent* aContent)
   569 {
   570   nsIDocument* currentDoc = aContent->GetCurrentDoc();
   571   if (!currentDoc)
   572     return nullptr;
   574   return currentDoc->GetShell();
   575 }
   577 // nsDOMCSSDeclaration abstract methods which should never be called
   578 // on a nsComputedDOMStyle object, but must be defined to avoid
   579 // compile errors.
   580 css::Declaration*
   581 nsComputedDOMStyle::GetCSSDeclaration(bool)
   582 {
   583   NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSDeclaration");
   584   return nullptr;
   585 }
   587 nsresult
   588 nsComputedDOMStyle::SetCSSDeclaration(css::Declaration*)
   589 {
   590   NS_RUNTIMEABORT("called nsComputedDOMStyle::SetCSSDeclaration");
   591   return NS_ERROR_FAILURE;
   592 }
   594 nsIDocument*
   595 nsComputedDOMStyle::DocToUpdate()
   596 {
   597   NS_RUNTIMEABORT("called nsComputedDOMStyle::DocToUpdate");
   598   return nullptr;
   599 }
   601 void
   602 nsComputedDOMStyle::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
   603 {
   604   NS_RUNTIMEABORT("called nsComputedDOMStyle::GetCSSParsingEnvironment");
   605   // Just in case NS_RUNTIMEABORT ever stops killing us for some reason
   606   aCSSParseEnv.mPrincipal = nullptr;
   607 }
   609 void
   610 nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
   611 {
   612   MOZ_ASSERT(!mStyleContextHolder);
   614   nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocumentWeak);
   615   if (!document) {
   616     return;
   617   }
   619   document->FlushPendingLinkUpdates();
   621   // Flush _before_ getting the presshell, since that could create a new
   622   // presshell.  Also note that we want to flush the style on the document
   623   // we're computing style in, not on the document mContent is in -- the two
   624   // may be different.
   625   document->FlushPendingNotifications(
   626     aNeedsLayoutFlush ? Flush_Layout : Flush_Style);
   627 #ifdef DEBUG
   628   mFlushedPendingReflows = aNeedsLayoutFlush;
   629 #endif
   631   mPresShell = document->GetShell();
   632   if (!mPresShell || !mPresShell->GetPresContext()) {
   633     return;
   634   }
   636   if (!mPseudo && mStyleType == eAll) {
   637     mOuterFrame = mContent->GetPrimaryFrame();
   638     mInnerFrame = mOuterFrame;
   639     if (mOuterFrame) {
   640       nsIAtom* type = mOuterFrame->GetType();
   641       if (type == nsGkAtoms::tableOuterFrame) {
   642         // If the frame is an outer table frame then we should get the style
   643         // from the inner table frame.
   644         mInnerFrame = mOuterFrame->GetFirstPrincipalChild();
   645         NS_ASSERTION(mInnerFrame, "Outer table must have an inner");
   646         NS_ASSERTION(!mInnerFrame->GetNextSibling(),
   647                      "Outer table frames should have just one child, "
   648                      "the inner table");
   649       }
   651       mStyleContextHolder = mInnerFrame->StyleContext();
   652       NS_ASSERTION(mStyleContextHolder, "Frame without style context?");
   653     }
   654   }
   656   if (!mStyleContextHolder || mStyleContextHolder->HasPseudoElementData()) {
   657 #ifdef DEBUG
   658     if (mStyleContextHolder) {
   659       // We want to check that going through this path because of
   660       // HasPseudoElementData is rare, because it slows us down a good
   661       // bit.  So check that we're really inside something associated
   662       // with a pseudo-element that contains elements.
   663       nsStyleContext *topWithPseudoElementData = mStyleContextHolder;
   664       while (topWithPseudoElementData->GetParent()->HasPseudoElementData()) {
   665         topWithPseudoElementData = topWithPseudoElementData->GetParent();
   666       }
   667       nsCSSPseudoElements::Type pseudo =
   668         topWithPseudoElementData->GetPseudoType();
   669       nsIAtom* pseudoAtom = nsCSSPseudoElements::GetPseudoAtom(pseudo);
   670       nsAutoString assertMsg(
   671         NS_LITERAL_STRING("we should be in a pseudo-element that is expected to contain elements ("));
   672       assertMsg.Append(nsDependentString(pseudoAtom->GetUTF16String()));
   673       assertMsg.Append(NS_LITERAL_STRING(")"));
   674       NS_ASSERTION(nsCSSPseudoElements::PseudoElementContainsElements(pseudo),
   675                    NS_LossyConvertUTF16toASCII(assertMsg).get());
   676     }
   677 #endif
   678     // Need to resolve a style context
   679     mStyleContextHolder =
   680       nsComputedDOMStyle::GetStyleContextForElement(mContent->AsElement(),
   681                                                     mPseudo,
   682                                                     mPresShell,
   683                                                     mStyleType);
   684     if (!mStyleContextHolder) {
   685       return;
   686     }
   688     NS_ASSERTION(mPseudo || !mStyleContextHolder->HasPseudoElementData(),
   689                  "should not have pseudo-element data");
   690   }
   692   // mExposeVisitedStyle is set to true only by testing APIs that
   693   // require chrome privilege.
   694   NS_ABORT_IF_FALSE(!mExposeVisitedStyle ||
   695                     nsContentUtils::IsCallerChrome(),
   696                     "mExposeVisitedStyle set incorrectly");
   697   if (mExposeVisitedStyle && mStyleContextHolder->RelevantLinkVisited()) {
   698     nsStyleContext *styleIfVisited = mStyleContextHolder->GetStyleIfVisited();
   699     if (styleIfVisited) {
   700       mStyleContextHolder = styleIfVisited;
   701     }
   702   }
   703 }
   705 void
   706 nsComputedDOMStyle::ClearCurrentStyleSources()
   707 {
   708   mOuterFrame = nullptr;
   709   mInnerFrame = nullptr;
   710   mPresShell = nullptr;
   712   // Release the current style context for it should be re-resolved
   713   // whenever a frame is not available.
   714   mStyleContextHolder = nullptr;
   715 }
   717 already_AddRefed<CSSValue>
   718 nsComputedDOMStyle::GetPropertyCSSValue(const nsAString& aPropertyName, ErrorResult& aRv)
   719 {
   720   nsCSSProperty prop = nsCSSProps::LookupProperty(aPropertyName,
   721                                                   nsCSSProps::eEnabledForAllContent);
   723   bool needsLayoutFlush;
   724   nsComputedStyleMap::Entry::ComputeMethod getter;
   726   if (prop == eCSSPropertyExtra_variable) {
   727     needsLayoutFlush = false;
   728     getter = nullptr;
   729   } else {
   730     // We don't (for now, anyway, though it may make sense to change it
   731     // for all aliases, including those in nsCSSPropAliasList) want
   732     // aliases to be enumerable (via GetLength and IndexedGetter), so
   733     // handle them here rather than adding entries to
   734     // GetQueryablePropertyMap.
   735     if (prop != eCSSProperty_UNKNOWN &&
   736         nsCSSProps::PropHasFlags(prop, CSS_PROPERTY_IS_ALIAS)) {
   737       const nsCSSProperty* subprops = nsCSSProps::SubpropertyEntryFor(prop);
   738       NS_ABORT_IF_FALSE(subprops[1] == eCSSProperty_UNKNOWN,
   739                         "must have list of length 1");
   740       prop = subprops[0];
   741     }
   743     const nsComputedStyleMap::Entry* propEntry =
   744       GetComputedStyleMap()->FindEntryForProperty(prop);
   746     if (!propEntry) {
   747 #ifdef DEBUG_ComputedDOMStyle
   748       NS_WARNING(PromiseFlatCString(NS_ConvertUTF16toUTF8(aPropertyName) +
   749                                     NS_LITERAL_CSTRING(" is not queryable!")).get());
   750 #endif
   752       // NOTE:  For branches, we should flush here for compatibility!
   753       return nullptr;
   754     }
   756     needsLayoutFlush = propEntry->IsLayoutFlushNeeded();
   757     getter = propEntry->mGetter;
   758   }
   760   UpdateCurrentStyleSources(needsLayoutFlush);
   761   if (!mStyleContextHolder) {
   762     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
   763     return nullptr;
   764   }
   766   nsRefPtr<CSSValue> val;
   767   if (prop == eCSSPropertyExtra_variable) {
   768     val = DoGetCustomProperty(aPropertyName);
   769   } else {
   770     // Call our pointer-to-member-function.
   771     val = (this->*getter)();
   772   }
   774   ClearCurrentStyleSources();
   776   return val.forget();
   777 }
   780 NS_IMETHODIMP
   781 nsComputedDOMStyle::RemoveProperty(const nsAString& aPropertyName,
   782                                    nsAString& aReturn)
   783 {
   784   return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
   785 }
   788 NS_IMETHODIMP
   789 nsComputedDOMStyle::GetPropertyPriority(const nsAString& aPropertyName,
   790                                         nsAString& aReturn)
   791 {
   792   aReturn.Truncate();
   794   return NS_OK;
   795 }
   798 NS_IMETHODIMP
   799 nsComputedDOMStyle::SetProperty(const nsAString& aPropertyName,
   800                                 const nsAString& aValue,
   801                                 const nsAString& aPriority)
   802 {
   803   return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
   804 }
   807 NS_IMETHODIMP
   808 nsComputedDOMStyle::Item(uint32_t aIndex, nsAString& aReturn)
   809 {
   810   return nsDOMCSSDeclaration::Item(aIndex, aReturn);
   811 }
   813 void
   814 nsComputedDOMStyle::IndexedGetter(uint32_t aIndex, bool& aFound,
   815                                   nsAString& aPropName)
   816 {
   817   nsComputedStyleMap* map = GetComputedStyleMap();
   818   uint32_t length = map->Length();
   820   if (aIndex < length) {
   821     aFound = true;
   822     CopyASCIItoUTF16(nsCSSProps::GetStringValue(map->PropertyAt(aIndex)),
   823                      aPropName);
   824     return;
   825   }
   827   // Custom properties are exposed with indexed properties just after all
   828   // of the built-in properties.
   829   UpdateCurrentStyleSources(false);
   830   if (!mStyleContextHolder) {
   831     aFound = false;
   832     return;
   833   }
   835   const nsStyleVariables* variables = StyleVariables();
   836   if (aIndex - length < variables->mVariables.Count()) {
   837     aFound = true;
   838     variables->mVariables.GetVariableAt(aIndex - length, aPropName);
   839   } else {
   840     aFound = false;
   841   }
   843   ClearCurrentStyleSources();
   844 }
   846 // Property getters...
   848 CSSValue*
   849 nsComputedDOMStyle::DoGetBinding()
   850 {
   851   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   853   const nsStyleDisplay* display = StyleDisplay();
   855   if (display->mBinding) {
   856     val->SetURI(display->mBinding->GetURI());
   857   } else {
   858     val->SetIdent(eCSSKeyword_none);
   859   }
   861   return val;
   862 }
   864 CSSValue*
   865 nsComputedDOMStyle::DoGetClear()
   866 {
   867   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   868   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakType,
   869                                                nsCSSProps::kClearKTable));
   870   return val;
   871 }
   873 CSSValue*
   874 nsComputedDOMStyle::DoGetFloat()
   875 {
   876   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
   877   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mFloats,
   878                                                nsCSSProps::kFloatKTable));
   879   return val;
   880 }
   882 CSSValue*
   883 nsComputedDOMStyle::DoGetBottom()
   884 {
   885   return GetOffsetWidthFor(NS_SIDE_BOTTOM);
   886 }
   888 CSSValue*
   889 nsComputedDOMStyle::DoGetStackSizing()
   890 {
   891   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   892   val->SetIdent(StyleXUL()->mStretchStack ? eCSSKeyword_stretch_to_fit :
   893                 eCSSKeyword_ignore);
   894   return val;
   895 }
   897 void
   898 nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue,
   899                                    nscolor aColor)
   900 {
   901   if (NS_GET_A(aColor) == 0) {
   902     aValue->SetIdent(eCSSKeyword_transparent);
   903     return;
   904   }
   906   nsROCSSPrimitiveValue *red   = new nsROCSSPrimitiveValue;
   907   nsROCSSPrimitiveValue *green = new nsROCSSPrimitiveValue;
   908   nsROCSSPrimitiveValue *blue  = new nsROCSSPrimitiveValue;
   909   nsROCSSPrimitiveValue *alpha  = new nsROCSSPrimitiveValue;
   911   uint8_t a = NS_GET_A(aColor);
   912   nsDOMCSSRGBColor *rgbColor =
   913     new nsDOMCSSRGBColor(red, green, blue, alpha, a < 255);
   915   red->SetNumber(NS_GET_R(aColor));
   916   green->SetNumber(NS_GET_G(aColor));
   917   blue->SetNumber(NS_GET_B(aColor));
   918   alpha->SetNumber(nsStyleUtil::ColorComponentToFloat(a));
   920   aValue->SetColor(rgbColor);
   921 }
   923 CSSValue*
   924 nsComputedDOMStyle::DoGetColor()
   925 {
   926   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   927   SetToRGBAColor(val, StyleColor()->mColor);
   928   return val;
   929 }
   931 CSSValue*
   932 nsComputedDOMStyle::DoGetOpacity()
   933 {
   934   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   935   val->SetNumber(StyleDisplay()->mOpacity);
   936   return val;
   937 }
   939 CSSValue*
   940 nsComputedDOMStyle::DoGetColumnCount()
   941 {
   942   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   944   const nsStyleColumn* column = StyleColumn();
   946   if (column->mColumnCount == NS_STYLE_COLUMN_COUNT_AUTO) {
   947     val->SetIdent(eCSSKeyword_auto);
   948   } else {
   949     val->SetNumber(column->mColumnCount);
   950   }
   952   return val;
   953 }
   955 CSSValue*
   956 nsComputedDOMStyle::DoGetColumnWidth()
   957 {
   958   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   960   // XXX fix the auto case. When we actually have a column frame, I think
   961   // we should return the computed column width.
   962   SetValueToCoord(val, StyleColumn()->mColumnWidth, true);
   963   return val;
   964 }
   966 CSSValue*
   967 nsComputedDOMStyle::DoGetColumnGap()
   968 {
   969   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   971   const nsStyleColumn* column = StyleColumn();
   972   if (column->mColumnGap.GetUnit() == eStyleUnit_Normal) {
   973     val->SetAppUnits(StyleFont()->mFont.size);
   974   } else {
   975     SetValueToCoord(val, StyleColumn()->mColumnGap, true);
   976   }
   978   return val;
   979 }
   981 CSSValue*
   982 nsComputedDOMStyle::DoGetColumnFill()
   983 {
   984   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   985   val->SetIdent(
   986     nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnFill,
   987                                    nsCSSProps::kColumnFillKTable));
   988   return val;
   989 }
   991 CSSValue*
   992 nsComputedDOMStyle::DoGetColumnRuleWidth()
   993 {
   994   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   995   val->SetAppUnits(StyleColumn()->GetComputedColumnRuleWidth());
   996   return val;
   997 }
   999 CSSValue*
  1000 nsComputedDOMStyle::DoGetColumnRuleStyle()
  1002   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  1003   val->SetIdent(
  1004     nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnRuleStyle,
  1005                                    nsCSSProps::kBorderStyleKTable));
  1006   return val;
  1009 CSSValue*
  1010 nsComputedDOMStyle::DoGetColumnRuleColor()
  1012   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  1014   const nsStyleColumn* column = StyleColumn();
  1015   nscolor ruleColor;
  1016   if (column->mColumnRuleColorIsForeground) {
  1017     ruleColor = StyleColor()->mColor;
  1018   } else {
  1019     ruleColor = column->mColumnRuleColor;
  1022   SetToRGBAColor(val, ruleColor);
  1023   return val;
  1026 CSSValue*
  1027 nsComputedDOMStyle::DoGetContent()
  1029   const nsStyleContent *content = StyleContent();
  1031   if (content->ContentCount() == 0) {
  1032     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  1033     val->SetIdent(eCSSKeyword_none);
  1034     return val;
  1037   if (content->ContentCount() == 1 &&
  1038       content->ContentAt(0).mType == eStyleContentType_AltContent) {
  1039     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  1040     val->SetIdent(eCSSKeyword__moz_alt_content);
  1041     return val;
  1044   nsDOMCSSValueList *valueList = GetROCSSValueList(false);
  1046   for (uint32_t i = 0, i_end = content->ContentCount(); i < i_end; ++i) {
  1047     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1048     valueList->AppendCSSValue(val);
  1050     const nsStyleContentData &data = content->ContentAt(i);
  1051     switch (data.mType) {
  1052       case eStyleContentType_String:
  1054           nsString str;
  1055           nsStyleUtil::AppendEscapedCSSString(
  1056             nsDependentString(data.mContent.mString), str);
  1057           val->SetString(str);
  1059         break;
  1060       case eStyleContentType_Image:
  1062           nsCOMPtr<nsIURI> uri;
  1063           if (data.mContent.mImage) {
  1064             data.mContent.mImage->GetURI(getter_AddRefs(uri));
  1066           val->SetURI(uri);
  1068         break;
  1069       case eStyleContentType_Attr:
  1071           nsAutoString str;
  1072           nsStyleUtil::AppendEscapedCSSIdent(
  1073             nsDependentString(data.mContent.mString), str);
  1074           val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_ATTR);
  1076         break;
  1077       case eStyleContentType_Counter:
  1078       case eStyleContentType_Counters:
  1080           /* FIXME: counters should really use an object */
  1081           nsAutoString str;
  1082           if (data.mType == eStyleContentType_Counter) {
  1083             str.AppendLiteral("counter(");
  1085           else {
  1086             str.AppendLiteral("counters(");
  1088           // WRITE ME
  1089           nsCSSValue::Array *a = data.mContent.mCounters;
  1091           nsStyleUtil::AppendEscapedCSSIdent(
  1092             nsDependentString(a->Item(0).GetStringBufferValue()), str);
  1093           int32_t typeItem = 1;
  1094           if (data.mType == eStyleContentType_Counters) {
  1095             typeItem = 2;
  1096             str.AppendLiteral(", ");
  1097             nsStyleUtil::AppendEscapedCSSString(
  1098               nsDependentString(a->Item(1).GetStringBufferValue()), str);
  1100           NS_ABORT_IF_FALSE(eCSSUnit_None != a->Item(typeItem).GetUnit(),
  1101                             "'none' should be handled  as enumerated value");
  1102           int32_t type = a->Item(typeItem).GetIntValue();
  1103           if (type != NS_STYLE_LIST_STYLE_DECIMAL) {
  1104             str.AppendLiteral(", ");
  1105             AppendASCIItoUTF16(
  1106               nsCSSProps::ValueToKeyword(type, nsCSSProps::kListStyleKTable),
  1107               str);
  1110           str.Append(char16_t(')'));
  1111           val->SetString(str, nsIDOMCSSPrimitiveValue::CSS_COUNTER);
  1113         break;
  1114       case eStyleContentType_OpenQuote:
  1115         val->SetIdent(eCSSKeyword_open_quote);
  1116         break;
  1117       case eStyleContentType_CloseQuote:
  1118         val->SetIdent(eCSSKeyword_close_quote);
  1119         break;
  1120       case eStyleContentType_NoOpenQuote:
  1121         val->SetIdent(eCSSKeyword_no_open_quote);
  1122         break;
  1123       case eStyleContentType_NoCloseQuote:
  1124         val->SetIdent(eCSSKeyword_no_close_quote);
  1125         break;
  1126       case eStyleContentType_AltContent:
  1127       default:
  1128         NS_NOTREACHED("unexpected type");
  1129         break;
  1133   return valueList;
  1136 CSSValue*
  1137 nsComputedDOMStyle::DoGetCounterIncrement()
  1139   const nsStyleContent *content = StyleContent();
  1141   if (content->CounterIncrementCount() == 0) {
  1142     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  1143     val->SetIdent(eCSSKeyword_none);
  1144     return val;
  1147   nsDOMCSSValueList *valueList = GetROCSSValueList(false);
  1149   for (uint32_t i = 0, i_end = content->CounterIncrementCount(); i < i_end; ++i) {
  1150     nsROCSSPrimitiveValue* name = new nsROCSSPrimitiveValue;
  1151     valueList->AppendCSSValue(name);
  1153     nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
  1154     valueList->AppendCSSValue(value);
  1156     const nsStyleCounterData *data = content->GetCounterIncrementAt(i);
  1157     nsAutoString escaped;
  1158     nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
  1159     name->SetString(escaped);
  1160     value->SetNumber(data->mValue); // XXX This should really be integer
  1163   return valueList;
  1166 /* Convert the stored representation into a list of two values and then hand
  1167  * it back.
  1168  */
  1169 CSSValue*
  1170 nsComputedDOMStyle::DoGetTransformOrigin()
  1172   /* We need to build up a list of two values.  We'll call them
  1173    * width and height.
  1174    */
  1176   /* Store things as a value list */
  1177   nsDOMCSSValueList* valueList = GetROCSSValueList(false);
  1179   /* Now, get the values. */
  1180   const nsStyleDisplay* display = StyleDisplay();
  1182   nsROCSSPrimitiveValue* width = new nsROCSSPrimitiveValue;
  1183   SetValueToCoord(width, display->mTransformOrigin[0], false,
  1184                   &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
  1185   valueList->AppendCSSValue(width);
  1187   nsROCSSPrimitiveValue* height = new nsROCSSPrimitiveValue;
  1188   SetValueToCoord(height, display->mTransformOrigin[1], false,
  1189                   &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
  1190   valueList->AppendCSSValue(height);
  1192   if (display->mTransformOrigin[2].GetUnit() != eStyleUnit_Coord ||
  1193       display->mTransformOrigin[2].GetCoordValue() != 0) {
  1194     nsROCSSPrimitiveValue* depth = new nsROCSSPrimitiveValue;
  1195     SetValueToCoord(depth, display->mTransformOrigin[2], false,
  1196                     nullptr);
  1197     valueList->AppendCSSValue(depth);
  1200   return valueList;
  1203 /* Convert the stored representation into a list of two values and then hand
  1204  * it back.
  1205  */
  1206 CSSValue*
  1207 nsComputedDOMStyle::DoGetPerspectiveOrigin()
  1209   /* We need to build up a list of two values.  We'll call them
  1210    * width and height.
  1211    */
  1213   /* Store things as a value list */
  1214   nsDOMCSSValueList* valueList = GetROCSSValueList(false);
  1216   /* Now, get the values. */
  1217   const nsStyleDisplay* display = StyleDisplay();
  1219   nsROCSSPrimitiveValue* width = new nsROCSSPrimitiveValue;
  1220   SetValueToCoord(width, display->mPerspectiveOrigin[0], false,
  1221                   &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
  1222   valueList->AppendCSSValue(width);
  1224   nsROCSSPrimitiveValue* height = new nsROCSSPrimitiveValue;
  1225   SetValueToCoord(height, display->mPerspectiveOrigin[1], false,
  1226                   &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
  1227   valueList->AppendCSSValue(height);
  1229   return valueList;
  1232 CSSValue*
  1233 nsComputedDOMStyle::DoGetPerspective()
  1235     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1236     SetValueToCoord(val, StyleDisplay()->mChildPerspective, false);
  1237     return val;
  1240 CSSValue*
  1241 nsComputedDOMStyle::DoGetBackfaceVisibility()
  1243     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1244     val->SetIdent(
  1245         nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBackfaceVisibility,
  1246                                        nsCSSProps::kBackfaceVisibilityKTable));
  1247     return val;
  1250 CSSValue*
  1251 nsComputedDOMStyle::DoGetTransformStyle()
  1253     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  1254     val->SetIdent(
  1255         nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mTransformStyle,
  1256                                        nsCSSProps::kTransformStyleKTable));
  1257     return val;
  1260 /* If the property is "none", hand back "none" wrapped in a value.
  1261  * Otherwise, compute the aggregate transform matrix and hands it back in a
  1262  * "matrix" wrapper.
  1263  */
  1264 CSSValue*
  1265 nsComputedDOMStyle::DoGetTransform()
  1267   /* First, get the display data.  We'll need it. */
  1268   const nsStyleDisplay* display = StyleDisplay();
  1270   /* If there are no transforms, then we should construct a single-element
  1271    * entry and hand it back.
  1272    */
  1273   if (!display->mSpecifiedTransform) {
  1274     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1276     /* Set it to "none." */
  1277     val->SetIdent(eCSSKeyword_none);
  1278     return val;
  1281   /* Otherwise, we need to compute the current value of the transform matrix,
  1282    * store it in a string, and hand it back to the caller.
  1283    */
  1285   /* Use the inner frame for width and height.  If we fail, assume zero.
  1286    * TODO: There is no good way for us to represent the case where there's no
  1287    * frame, which is problematic.  The reason is that when we have percentage
  1288    * transforms, there are a total of four stored matrix entries that influence
  1289    * the transform based on the size of the element.  However, this poses a
  1290    * problem, because only two of these values can be explicitly referenced
  1291    * using the named transforms.  Until a real solution is found, we'll just
  1292    * use this approach.
  1293    */
  1294   nsRect bounds =
  1295     (mInnerFrame ? nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame) :
  1296      nsRect(0, 0, 0, 0));
  1298    bool dummy;
  1299    gfx3DMatrix matrix =
  1300      nsStyleTransformMatrix::ReadTransforms(display->mSpecifiedTransform->mHead,
  1301                                             mStyleContextHolder,
  1302                                             mStyleContextHolder->PresContext(),
  1303                                             dummy,
  1304                                             bounds,
  1305                                             float(mozilla::AppUnitsPerCSSPixel()));
  1307   return MatrixToCSSValue(matrix);
  1310 /* static */ nsROCSSPrimitiveValue*
  1311 nsComputedDOMStyle::MatrixToCSSValue(gfx3DMatrix& matrix)
  1313   bool is3D = !matrix.Is2D();
  1315   nsAutoString resultString(NS_LITERAL_STRING("matrix"));
  1316   if (is3D) {
  1317     resultString.Append(NS_LITERAL_STRING("3d"));
  1320   resultString.Append(NS_LITERAL_STRING("("));
  1321   resultString.AppendFloat(matrix._11);
  1322   resultString.Append(NS_LITERAL_STRING(", "));
  1323   resultString.AppendFloat(matrix._12);
  1324   resultString.Append(NS_LITERAL_STRING(", "));
  1325   if (is3D) {
  1326     resultString.AppendFloat(matrix._13);
  1327     resultString.Append(NS_LITERAL_STRING(", "));
  1328     resultString.AppendFloat(matrix._14);
  1329     resultString.Append(NS_LITERAL_STRING(", "));
  1331   resultString.AppendFloat(matrix._21);
  1332   resultString.Append(NS_LITERAL_STRING(", "));
  1333   resultString.AppendFloat(matrix._22);
  1334   resultString.Append(NS_LITERAL_STRING(", "));
  1335   if (is3D) {
  1336     resultString.AppendFloat(matrix._23);
  1337     resultString.Append(NS_LITERAL_STRING(", "));
  1338     resultString.AppendFloat(matrix._24);
  1339     resultString.Append(NS_LITERAL_STRING(", "));
  1340     resultString.AppendFloat(matrix._31);
  1341     resultString.Append(NS_LITERAL_STRING(", "));
  1342     resultString.AppendFloat(matrix._32);
  1343     resultString.Append(NS_LITERAL_STRING(", "));
  1344     resultString.AppendFloat(matrix._33);
  1345     resultString.Append(NS_LITERAL_STRING(", "));
  1346     resultString.AppendFloat(matrix._34);
  1347     resultString.Append(NS_LITERAL_STRING(", "));
  1349   resultString.AppendFloat(matrix._41);
  1350   resultString.Append(NS_LITERAL_STRING(", "));
  1351   resultString.AppendFloat(matrix._42);
  1352   if (is3D) {
  1353     resultString.Append(NS_LITERAL_STRING(", "));
  1354     resultString.AppendFloat(matrix._43);
  1355     resultString.Append(NS_LITERAL_STRING(", "));
  1356     resultString.AppendFloat(matrix._44);
  1358   resultString.Append(NS_LITERAL_STRING(")"));
  1360   /* Create a value to hold our result. */
  1361   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1363   val->SetString(resultString);
  1364   return val;
  1367 CSSValue*
  1368 nsComputedDOMStyle::DoGetCounterReset()
  1370   const nsStyleContent *content = StyleContent();
  1372   if (content->CounterResetCount() == 0) {
  1373     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  1374     val->SetIdent(eCSSKeyword_none);
  1375     return val;
  1378   nsDOMCSSValueList *valueList = GetROCSSValueList(false);
  1380   for (uint32_t i = 0, i_end = content->CounterResetCount(); i < i_end; ++i) {
  1381     nsROCSSPrimitiveValue* name = new nsROCSSPrimitiveValue;
  1382     valueList->AppendCSSValue(name);
  1384     nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
  1385     valueList->AppendCSSValue(value);
  1387     const nsStyleCounterData *data = content->GetCounterResetAt(i);
  1388     nsAutoString escaped;
  1389     nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
  1390     name->SetString(escaped);
  1391     value->SetNumber(data->mValue); // XXX This should really be integer
  1394   return valueList;
  1397 CSSValue*
  1398 nsComputedDOMStyle::DoGetQuotes()
  1400   const nsStyleQuotes *quotes = StyleQuotes();
  1402   if (quotes->QuotesCount() == 0) {
  1403     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  1404     val->SetIdent(eCSSKeyword_none);
  1405     return val;
  1408   nsDOMCSSValueList *valueList = GetROCSSValueList(false);
  1410   for (uint32_t i = 0, i_end = quotes->QuotesCount(); i < i_end; ++i) {
  1411     nsROCSSPrimitiveValue* openVal = new nsROCSSPrimitiveValue;
  1412     valueList->AppendCSSValue(openVal);
  1414     nsROCSSPrimitiveValue* closeVal = new nsROCSSPrimitiveValue;
  1415     valueList->AppendCSSValue(closeVal);
  1417     nsString s;
  1418     nsStyleUtil::AppendEscapedCSSString(*quotes->OpenQuoteAt(i), s);
  1419     openVal->SetString(s);
  1420     s.Truncate();
  1421     nsStyleUtil::AppendEscapedCSSString(*quotes->CloseQuoteAt(i), s);
  1422     closeVal->SetString(s);
  1425   return valueList;
  1428 CSSValue*
  1429 nsComputedDOMStyle::DoGetFontFamily()
  1431   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1433   const nsStyleFont* font = StyleFont();
  1435   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocumentWeak);
  1436   NS_ASSERTION(doc, "document is required");
  1437   nsIPresShell* presShell = doc->GetShell();
  1438   NS_ASSERTION(presShell, "pres shell is required");
  1439   nsPresContext *presContext = presShell->GetPresContext();
  1440   NS_ASSERTION(presContext, "pres context is required");
  1442   const nsString& fontName = font->mFont.name;
  1443   if (font->mGenericID == kGenericFont_NONE && !font->mFont.systemFont) {
  1444     const nsFont* defaultFont =
  1445       presContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
  1446                                   font->mLanguage);
  1448     int32_t lendiff = fontName.Length() - defaultFont->name.Length();
  1449     if (lendiff > 0) {
  1450       val->SetString(Substring(fontName, 0, lendiff-1)); // -1 removes comma
  1451     } else {
  1452       val->SetString(fontName);
  1454   } else {
  1455     val->SetString(fontName);
  1458   return val;
  1461 CSSValue*
  1462 nsComputedDOMStyle::DoGetFontSize()
  1464   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1466   // Note: StyleFont()->mSize is the 'computed size';
  1467   // StyleFont()->mFont.size is the 'actual size'
  1468   val->SetAppUnits(StyleFont()->mSize);
  1469   return val;
  1472 CSSValue*
  1473 nsComputedDOMStyle::DoGetFontSizeAdjust()
  1475   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  1477   const nsStyleFont *font = StyleFont();
  1479   if (font->mFont.sizeAdjust) {
  1480     val->SetNumber(font->mFont.sizeAdjust);
  1481   } else {
  1482     val->SetIdent(eCSSKeyword_none);
  1485   return val;
  1488 CSSValue*
  1489 nsComputedDOMStyle::DoGetOSXFontSmoothing()
  1491   if (!nsContentUtils::IsCallerChrome())
  1492     return nullptr;
  1494   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1495   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.smoothing,
  1496                                                nsCSSProps::kFontSmoothingKTable));
  1497   return val;
  1500 CSSValue*
  1501 nsComputedDOMStyle::DoGetFontStretch()
  1503   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1505   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.stretch,
  1506                                                nsCSSProps::kFontStretchKTable));
  1508   return val;
  1511 CSSValue*
  1512 nsComputedDOMStyle::DoGetFontStyle()
  1514   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1515   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.style,
  1516                                                nsCSSProps::kFontStyleKTable));
  1517   return val;
  1520 CSSValue*
  1521 nsComputedDOMStyle::DoGetFontWeight()
  1523   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1525   const nsStyleFont* font = StyleFont();
  1527   uint16_t weight = font->mFont.weight;
  1528   NS_ASSERTION(weight % 100 == 0, "unexpected value of font-weight");
  1529   val->SetNumber(weight);
  1531   return val;
  1534 CSSValue*
  1535 nsComputedDOMStyle::DoGetFontVariant()
  1537   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1538   val->SetIdent(
  1539     nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.variant,
  1540                                    nsCSSProps::kFontVariantKTable));
  1541   return val;
  1544 CSSValue*
  1545 nsComputedDOMStyle::DoGetFontFeatureSettings()
  1547   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1549   const nsStyleFont* font = StyleFont();
  1550   if (font->mFont.fontFeatureSettings.IsEmpty()) {
  1551     val->SetIdent(eCSSKeyword_normal);
  1552   } else {
  1553     nsAutoString result;
  1554     nsStyleUtil::AppendFontFeatureSettings(font->mFont.fontFeatureSettings,
  1555                                            result);
  1556     val->SetString(result);
  1558   return val;
  1561 CSSValue*
  1562 nsComputedDOMStyle::DoGetFontKerning()
  1564   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1565   val->SetIdent(
  1566     nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.kerning,
  1567                                    nsCSSProps::kFontKerningKTable));
  1568   return val;
  1571 CSSValue*
  1572 nsComputedDOMStyle::DoGetFontLanguageOverride()
  1574   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1576   const nsStyleFont* font = StyleFont();
  1577   if (font->mFont.languageOverride.IsEmpty()) {
  1578     val->SetIdent(eCSSKeyword_normal);
  1579   } else {
  1580     nsString str;
  1581     nsStyleUtil::AppendEscapedCSSString(font->mFont.languageOverride, str);
  1582     val->SetString(str);
  1584   return val;
  1587 CSSValue*
  1588 nsComputedDOMStyle::DoGetFontSynthesis()
  1590   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1592   int32_t intValue = StyleFont()->mFont.synthesis;
  1594   if (0 == intValue) {
  1595     val->SetIdent(eCSSKeyword_none);
  1596   } else {
  1597     nsAutoString valueStr;
  1599     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_synthesis,
  1600       intValue, NS_FONT_SYNTHESIS_WEIGHT,
  1601       NS_FONT_SYNTHESIS_STYLE, valueStr);
  1602     val->SetString(valueStr);
  1605   return val;
  1608 CSSValue*
  1609 nsComputedDOMStyle::DoGetFontVariantAlternates()
  1611   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1613   int32_t intValue = StyleFont()->mFont.variantAlternates;
  1615   if (0 == intValue) {
  1616     val->SetIdent(eCSSKeyword_normal);
  1617     return val;
  1620   // first, include enumerated values
  1621   nsAutoString valueStr;
  1623   nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_alternates,
  1624     intValue & NS_FONT_VARIANT_ALTERNATES_ENUMERATED_MASK,
  1625     NS_FONT_VARIANT_ALTERNATES_HISTORICAL,
  1626     NS_FONT_VARIANT_ALTERNATES_HISTORICAL, valueStr);
  1628   // next, include functional values if present
  1629   if (intValue & NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK) {
  1630     nsStyleUtil::SerializeFunctionalAlternates(StyleFont()->mFont.alternateValues,
  1631                                                valueStr);
  1634   val->SetString(valueStr);
  1635   return val;
  1639 CSSValue*
  1640 nsComputedDOMStyle::DoGetFontVariantCaps()
  1642   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1644   int32_t intValue = StyleFont()->mFont.variantCaps;
  1646   if (0 == intValue) {
  1647     val->SetIdent(eCSSKeyword_normal);
  1648   } else {
  1649     val->SetIdent(
  1650       nsCSSProps::ValueToKeywordEnum(intValue,
  1651                                      nsCSSProps::kFontVariantCapsKTable));
  1654   return val;
  1657 CSSValue*
  1658 nsComputedDOMStyle::DoGetFontVariantEastAsian()
  1660   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1662   int32_t intValue = StyleFont()->mFont.variantEastAsian;
  1664   if (0 == intValue) {
  1665     val->SetIdent(eCSSKeyword_normal);
  1666   } else {
  1667     nsAutoString valueStr;
  1669     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_east_asian,
  1670       intValue, NS_FONT_VARIANT_EAST_ASIAN_JIS78,
  1671       NS_FONT_VARIANT_EAST_ASIAN_RUBY, valueStr);
  1672     val->SetString(valueStr);
  1675   return val;
  1678 CSSValue*
  1679 nsComputedDOMStyle::DoGetFontVariantLigatures()
  1681   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1683   int32_t intValue = StyleFont()->mFont.variantLigatures;
  1685   if (0 == intValue) {
  1686     val->SetIdent(eCSSKeyword_normal);
  1687   } else {
  1688     nsAutoString valueStr;
  1690     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_ligatures,
  1691       intValue, NS_FONT_VARIANT_LIGATURES_NONE,
  1692       NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL, valueStr);
  1693     val->SetString(valueStr);
  1696   return val;
  1699 CSSValue*
  1700 nsComputedDOMStyle::DoGetFontVariantNumeric()
  1702   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1704   int32_t intValue = StyleFont()->mFont.variantNumeric;
  1706   if (0 == intValue) {
  1707     val->SetIdent(eCSSKeyword_normal);
  1708   } else {
  1709     nsAutoString valueStr;
  1711     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_numeric,
  1712       intValue, NS_FONT_VARIANT_NUMERIC_LINING,
  1713       NS_FONT_VARIANT_NUMERIC_ORDINAL, valueStr);
  1714     val->SetString(valueStr);
  1717   return val;
  1720 CSSValue*
  1721 nsComputedDOMStyle::DoGetFontVariantPosition()
  1723   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1725   int32_t intValue = StyleFont()->mFont.variantPosition;
  1727   if (0 == intValue) {
  1728     val->SetIdent(eCSSKeyword_normal);
  1729   } else {
  1730     val->SetIdent(
  1731       nsCSSProps::ValueToKeywordEnum(intValue,
  1732                                      nsCSSProps::kFontVariantPositionKTable));
  1735   return val;
  1738 CSSValue*
  1739 nsComputedDOMStyle::GetBackgroundList(uint8_t nsStyleBackground::Layer::* aMember,
  1740                                       uint32_t nsStyleBackground::* aCount,
  1741                                       const KTableValue aTable[])
  1743   const nsStyleBackground* bg = StyleBackground();
  1745   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  1747   for (uint32_t i = 0, i_end = bg->*aCount; i < i_end; ++i) {
  1748     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  1749     valueList->AppendCSSValue(val);
  1750     val->SetIdent(nsCSSProps::ValueToKeywordEnum(bg->mLayers[i].*aMember,
  1751                                                  aTable));
  1754   return valueList;
  1757 CSSValue*
  1758 nsComputedDOMStyle::DoGetBackgroundAttachment()
  1760   return GetBackgroundList(&nsStyleBackground::Layer::mAttachment,
  1761                            &nsStyleBackground::mAttachmentCount,
  1762                            nsCSSProps::kBackgroundAttachmentKTable);
  1765 CSSValue*
  1766 nsComputedDOMStyle::DoGetBackgroundClip()
  1768   return GetBackgroundList(&nsStyleBackground::Layer::mClip,
  1769                            &nsStyleBackground::mClipCount,
  1770                            nsCSSProps::kBackgroundOriginKTable);
  1773 CSSValue*
  1774 nsComputedDOMStyle::DoGetBackgroundColor()
  1776   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  1777   SetToRGBAColor(val, StyleBackground()->mBackgroundColor);
  1778   return val;
  1782 static void
  1783 SetValueToCalc(const nsStyleCoord::Calc *aCalc, nsROCSSPrimitiveValue *aValue)
  1785   nsRefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
  1786   nsAutoString tmp, result;
  1788   result.AppendLiteral("calc(");
  1790   val->SetAppUnits(aCalc->mLength);
  1791   val->GetCssText(tmp);
  1792   result.Append(tmp);
  1794   if (aCalc->mHasPercent) {
  1795     result.AppendLiteral(" + ");
  1797     val->SetPercent(aCalc->mPercent);
  1798     val->GetCssText(tmp);
  1799     result.Append(tmp);
  1802   result.AppendLiteral(")");
  1804   aValue->SetString(result); // not really SetString
  1807 static void
  1808 AppendCSSGradientLength(const nsStyleCoord& aValue,
  1809                         nsROCSSPrimitiveValue* aPrimitive,
  1810                         nsAString& aString)
  1812   nsAutoString tokenString;
  1813   if (aValue.IsCalcUnit())
  1814     SetValueToCalc(aValue.GetCalcValue(), aPrimitive);
  1815   else if (aValue.GetUnit() == eStyleUnit_Coord)
  1816     aPrimitive->SetAppUnits(aValue.GetCoordValue());
  1817   else
  1818     aPrimitive->SetPercent(aValue.GetPercentValue());
  1819   aPrimitive->GetCssText(tokenString);
  1820   aString.Append(tokenString);
  1823 static void
  1824 AppendCSSGradientToBoxPosition(const nsStyleGradient* aGradient,
  1825                                nsAString& aString,
  1826                                bool& aNeedSep)
  1828   float xValue = aGradient->mBgPosX.GetPercentValue();
  1829   float yValue = aGradient->mBgPosY.GetPercentValue();
  1831   if (yValue == 1.0f && xValue == 0.5f) {
  1832     // omit "to bottom"
  1833     return;
  1835   NS_ASSERTION(yValue != 0.5f || xValue != 0.5f, "invalid box position");
  1837   aString.AppendLiteral("to");
  1839   if (yValue == 0.0f) {
  1840     aString.AppendLiteral(" top");
  1841   } else if (yValue == 1.0f) {
  1842     aString.AppendLiteral(" bottom");
  1843   } else if (yValue != 0.5f) { // do not write "center" keyword
  1844     NS_NOTREACHED("invalid box position");
  1847   if (xValue == 0.0f) {
  1848     aString.AppendLiteral(" left");
  1849   } else if (xValue == 1.0f) {
  1850     aString.AppendLiteral(" right");
  1851   } else if (xValue != 0.5f) { // do not write "center" keyword
  1852     NS_NOTREACHED("invalid box position");
  1855   aNeedSep = true;
  1858 void
  1859 nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient,
  1860                                          nsAString& aString)
  1862   if (!aGradient->mLegacySyntax) {
  1863     aString.Truncate();
  1864   } else {
  1865     aString.AssignLiteral("-moz-");
  1867   if (aGradient->mRepeating) {
  1868     aString.AppendLiteral("repeating-");
  1870   bool isRadial = aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR;
  1871   if (isRadial) {
  1872     aString.AppendLiteral("radial-gradient(");
  1873   } else {
  1874     aString.AppendLiteral("linear-gradient(");
  1877   bool needSep = false;
  1878   nsAutoString tokenString;
  1879   nsROCSSPrimitiveValue *tmpVal = new nsROCSSPrimitiveValue;
  1881   if (isRadial && !aGradient->mLegacySyntax) {
  1882     if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE) {
  1883       if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
  1884         aString.AppendLiteral("circle");
  1885         needSep = true;
  1887       if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) {
  1888         if (needSep) {
  1889           aString.AppendLiteral(" ");
  1891         AppendASCIItoUTF16(nsCSSProps::
  1892                            ValueToKeyword(aGradient->mSize,
  1893                                           nsCSSProps::kRadialGradientSizeKTable),
  1894                            aString);
  1895         needSep = true;
  1897     } else {
  1898       AppendCSSGradientLength(aGradient->mRadiusX, tmpVal, aString);
  1899       if (aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
  1900         aString.AppendLiteral(" ");
  1901         AppendCSSGradientLength(aGradient->mRadiusY, tmpVal, aString);
  1903       needSep = true;
  1906   if (aGradient->mBgPosX.GetUnit() != eStyleUnit_None) {
  1907     MOZ_ASSERT(aGradient->mBgPosY.GetUnit() != eStyleUnit_None);
  1908     if (!isRadial && !aGradient->mLegacySyntax) {
  1909       AppendCSSGradientToBoxPosition(aGradient, aString, needSep);
  1910     } else if (aGradient->mBgPosX.GetUnit() != eStyleUnit_Percent ||
  1911                aGradient->mBgPosX.GetPercentValue() != 0.5f ||
  1912                aGradient->mBgPosY.GetUnit() != eStyleUnit_Percent ||
  1913                aGradient->mBgPosY.GetPercentValue() != (isRadial ? 0.5f : 1.0f)) {
  1914       if (isRadial && !aGradient->mLegacySyntax) {
  1915         if (needSep) {
  1916           aString.AppendLiteral(" ");
  1918         aString.AppendLiteral("at ");
  1919         needSep = false;
  1921       AppendCSSGradientLength(aGradient->mBgPosX, tmpVal, aString);
  1922       if (aGradient->mBgPosY.GetUnit() != eStyleUnit_None) {
  1923         aString.AppendLiteral(" ");
  1924         AppendCSSGradientLength(aGradient->mBgPosY, tmpVal, aString);
  1926       needSep = true;
  1929   if (aGradient->mAngle.GetUnit() != eStyleUnit_None) {
  1930     MOZ_ASSERT(!isRadial || aGradient->mLegacySyntax);
  1931     if (needSep) {
  1932       aString.AppendLiteral(" ");
  1934     nsStyleUtil::AppendAngleValue(aGradient->mAngle, aString);
  1935     needSep = true;
  1938   if (isRadial && aGradient->mLegacySyntax &&
  1939       (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR ||
  1940        aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)) {
  1941     MOZ_ASSERT(aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE);
  1942     if (needSep) {
  1943       aString.AppendLiteral(", ");
  1944       needSep = false;
  1946     if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
  1947       aString.AppendLiteral("circle");
  1948       needSep = true;
  1950     if (aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) {
  1951       if (needSep) {
  1952         aString.AppendLiteral(" ");
  1954       AppendASCIItoUTF16(nsCSSProps::
  1955                          ValueToKeyword(aGradient->mSize,
  1956                                         nsCSSProps::kRadialGradientSizeKTable),
  1957                          aString);
  1959     needSep = true;
  1963   // color stops
  1964   for (uint32_t i = 0; i < aGradient->mStops.Length(); ++i) {
  1965     if (needSep) {
  1966       aString.AppendLiteral(", ");
  1968     SetToRGBAColor(tmpVal, aGradient->mStops[i].mColor);
  1969     tmpVal->GetCssText(tokenString);
  1970     aString.Append(tokenString);
  1972     if (aGradient->mStops[i].mLocation.GetUnit() != eStyleUnit_None) {
  1973       aString.AppendLiteral(" ");
  1974       AppendCSSGradientLength(aGradient->mStops[i].mLocation, tmpVal, aString);
  1976     needSep = true;
  1979   delete tmpVal;
  1980   aString.AppendLiteral(")");
  1983 // -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
  1984 void
  1985 nsComputedDOMStyle::GetImageRectString(nsIURI* aURI,
  1986                                        const nsStyleSides& aCropRect,
  1987                                        nsString& aString)
  1989   nsDOMCSSValueList* valueList = GetROCSSValueList(true);
  1991   // <uri>
  1992   nsROCSSPrimitiveValue *valURI = new nsROCSSPrimitiveValue;
  1993   valueList->AppendCSSValue(valURI);
  1994   valURI->SetURI(aURI);
  1996   // <top>, <right>, <bottom>, <left>
  1997   NS_FOR_CSS_SIDES(side) {
  1998     nsROCSSPrimitiveValue *valSide = new nsROCSSPrimitiveValue;
  1999     valueList->AppendCSSValue(valSide);
  2000     SetValueToCoord(valSide, aCropRect.Get(side), false);
  2003   nsAutoString argumentString;
  2004   valueList->GetCssText(argumentString);
  2005   delete valueList;
  2007   aString = NS_LITERAL_STRING("-moz-image-rect(") +
  2008             argumentString +
  2009             NS_LITERAL_STRING(")");
  2012 void
  2013 nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage,
  2014                                          nsROCSSPrimitiveValue* aValue)
  2016   switch (aStyleImage.GetType()) {
  2017     case eStyleImageType_Image:
  2019       imgIRequest *req = aStyleImage.GetImageData();
  2020       nsCOMPtr<nsIURI> uri;
  2021       req->GetURI(getter_AddRefs(uri));
  2023       const nsStyleSides* cropRect = aStyleImage.GetCropRect();
  2024       if (cropRect) {
  2025         nsAutoString imageRectString;
  2026         GetImageRectString(uri, *cropRect, imageRectString);
  2027         aValue->SetString(imageRectString);
  2028       } else {
  2029         aValue->SetURI(uri);
  2031       break;
  2033     case eStyleImageType_Gradient:
  2035       nsAutoString gradientString;
  2036       GetCSSGradientString(aStyleImage.GetGradientData(),
  2037                            gradientString);
  2038       aValue->SetString(gradientString);
  2039       break;
  2041     case eStyleImageType_Element:
  2043       nsAutoString elementId;
  2044       nsStyleUtil::AppendEscapedCSSIdent(
  2045         nsDependentString(aStyleImage.GetElementId()), elementId);
  2046       nsAutoString elementString = NS_LITERAL_STRING("-moz-element(#") +
  2047                                    elementId +
  2048                                    NS_LITERAL_STRING(")");
  2049       aValue->SetString(elementString);
  2050       break;
  2052     case eStyleImageType_Null:
  2053       aValue->SetIdent(eCSSKeyword_none);
  2054       break;
  2055     default:
  2056       NS_NOTREACHED("unexpected image type");
  2057       break;
  2061 CSSValue*
  2062 nsComputedDOMStyle::DoGetBackgroundImage()
  2064   const nsStyleBackground* bg = StyleBackground();
  2066   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  2068   for (uint32_t i = 0, i_end = bg->mImageCount; i < i_end; ++i) {
  2069     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2070     valueList->AppendCSSValue(val);
  2072     const nsStyleImage& image = bg->mLayers[i].mImage;
  2073     SetValueToStyleImage(image, val);
  2076   return valueList;
  2079 CSSValue*
  2080 nsComputedDOMStyle::DoGetBackgroundInlinePolicy()
  2082   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2083   val->SetIdent(nsCSSProps::ValueToKeywordEnum(
  2084                   StyleBackground()->mBackgroundInlinePolicy,
  2085                   nsCSSProps::kBackgroundInlinePolicyKTable));
  2086   return val;
  2089 CSSValue*
  2090 nsComputedDOMStyle::DoGetBackgroundBlendMode()
  2092   return GetBackgroundList(&nsStyleBackground::Layer::mBlendMode,
  2093                            &nsStyleBackground::mBlendModeCount,
  2094                            nsCSSProps::kBlendModeKTable);
  2097 CSSValue*
  2098 nsComputedDOMStyle::DoGetBackgroundOrigin()
  2100   return GetBackgroundList(&nsStyleBackground::Layer::mOrigin,
  2101                            &nsStyleBackground::mOriginCount,
  2102                            nsCSSProps::kBackgroundOriginKTable);
  2105 CSSValue*
  2106 nsComputedDOMStyle::DoGetBackgroundPosition()
  2108   const nsStyleBackground* bg = StyleBackground();
  2110   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  2112   for (uint32_t i = 0, i_end = bg->mPositionCount; i < i_end; ++i) {
  2113     nsDOMCSSValueList *itemList = GetROCSSValueList(false);
  2114     valueList->AppendCSSValue(itemList);
  2116     nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue;
  2117     itemList->AppendCSSValue(valX);
  2119     nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue;
  2120     itemList->AppendCSSValue(valY);
  2122     const nsStyleBackground::Position &pos = bg->mLayers[i].mPosition;
  2124     if (!pos.mXPosition.mHasPercent) {
  2125       NS_ABORT_IF_FALSE(pos.mXPosition.mPercent == 0.0f,
  2126                         "Shouldn't have mPercent!");
  2127       valX->SetAppUnits(pos.mXPosition.mLength);
  2128     } else if (pos.mXPosition.mLength == 0) {
  2129       valX->SetPercent(pos.mXPosition.mPercent);
  2130     } else {
  2131       SetValueToCalc(&pos.mXPosition, valX);
  2134     if (!pos.mYPosition.mHasPercent) {
  2135       NS_ABORT_IF_FALSE(pos.mYPosition.mPercent == 0.0f,
  2136                         "Shouldn't have mPercent!");
  2137       valY->SetAppUnits(pos.mYPosition.mLength);
  2138     } else if (pos.mYPosition.mLength == 0) {
  2139       valY->SetPercent(pos.mYPosition.mPercent);
  2140     } else {
  2141       SetValueToCalc(&pos.mYPosition, valY);
  2145   return valueList;
  2148 CSSValue*
  2149 nsComputedDOMStyle::DoGetBackgroundRepeat()
  2151   const nsStyleBackground* bg = StyleBackground();
  2153   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  2155   for (uint32_t i = 0, i_end = bg->mRepeatCount; i < i_end; ++i) {
  2156     nsDOMCSSValueList *itemList = GetROCSSValueList(false);
  2157     valueList->AppendCSSValue(itemList);
  2159     nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue;
  2160     itemList->AppendCSSValue(valX);
  2162     const uint8_t& xRepeat = bg->mLayers[i].mRepeat.mXRepeat;
  2163     const uint8_t& yRepeat = bg->mLayers[i].mRepeat.mYRepeat;
  2165     bool hasContraction = true;
  2166     unsigned contraction;
  2167     if (xRepeat == yRepeat) {
  2168       contraction = xRepeat;
  2169     } else if (xRepeat == NS_STYLE_BG_REPEAT_REPEAT &&
  2170                yRepeat == NS_STYLE_BG_REPEAT_NO_REPEAT) {
  2171       contraction = NS_STYLE_BG_REPEAT_REPEAT_X;
  2172     } else if (xRepeat == NS_STYLE_BG_REPEAT_NO_REPEAT &&
  2173                yRepeat == NS_STYLE_BG_REPEAT_REPEAT) {
  2174       contraction = NS_STYLE_BG_REPEAT_REPEAT_Y;
  2175     } else {
  2176       hasContraction = false;
  2179     if (hasContraction) {
  2180       valX->SetIdent(nsCSSProps::ValueToKeywordEnum(contraction,
  2181                                          nsCSSProps::kBackgroundRepeatKTable));
  2182     } else {
  2183       nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue;
  2184       itemList->AppendCSSValue(valY);
  2186       valX->SetIdent(nsCSSProps::ValueToKeywordEnum(xRepeat,
  2187                                           nsCSSProps::kBackgroundRepeatKTable));
  2188       valY->SetIdent(nsCSSProps::ValueToKeywordEnum(yRepeat,
  2189                                           nsCSSProps::kBackgroundRepeatKTable));
  2193   return valueList;
  2196 CSSValue*
  2197 nsComputedDOMStyle::DoGetBackgroundSize()
  2199   const nsStyleBackground* bg = StyleBackground();
  2201   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  2203   for (uint32_t i = 0, i_end = bg->mSizeCount; i < i_end; ++i) {
  2204     const nsStyleBackground::Size &size = bg->mLayers[i].mSize;
  2206     switch (size.mWidthType) {
  2207       case nsStyleBackground::Size::eContain:
  2208       case nsStyleBackground::Size::eCover: {
  2209         NS_ABORT_IF_FALSE(size.mWidthType == size.mHeightType,
  2210                           "unsynced types");
  2211         nsCSSKeyword keyword = size.mWidthType == nsStyleBackground::Size::eContain
  2212                              ? eCSSKeyword_contain
  2213                              : eCSSKeyword_cover;
  2214         nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  2215         valueList->AppendCSSValue(val);
  2216         val->SetIdent(keyword);
  2217         break;
  2219       default: {
  2220         nsDOMCSSValueList *itemList = GetROCSSValueList(false);
  2221         valueList->AppendCSSValue(itemList);
  2223         nsROCSSPrimitiveValue* valX = new nsROCSSPrimitiveValue;
  2224         itemList->AppendCSSValue(valX);
  2225         nsROCSSPrimitiveValue* valY = new nsROCSSPrimitiveValue;
  2226         itemList->AppendCSSValue(valY);
  2228         if (size.mWidthType == nsStyleBackground::Size::eAuto) {
  2229           valX->SetIdent(eCSSKeyword_auto);
  2230         } else {
  2231           NS_ABORT_IF_FALSE(size.mWidthType ==
  2232                               nsStyleBackground::Size::eLengthPercentage,
  2233                             "bad mWidthType");
  2234           if (!size.mWidth.mHasPercent &&
  2235               // negative values must have come from calc()
  2236               size.mWidth.mLength >= 0) {
  2237             NS_ABORT_IF_FALSE(size.mWidth.mPercent == 0.0f,
  2238                               "Shouldn't have mPercent");
  2239             valX->SetAppUnits(size.mWidth.mLength);
  2240           } else if (size.mWidth.mLength == 0 &&
  2241                      // negative values must have come from calc()
  2242                      size.mWidth.mPercent >= 0.0f) {
  2243             valX->SetPercent(size.mWidth.mPercent);
  2244           } else {
  2245             SetValueToCalc(&size.mWidth, valX);
  2249         if (size.mHeightType == nsStyleBackground::Size::eAuto) {
  2250           valY->SetIdent(eCSSKeyword_auto);
  2251         } else {
  2252           NS_ABORT_IF_FALSE(size.mHeightType ==
  2253                               nsStyleBackground::Size::eLengthPercentage,
  2254                             "bad mHeightType");
  2255           if (!size.mHeight.mHasPercent &&
  2256               // negative values must have come from calc()
  2257               size.mHeight.mLength >= 0) {
  2258             NS_ABORT_IF_FALSE(size.mHeight.mPercent == 0.0f,
  2259                               "Shouldn't have mPercent");
  2260             valY->SetAppUnits(size.mHeight.mLength);
  2261           } else if (size.mHeight.mLength == 0 &&
  2262                      // negative values must have come from calc()
  2263                      size.mHeight.mPercent >= 0.0f) {
  2264             valY->SetPercent(size.mHeight.mPercent);
  2265           } else {
  2266             SetValueToCalc(&size.mHeight, valY);
  2269         break;
  2274   return valueList;
  2277 CSSValue*
  2278 nsComputedDOMStyle::DoGetGridTemplateAreas()
  2280   const css::GridTemplateAreasValue* areas =
  2281     StylePosition()->mGridTemplateAreas;
  2282   if (!areas) {
  2283     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2284     val->SetIdent(eCSSKeyword_none);
  2285     return val;
  2288   MOZ_ASSERT(!areas->mTemplates.IsEmpty(),
  2289              "Unexpected empty array in GridTemplateAreasValue");
  2290   nsDOMCSSValueList *valueList = GetROCSSValueList(false);
  2291   for (uint32_t i = 0; i < areas->mTemplates.Length(); i++) {
  2292     nsAutoString str;
  2293     nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[i], str);
  2294     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2295     val->SetString(str);
  2296     valueList->AppendCSSValue(val);
  2298   return valueList;
  2301 // aLineNames must not be empty
  2302 CSSValue*
  2303 nsComputedDOMStyle::GetGridLineNames(const nsTArray<nsString>& aLineNames)
  2305   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2306   nsAutoString lineNamesString;
  2307   uint32_t i_end = aLineNames.Length();
  2308   lineNamesString.AssignLiteral("(");
  2309   if (i_end > 0) {
  2310     for (uint32_t i = 0;;) {
  2311       nsStyleUtil::AppendEscapedCSSIdent(aLineNames[i], lineNamesString);
  2312       if (++i == i_end) {
  2313         break;
  2315       lineNamesString.AppendLiteral(" ");
  2318   lineNamesString.AppendLiteral(")");
  2319   val->SetString(lineNamesString);
  2320   return val;
  2323 CSSValue*
  2324 nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue,
  2325                                      const nsStyleCoord& aMaxValue)
  2327   // FIXME bug 978212: for grid-template-columns and grid-template-rows
  2328   // (not grid-auto-columns and grid-auto-rows), if we have frame,
  2329   // every <track-size> should be resolved into 'px' here,
  2330   // based on layout results.
  2331   if (aMinValue == aMaxValue) {
  2332     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2333     SetValueToCoord(val, aMinValue, true,
  2334                     nullptr, nsCSSProps::kGridTrackBreadthKTable);
  2335     return val;
  2338   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2339   nsAutoString argumentStr, minmaxStr;
  2340   minmaxStr.AppendLiteral("minmax(");
  2342   SetValueToCoord(val, aMinValue, true,
  2343                   nullptr, nsCSSProps::kGridTrackBreadthKTable);
  2344   val->GetCssText(argumentStr);
  2345   minmaxStr.Append(argumentStr);
  2347   minmaxStr.AppendLiteral(", ");
  2349   SetValueToCoord(val, aMaxValue, true,
  2350                   nullptr, nsCSSProps::kGridTrackBreadthKTable);
  2351   val->GetCssText(argumentStr);
  2352   minmaxStr.Append(argumentStr);
  2354   minmaxStr.Append(char16_t(')'));
  2355   val->SetString(minmaxStr);
  2356   return val;
  2359 CSSValue*
  2360 nsComputedDOMStyle::GetGridTemplateColumnsRows(const nsStyleGridTemplate& aTrackList)
  2362   if (aTrackList.mIsSubgrid) {
  2363     NS_ASSERTION(aTrackList.mMinTrackSizingFunctions.IsEmpty() &&
  2364                  aTrackList.mMaxTrackSizingFunctions.IsEmpty(),
  2365                  "Unexpected sizing functions with subgrid");
  2366     nsDOMCSSValueList* valueList = GetROCSSValueList(false);
  2368     nsROCSSPrimitiveValue* subgridKeyword = new nsROCSSPrimitiveValue;
  2369     subgridKeyword->SetIdent(eCSSKeyword_subgrid);
  2370     valueList->AppendCSSValue(subgridKeyword);
  2372     for (uint32_t i = 0; i < aTrackList.mLineNameLists.Length(); i++) {
  2373       valueList->AppendCSSValue(GetGridLineNames(aTrackList.mLineNameLists[i]));
  2375     return valueList;
  2378   uint32_t numSizes = aTrackList.mMinTrackSizingFunctions.Length();
  2379   MOZ_ASSERT(aTrackList.mMaxTrackSizingFunctions.Length() == numSizes,
  2380              "Different number of min and max track sizing functions");
  2381   // An empty <track-list> is represented as "none" in syntax.
  2382   if (numSizes == 0) {
  2383     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  2384     val->SetIdent(eCSSKeyword_none);
  2385     return val;
  2388   nsDOMCSSValueList* valueList = GetROCSSValueList(false);
  2389   // Delimiting N tracks requires N+1 lines:
  2390   // one before each track, plus one at the very end.
  2391   MOZ_ASSERT(aTrackList.mLineNameLists.Length() == numSizes + 1,
  2392              "Unexpected number of line name lists");
  2393   for (uint32_t i = 0;; i++) {
  2394     const nsTArray<nsString>& lineNames = aTrackList.mLineNameLists[i];
  2395     if (!lineNames.IsEmpty()) {
  2396       valueList->AppendCSSValue(GetGridLineNames(lineNames));
  2398     if (i == numSizes) {
  2399       break;
  2401     valueList->AppendCSSValue(GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i],
  2402                                                aTrackList.mMaxTrackSizingFunctions[i]));
  2405   return valueList;
  2408 CSSValue*
  2409 nsComputedDOMStyle::DoGetGridAutoFlow()
  2411   nsAutoString str;
  2412   nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_grid_auto_flow,
  2413                                      StylePosition()->mGridAutoFlow,
  2414                                      NS_STYLE_GRID_AUTO_FLOW_NONE,
  2415                                      NS_STYLE_GRID_AUTO_FLOW_DENSE,
  2416                                      str);
  2417   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  2418   val->SetString(str);
  2419   return val;
  2422 CSSValue*
  2423 nsComputedDOMStyle::DoGetGridAutoColumns()
  2425   return GetGridTrackSize(StylePosition()->mGridAutoColumnsMin,
  2426                           StylePosition()->mGridAutoColumnsMax);
  2429 CSSValue*
  2430 nsComputedDOMStyle::DoGetGridAutoRows()
  2432   return GetGridTrackSize(StylePosition()->mGridAutoRowsMin,
  2433                           StylePosition()->mGridAutoRowsMax);
  2436 CSSValue*
  2437 nsComputedDOMStyle::DoGetGridTemplateColumns()
  2439   return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns);
  2442 CSSValue*
  2443 nsComputedDOMStyle::DoGetGridTemplateRows()
  2445   return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows);
  2448 CSSValue*
  2449 nsComputedDOMStyle::GetGridLine(const nsStyleGridLine& aGridLine)
  2451   if (aGridLine.IsAuto()) {
  2452     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  2453     val->SetIdent(eCSSKeyword_auto);
  2454     return val;
  2457   nsDOMCSSValueList* valueList = GetROCSSValueList(false);
  2459   if (aGridLine.mHasSpan) {
  2460     nsROCSSPrimitiveValue* span = new nsROCSSPrimitiveValue;
  2461     span->SetIdent(eCSSKeyword_span);
  2462     valueList->AppendCSSValue(span);
  2465   if (aGridLine.mInteger != 0) {
  2466     nsROCSSPrimitiveValue* integer = new nsROCSSPrimitiveValue;
  2467     integer->SetNumber(aGridLine.mInteger);
  2468     valueList->AppendCSSValue(integer);
  2471   if (!aGridLine.mLineName.IsEmpty()) {
  2472     nsROCSSPrimitiveValue* lineName = new nsROCSSPrimitiveValue;
  2473     nsString escapedLineName;
  2474     nsStyleUtil::AppendEscapedCSSIdent(aGridLine.mLineName, escapedLineName);
  2475     lineName->SetString(escapedLineName);
  2476     valueList->AppendCSSValue(lineName);
  2479   NS_ASSERTION(valueList->Length() > 0,
  2480                "Should have appended at least one value");
  2481   return valueList;
  2484 CSSValue*
  2485 nsComputedDOMStyle::DoGetGridAutoPosition()
  2487   nsDOMCSSValueList* valueList = GetROCSSValueList(false);
  2489   valueList->AppendCSSValue(
  2490     GetGridLine(StylePosition()->mGridAutoPositionColumn));
  2492   nsROCSSPrimitiveValue* slash = new nsROCSSPrimitiveValue;
  2493   slash->SetString(NS_LITERAL_STRING("/"));
  2494   valueList->AppendCSSValue(slash);
  2496   valueList->AppendCSSValue(
  2497     GetGridLine(StylePosition()->mGridAutoPositionRow));
  2499   return valueList;
  2502 CSSValue*
  2503 nsComputedDOMStyle::DoGetGridColumnStart()
  2505   return GetGridLine(StylePosition()->mGridColumnStart);
  2508 CSSValue*
  2509 nsComputedDOMStyle::DoGetGridColumnEnd()
  2511   return GetGridLine(StylePosition()->mGridColumnEnd);
  2514 CSSValue*
  2515 nsComputedDOMStyle::DoGetGridRowStart()
  2517   return GetGridLine(StylePosition()->mGridRowStart);
  2520 CSSValue*
  2521 nsComputedDOMStyle::DoGetGridRowEnd()
  2523   return GetGridLine(StylePosition()->mGridRowEnd);
  2526 CSSValue*
  2527 nsComputedDOMStyle::DoGetPaddingTop()
  2529   return GetPaddingWidthFor(NS_SIDE_TOP);
  2532 CSSValue*
  2533 nsComputedDOMStyle::DoGetPaddingBottom()
  2535   return GetPaddingWidthFor(NS_SIDE_BOTTOM);
  2538 CSSValue*
  2539 nsComputedDOMStyle::DoGetPaddingLeft()
  2541   return GetPaddingWidthFor(NS_SIDE_LEFT);
  2544 CSSValue*
  2545 nsComputedDOMStyle::DoGetPaddingRight()
  2547   return GetPaddingWidthFor(NS_SIDE_RIGHT);
  2550 CSSValue*
  2551 nsComputedDOMStyle::DoGetBorderCollapse()
  2553   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  2554   val->SetIdent(
  2555     nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mBorderCollapse,
  2556                                    nsCSSProps::kBorderCollapseKTable));
  2557   return val;
  2560 CSSValue*
  2561 nsComputedDOMStyle::DoGetBorderSpacing()
  2563   nsDOMCSSValueList *valueList = GetROCSSValueList(false);
  2565   nsROCSSPrimitiveValue* xSpacing = new nsROCSSPrimitiveValue;
  2566   valueList->AppendCSSValue(xSpacing);
  2568   nsROCSSPrimitiveValue* ySpacing = new nsROCSSPrimitiveValue;
  2569   valueList->AppendCSSValue(ySpacing);
  2571   const nsStyleTableBorder *border = StyleTableBorder();
  2572   xSpacing->SetAppUnits(border->mBorderSpacingX);
  2573   ySpacing->SetAppUnits(border->mBorderSpacingY);
  2575   return valueList;
  2578 CSSValue*
  2579 nsComputedDOMStyle::DoGetCaptionSide()
  2581   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2582   val->SetIdent(
  2583     nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mCaptionSide,
  2584                                    nsCSSProps::kCaptionSideKTable));
  2585   return val;
  2588 CSSValue*
  2589 nsComputedDOMStyle::DoGetEmptyCells()
  2591   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2592   val->SetIdent(
  2593     nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mEmptyCells,
  2594                                    nsCSSProps::kEmptyCellsKTable));
  2595   return val;
  2598 CSSValue*
  2599 nsComputedDOMStyle::DoGetTableLayout()
  2601   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2602   val->SetIdent(
  2603     nsCSSProps::ValueToKeywordEnum(StyleTable()->mLayoutStrategy,
  2604                                    nsCSSProps::kTableLayoutKTable));
  2605   return val;
  2608 CSSValue*
  2609 nsComputedDOMStyle::DoGetBorderTopStyle()
  2611   return GetBorderStyleFor(NS_SIDE_TOP);
  2614 CSSValue*
  2615 nsComputedDOMStyle::DoGetBorderBottomStyle()
  2617   return GetBorderStyleFor(NS_SIDE_BOTTOM);
  2620 CSSValue*
  2621 nsComputedDOMStyle::DoGetBorderLeftStyle()
  2623   return GetBorderStyleFor(NS_SIDE_LEFT);
  2626 CSSValue*
  2627 nsComputedDOMStyle::DoGetBorderRightStyle()
  2629   return GetBorderStyleFor(NS_SIDE_RIGHT);
  2632 CSSValue*
  2633 nsComputedDOMStyle::DoGetBorderBottomColors()
  2635   return GetBorderColorsFor(NS_SIDE_BOTTOM);
  2638 CSSValue*
  2639 nsComputedDOMStyle::DoGetBorderLeftColors()
  2641   return GetBorderColorsFor(NS_SIDE_LEFT);
  2644 CSSValue*
  2645 nsComputedDOMStyle::DoGetBorderRightColors()
  2647   return GetBorderColorsFor(NS_SIDE_RIGHT);
  2651 CSSValue*
  2652 nsComputedDOMStyle::DoGetBorderTopColors()
  2654   return GetBorderColorsFor(NS_SIDE_TOP);
  2657 CSSValue*
  2658 nsComputedDOMStyle::DoGetBorderBottomLeftRadius()
  2660   return GetEllipseRadii(StyleBorder()->mBorderRadius,
  2661                          NS_CORNER_BOTTOM_LEFT, true);
  2664 CSSValue*
  2665 nsComputedDOMStyle::DoGetBorderBottomRightRadius()
  2667   return GetEllipseRadii(StyleBorder()->mBorderRadius,
  2668                          NS_CORNER_BOTTOM_RIGHT, true);
  2671 CSSValue*
  2672 nsComputedDOMStyle::DoGetBorderTopLeftRadius()
  2674   return GetEllipseRadii(StyleBorder()->mBorderRadius,
  2675                          NS_CORNER_TOP_LEFT, true);
  2678 CSSValue*
  2679 nsComputedDOMStyle::DoGetBorderTopRightRadius()
  2681   return GetEllipseRadii(StyleBorder()->mBorderRadius,
  2682                          NS_CORNER_TOP_RIGHT, true);
  2685 CSSValue*
  2686 nsComputedDOMStyle::DoGetBorderTopWidth()
  2688   return GetBorderWidthFor(NS_SIDE_TOP);
  2691 CSSValue*
  2692 nsComputedDOMStyle::DoGetBorderBottomWidth()
  2694   return GetBorderWidthFor(NS_SIDE_BOTTOM);
  2697 CSSValue*
  2698 nsComputedDOMStyle::DoGetBorderLeftWidth()
  2700   return GetBorderWidthFor(NS_SIDE_LEFT);
  2703 CSSValue*
  2704 nsComputedDOMStyle::DoGetBorderRightWidth()
  2706   return GetBorderWidthFor(NS_SIDE_RIGHT);
  2709 CSSValue*
  2710 nsComputedDOMStyle::DoGetBorderTopColor()
  2712   return GetBorderColorFor(NS_SIDE_TOP);
  2715 CSSValue*
  2716 nsComputedDOMStyle::DoGetBorderBottomColor()
  2718   return GetBorderColorFor(NS_SIDE_BOTTOM);
  2721 CSSValue*
  2722 nsComputedDOMStyle::DoGetBorderLeftColor()
  2724   return GetBorderColorFor(NS_SIDE_LEFT);
  2727 CSSValue*
  2728 nsComputedDOMStyle::DoGetBorderRightColor()
  2730   return GetBorderColorFor(NS_SIDE_RIGHT);
  2733 CSSValue*
  2734 nsComputedDOMStyle::DoGetMarginTopWidth()
  2736   return GetMarginWidthFor(NS_SIDE_TOP);
  2739 CSSValue*
  2740 nsComputedDOMStyle::DoGetMarginBottomWidth()
  2742   return GetMarginWidthFor(NS_SIDE_BOTTOM);
  2745 CSSValue*
  2746 nsComputedDOMStyle::DoGetMarginLeftWidth()
  2748   return GetMarginWidthFor(NS_SIDE_LEFT);
  2751 CSSValue*
  2752 nsComputedDOMStyle::DoGetMarginRightWidth()
  2754   return GetMarginWidthFor(NS_SIDE_RIGHT);
  2757 CSSValue*
  2758 nsComputedDOMStyle::DoGetMarkerOffset()
  2760   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  2761   SetValueToCoord(val, StyleContent()->mMarkerOffset, false);
  2762   return val;
  2765 CSSValue*
  2766 nsComputedDOMStyle::DoGetOrient()
  2768   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2769   val->SetIdent(
  2770     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOrient,
  2771                                    nsCSSProps::kOrientKTable));
  2772   return val;
  2775 CSSValue*
  2776 nsComputedDOMStyle::DoGetOutlineWidth()
  2778   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  2780   const nsStyleOutline* outline = StyleOutline();
  2782   nscoord width;
  2783   if (outline->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) {
  2784     NS_ASSERTION(outline->GetOutlineWidth(width) && width == 0,
  2785                  "unexpected width");
  2786     width = 0;
  2787   } else {
  2788 #ifdef DEBUG
  2789     bool res =
  2790 #endif
  2791       outline->GetOutlineWidth(width);
  2792     NS_ASSERTION(res, "percent outline doesn't exist");
  2794   val->SetAppUnits(width);
  2796   return val;
  2799 CSSValue*
  2800 nsComputedDOMStyle::DoGetOutlineStyle()
  2802   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  2803   val->SetIdent(
  2804     nsCSSProps::ValueToKeywordEnum(StyleOutline()->GetOutlineStyle(),
  2805                                    nsCSSProps::kOutlineStyleKTable));
  2806   return val;
  2809 CSSValue*
  2810 nsComputedDOMStyle::DoGetOutlineOffset()
  2812   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  2813   val->SetAppUnits(StyleOutline()->mOutlineOffset);
  2814   return val;
  2817 CSSValue*
  2818 nsComputedDOMStyle::DoGetOutlineRadiusBottomLeft()
  2820   return GetEllipseRadii(StyleOutline()->mOutlineRadius,
  2821                          NS_CORNER_BOTTOM_LEFT, false);
  2824 CSSValue*
  2825 nsComputedDOMStyle::DoGetOutlineRadiusBottomRight()
  2827   return GetEllipseRadii(StyleOutline()->mOutlineRadius,
  2828                          NS_CORNER_BOTTOM_RIGHT, false);
  2831 CSSValue*
  2832 nsComputedDOMStyle::DoGetOutlineRadiusTopLeft()
  2834   return GetEllipseRadii(StyleOutline()->mOutlineRadius,
  2835                          NS_CORNER_TOP_LEFT, false);
  2838 CSSValue*
  2839 nsComputedDOMStyle::DoGetOutlineRadiusTopRight()
  2841   return GetEllipseRadii(StyleOutline()->mOutlineRadius,
  2842                          NS_CORNER_TOP_RIGHT, false);
  2845 CSSValue*
  2846 nsComputedDOMStyle::DoGetOutlineColor()
  2848   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  2850   nscolor color;
  2851   if (!StyleOutline()->GetOutlineColor(color))
  2852     color = StyleColor()->mColor;
  2854   SetToRGBAColor(val, color);
  2855   return val;
  2858 CSSValue*
  2859 nsComputedDOMStyle::GetEllipseRadii(const nsStyleCorners& aRadius,
  2860                                     uint8_t aFullCorner,
  2861                                     bool aIsBorder) // else outline
  2863   nsStyleCoord radiusX, radiusY;
  2864   if (mInnerFrame && aIsBorder) {
  2865     nscoord radii[8];
  2866     mInnerFrame->GetBorderRadii(radii);
  2867     radiusX.SetCoordValue(radii[NS_FULL_TO_HALF_CORNER(aFullCorner, false)]);
  2868     radiusY.SetCoordValue(radii[NS_FULL_TO_HALF_CORNER(aFullCorner, true)]);
  2869   } else {
  2870     radiusX = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, false));
  2871     radiusY = aRadius.Get(NS_FULL_TO_HALF_CORNER(aFullCorner, true));
  2873     if (mInnerFrame) {
  2874       // We need to convert to absolute coordinates before doing the
  2875       // equality check below.
  2876       nscoord v;
  2878       v = StyleCoordToNSCoord(radiusX,
  2879                               &nsComputedDOMStyle::GetFrameBorderRectWidth,
  2880                               0, true);
  2881       radiusX.SetCoordValue(v);
  2883       v = StyleCoordToNSCoord(radiusY,
  2884                               &nsComputedDOMStyle::GetFrameBorderRectHeight,
  2885                               0, true);
  2886       radiusY.SetCoordValue(v);
  2890   // for compatibility, return a single value if X and Y are equal
  2891   if (radiusX == radiusY) {
  2892     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2894     SetValueToCoord(val, radiusX, true);
  2896     return val;
  2899   nsDOMCSSValueList *valueList = GetROCSSValueList(false);
  2901   nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue;
  2902   valueList->AppendCSSValue(valX);
  2904   nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue;
  2905   valueList->AppendCSSValue(valY);
  2907   SetValueToCoord(valX, radiusX, true);
  2908   SetValueToCoord(valY, radiusY, true);
  2910   return valueList;
  2913 CSSValue*
  2914 nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray,
  2915                                       const nscolor& aDefaultColor,
  2916                                       bool aIsBoxShadow)
  2918   if (!aArray) {
  2919     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2920     val->SetIdent(eCSSKeyword_none);
  2921     return val;
  2924   static nscoord nsCSSShadowItem::* const shadowValuesNoSpread[] = {
  2925     &nsCSSShadowItem::mXOffset,
  2926     &nsCSSShadowItem::mYOffset,
  2927     &nsCSSShadowItem::mRadius
  2928   };
  2930   static nscoord nsCSSShadowItem::* const shadowValuesWithSpread[] = {
  2931     &nsCSSShadowItem::mXOffset,
  2932     &nsCSSShadowItem::mYOffset,
  2933     &nsCSSShadowItem::mRadius,
  2934     &nsCSSShadowItem::mSpread
  2935   };
  2937   nscoord nsCSSShadowItem::* const * shadowValues;
  2938   uint32_t shadowValuesLength;
  2939   if (aIsBoxShadow) {
  2940     shadowValues = shadowValuesWithSpread;
  2941     shadowValuesLength = ArrayLength(shadowValuesWithSpread);
  2942   } else {
  2943     shadowValues = shadowValuesNoSpread;
  2944     shadowValuesLength = ArrayLength(shadowValuesNoSpread);
  2947   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  2949   for (nsCSSShadowItem *item = aArray->ShadowAt(0),
  2950                    *item_end = item + aArray->Length();
  2951        item < item_end; ++item) {
  2952     nsDOMCSSValueList *itemList = GetROCSSValueList(false);
  2953     valueList->AppendCSSValue(itemList);
  2955     // Color is either the specified shadow color or the foreground color
  2956     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  2957     itemList->AppendCSSValue(val);
  2958     nscolor shadowColor;
  2959     if (item->mHasColor) {
  2960       shadowColor = item->mColor;
  2961     } else {
  2962       shadowColor = aDefaultColor;
  2964     SetToRGBAColor(val, shadowColor);
  2966     // Set the offsets, blur radius, and spread if available
  2967     for (uint32_t i = 0; i < shadowValuesLength; ++i) {
  2968       val = new nsROCSSPrimitiveValue;
  2969       itemList->AppendCSSValue(val);
  2970       val->SetAppUnits(item->*(shadowValues[i]));
  2973     if (item->mInset && aIsBoxShadow) {
  2974       // This is an inset box-shadow
  2975       val = new nsROCSSPrimitiveValue;
  2976       itemList->AppendCSSValue(val);
  2977       val->SetIdent(
  2978         nsCSSProps::ValueToKeywordEnum(NS_STYLE_BOX_SHADOW_INSET,
  2979                                        nsCSSProps::kBoxShadowTypeKTable));
  2983   return valueList;
  2986 CSSValue*
  2987 nsComputedDOMStyle::DoGetBoxShadow()
  2989   return GetCSSShadowArray(StyleBorder()->mBoxShadow,
  2990                            StyleColor()->mColor,
  2991                            true);
  2994 CSSValue*
  2995 nsComputedDOMStyle::DoGetZIndex()
  2997   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  2998   SetValueToCoord(val, StylePosition()->mZIndex, false);
  2999   return val;
  3002 CSSValue*
  3003 nsComputedDOMStyle::DoGetListStyleImage()
  3005   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3007   const nsStyleList* list = StyleList();
  3009   if (!list->GetListStyleImage()) {
  3010     val->SetIdent(eCSSKeyword_none);
  3011   } else {
  3012     nsCOMPtr<nsIURI> uri;
  3013     if (list->GetListStyleImage()) {
  3014       list->GetListStyleImage()->GetURI(getter_AddRefs(uri));
  3016     val->SetURI(uri);
  3019   return val;
  3022 CSSValue*
  3023 nsComputedDOMStyle::DoGetListStylePosition()
  3025   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3026   val->SetIdent(
  3027     nsCSSProps::ValueToKeywordEnum(StyleList()->mListStylePosition,
  3028                                    nsCSSProps::kListStylePositionKTable));
  3029   return val;
  3032 CSSValue*
  3033 nsComputedDOMStyle::DoGetListStyleType()
  3035   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3036   val->SetIdent(
  3037     nsCSSProps::ValueToKeywordEnum(StyleList()->mListStyleType,
  3038                                    nsCSSProps::kListStyleKTable));
  3039   return val;
  3042 CSSValue*
  3043 nsComputedDOMStyle::DoGetImageRegion()
  3045   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3047   const nsStyleList* list = StyleList();
  3049   if (list->mImageRegion.width <= 0 || list->mImageRegion.height <= 0) {
  3050     val->SetIdent(eCSSKeyword_auto);
  3051   } else {
  3052     // create the cssvalues for the sides, stick them in the rect object
  3053     nsROCSSPrimitiveValue *topVal    = new nsROCSSPrimitiveValue;
  3054     nsROCSSPrimitiveValue *rightVal  = new nsROCSSPrimitiveValue;
  3055     nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue;
  3056     nsROCSSPrimitiveValue *leftVal   = new nsROCSSPrimitiveValue;
  3057     nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
  3058                                               bottomVal, leftVal);
  3059     topVal->SetAppUnits(list->mImageRegion.y);
  3060     rightVal->SetAppUnits(list->mImageRegion.width + list->mImageRegion.x);
  3061     bottomVal->SetAppUnits(list->mImageRegion.height + list->mImageRegion.y);
  3062     leftVal->SetAppUnits(list->mImageRegion.x);
  3063     val->SetRect(domRect);
  3066   return val;
  3069 CSSValue*
  3070 nsComputedDOMStyle::DoGetLineHeight()
  3072   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3074   nscoord lineHeight;
  3075   if (GetLineHeightCoord(lineHeight)) {
  3076     val->SetAppUnits(lineHeight);
  3077   } else {
  3078     SetValueToCoord(val, StyleText()->mLineHeight, true,
  3079                     nullptr, nsCSSProps::kLineHeightKTable);
  3082   return val;
  3085 CSSValue*
  3086 nsComputedDOMStyle::DoGetVerticalAlign()
  3088   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3089   SetValueToCoord(val, StyleTextReset()->mVerticalAlign, false,
  3090                   &nsComputedDOMStyle::GetLineHeightCoord,
  3091                   nsCSSProps::kVerticalAlignKTable);
  3092   return val;
  3095 CSSValue*
  3096 nsComputedDOMStyle::CreateTextAlignValue(uint8_t aAlign, bool aAlignTrue,
  3097                                          const KTableValue aTable[])
  3099   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3100   val->SetIdent(nsCSSProps::ValueToKeywordEnum(aAlign, aTable));
  3101   if (!aAlignTrue) {
  3102     return val;
  3105   nsROCSSPrimitiveValue* first = new nsROCSSPrimitiveValue;
  3106   first->SetIdent(eCSSKeyword_true);
  3108   nsDOMCSSValueList* valueList = GetROCSSValueList(false);
  3109   valueList->AppendCSSValue(first);
  3110   valueList->AppendCSSValue(val);
  3111   return valueList;
  3114 CSSValue*
  3115 nsComputedDOMStyle::DoGetTextAlign()
  3117   const nsStyleText* style = StyleText();
  3118   return CreateTextAlignValue(style->mTextAlign, style->mTextAlignTrue,
  3119                               nsCSSProps::kTextAlignKTable);
  3122 CSSValue*
  3123 nsComputedDOMStyle::DoGetTextAlignLast()
  3125   const nsStyleText* style = StyleText();
  3126   return CreateTextAlignValue(style->mTextAlignLast, style->mTextAlignLastTrue,
  3127                               nsCSSProps::kTextAlignLastKTable);
  3130 CSSValue*
  3131 nsComputedDOMStyle::DoGetTextCombineUpright()
  3133   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3134   uint8_t tch = StyleText()->mTextCombineUpright;
  3136   if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
  3137     val->SetIdent(
  3138       nsCSSProps::ValueToKeywordEnum(tch,
  3139                                      nsCSSProps::kTextCombineUprightKTable));
  3140   } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2) {
  3141     val->SetString(NS_LITERAL_STRING("digits 2"));
  3142   } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3) {
  3143     val->SetString(NS_LITERAL_STRING("digits 3"));
  3144   } else {
  3145     val->SetString(NS_LITERAL_STRING("digits 4"));
  3148   return val;
  3151 CSSValue*
  3152 nsComputedDOMStyle::DoGetTextDecoration()
  3154   const nsStyleTextReset* textReset = StyleTextReset();
  3156   // If decoration style or color wasn't initial value, the author knew the
  3157   // text-decoration is a shorthand property in CSS 3.
  3158   // Return nullptr in such cases.
  3159   if (textReset->GetDecorationStyle() != NS_STYLE_TEXT_DECORATION_STYLE_SOLID) {
  3160     return nullptr;
  3163   nscolor color;
  3164   bool isForegroundColor;
  3165   textReset->GetDecorationColor(color, isForegroundColor);
  3166   if (!isForegroundColor) {
  3167     return nullptr;
  3170   // Otherwise, the web pages may have been written for CSS 2.1 or earlier,
  3171   // i.e., text-decoration was assumed as a longhand property.  In that case,
  3172   // we should return computed value same as CSS 2.1 for backward compatibility.
  3174   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3175   uint8_t line = textReset->mTextDecorationLine;
  3176   // Clear the -moz-anchor-decoration bit and the OVERRIDE_ALL bits -- we
  3177   // don't want these to appear in the computed style.
  3178   line &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS |
  3179             NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL);
  3181   if (line == NS_STYLE_TEXT_DECORATION_LINE_NONE) {
  3182     val->SetIdent(eCSSKeyword_none);
  3183   } else {
  3184     nsAutoString str;
  3185     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
  3186       line, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
  3187       NS_STYLE_TEXT_DECORATION_LINE_BLINK, str);
  3188     val->SetString(str);
  3191   return val;
  3194 CSSValue*
  3195 nsComputedDOMStyle::DoGetTextDecorationColor()
  3197   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3199   nscolor color;
  3200   bool isForeground;
  3201   StyleTextReset()->GetDecorationColor(color, isForeground);
  3202   if (isForeground) {
  3203     color = StyleColor()->mColor;
  3206   SetToRGBAColor(val, color);
  3208   return val;
  3211 CSSValue*
  3212 nsComputedDOMStyle::DoGetTextDecorationLine()
  3214   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3216   int32_t intValue = StyleTextReset()->mTextDecorationLine;
  3218   if (NS_STYLE_TEXT_DECORATION_LINE_NONE == intValue) {
  3219     val->SetIdent(eCSSKeyword_none);
  3220   } else {
  3221     nsAutoString decorationLineString;
  3222     // Clear the -moz-anchor-decoration bit and the OVERRIDE_ALL bits -- we
  3223     // don't want these to appear in the computed style.
  3224     intValue &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS |
  3225                   NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL);
  3226     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
  3227       intValue, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
  3228       NS_STYLE_TEXT_DECORATION_LINE_BLINK, decorationLineString);
  3229     val->SetString(decorationLineString);
  3232   return val;
  3235 CSSValue*
  3236 nsComputedDOMStyle::DoGetTextDecorationStyle()
  3238   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3240   val->SetIdent(
  3241     nsCSSProps::ValueToKeywordEnum(StyleTextReset()->GetDecorationStyle(),
  3242                                    nsCSSProps::kTextDecorationStyleKTable));
  3244   return val;
  3247 CSSValue*
  3248 nsComputedDOMStyle::DoGetTextIndent()
  3250   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3251   SetValueToCoord(val, StyleText()->mTextIndent, false,
  3252                   &nsComputedDOMStyle::GetCBContentWidth);
  3253   return val;
  3256 CSSValue*
  3257 nsComputedDOMStyle::DoGetTextOrientation()
  3259   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3260   val->SetIdent(
  3261     nsCSSProps::ValueToKeywordEnum(StyleText()->mTextOrientation,
  3262                                    nsCSSProps::kTextOrientationKTable));
  3263   return val;
  3266 CSSValue*
  3267 nsComputedDOMStyle::DoGetTextOverflow()
  3269   const nsStyleTextReset *style = StyleTextReset();
  3270   nsROCSSPrimitiveValue *first = new nsROCSSPrimitiveValue;
  3271   const nsStyleTextOverflowSide *side = style->mTextOverflow.GetFirstValue();
  3272   if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
  3273     nsString str;
  3274     nsStyleUtil::AppendEscapedCSSString(side->mString, str);
  3275     first->SetString(str);
  3276   } else {
  3277     first->SetIdent(
  3278       nsCSSProps::ValueToKeywordEnum(side->mType,
  3279                                      nsCSSProps::kTextOverflowKTable));
  3281   side = style->mTextOverflow.GetSecondValue();
  3282   if (!side) {
  3283     return first;
  3285   nsROCSSPrimitiveValue *second = new nsROCSSPrimitiveValue;
  3286   if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
  3287     nsString str;
  3288     nsStyleUtil::AppendEscapedCSSString(side->mString, str);
  3289     second->SetString(str);
  3290   } else {
  3291     second->SetIdent(
  3292       nsCSSProps::ValueToKeywordEnum(side->mType,
  3293                                      nsCSSProps::kTextOverflowKTable));
  3296   nsDOMCSSValueList *valueList = GetROCSSValueList(false);
  3297   valueList->AppendCSSValue(first);
  3298   valueList->AppendCSSValue(second);
  3299   return valueList;
  3302 CSSValue*
  3303 nsComputedDOMStyle::DoGetTextShadow()
  3305   return GetCSSShadowArray(StyleText()->mTextShadow,
  3306                            StyleColor()->mColor,
  3307                            false);
  3310 CSSValue*
  3311 nsComputedDOMStyle::DoGetTextTransform()
  3313   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3314   val->SetIdent(
  3315     nsCSSProps::ValueToKeywordEnum(StyleText()->mTextTransform,
  3316                                    nsCSSProps::kTextTransformKTable));
  3317   return val;
  3320 CSSValue*
  3321 nsComputedDOMStyle::DoGetTabSize()
  3323   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3324   val->SetNumber(StyleText()->mTabSize);
  3325   return val;
  3328 CSSValue*
  3329 nsComputedDOMStyle::DoGetLetterSpacing()
  3331   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3332   SetValueToCoord(val, StyleText()->mLetterSpacing, false);
  3333   return val;
  3336 CSSValue*
  3337 nsComputedDOMStyle::DoGetWordSpacing()
  3339   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3340   val->SetAppUnits(StyleText()->mWordSpacing);
  3341   return val;
  3344 CSSValue*
  3345 nsComputedDOMStyle::DoGetWhiteSpace()
  3347   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3348   val->SetIdent(
  3349     nsCSSProps::ValueToKeywordEnum(StyleText()->mWhiteSpace,
  3350                                    nsCSSProps::kWhitespaceKTable));
  3351   return val;
  3354 CSSValue*
  3355 nsComputedDOMStyle::DoGetWindowShadow()
  3357   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3358   val->SetIdent(
  3359     nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mWindowShadow,
  3360                                    nsCSSProps::kWindowShadowKTable));
  3361   return val;
  3364 CSSValue*
  3365 nsComputedDOMStyle::DoGetWordBreak()
  3367   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3368   val->SetIdent(
  3369     nsCSSProps::ValueToKeywordEnum(StyleText()->mWordBreak,
  3370                                    nsCSSProps::kWordBreakKTable));
  3371   return val;
  3374 CSSValue*
  3375 nsComputedDOMStyle::DoGetWordWrap()
  3377   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3378   val->SetIdent(
  3379     nsCSSProps::ValueToKeywordEnum(StyleText()->mWordWrap,
  3380                                    nsCSSProps::kWordWrapKTable));
  3381   return val;
  3384 CSSValue*
  3385 nsComputedDOMStyle::DoGetHyphens()
  3387   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3388   val->SetIdent(
  3389     nsCSSProps::ValueToKeywordEnum(StyleText()->mHyphens,
  3390                                    nsCSSProps::kHyphensKTable));
  3391   return val;
  3394 CSSValue*
  3395 nsComputedDOMStyle::DoGetTextSizeAdjust()
  3397   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3398   switch (StyleText()->mTextSizeAdjust) {
  3399     default:
  3400       NS_NOTREACHED("unexpected value");
  3401       // fall through
  3402     case NS_STYLE_TEXT_SIZE_ADJUST_AUTO:
  3403       val->SetIdent(eCSSKeyword_auto);
  3404       break;
  3405     case NS_STYLE_TEXT_SIZE_ADJUST_NONE:
  3406       val->SetIdent(eCSSKeyword_none);
  3407       break;
  3409   return val;
  3412 CSSValue*
  3413 nsComputedDOMStyle::DoGetPointerEvents()
  3415   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3416   val->SetIdent(
  3417     nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mPointerEvents,
  3418                                    nsCSSProps::kPointerEventsKTable));
  3419   return val;
  3422 CSSValue*
  3423 nsComputedDOMStyle::DoGetVisibility()
  3425   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3426   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mVisible,
  3427                                                nsCSSProps::kVisibilityKTable));
  3428   return val;
  3431 CSSValue*
  3432 nsComputedDOMStyle::DoGetWritingMode()
  3434   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3435   val->SetIdent(
  3436     nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mWritingMode,
  3437                                    nsCSSProps::kWritingModeKTable));
  3438   return val;
  3441 CSSValue*
  3442 nsComputedDOMStyle::DoGetDirection()
  3444   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3445   val->SetIdent(
  3446     nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mDirection,
  3447                                    nsCSSProps::kDirectionKTable));
  3448   return val;
  3451 static_assert(NS_STYLE_UNICODE_BIDI_NORMAL == 0,
  3452               "unicode-bidi style constants not as expected");
  3454 CSSValue*
  3455 nsComputedDOMStyle::DoGetUnicodeBidi()
  3457   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3458   val->SetIdent(
  3459     nsCSSProps::ValueToKeywordEnum(StyleTextReset()->mUnicodeBidi,
  3460                                    nsCSSProps::kUnicodeBidiKTable));
  3461   return val;
  3464 CSSValue*
  3465 nsComputedDOMStyle::DoGetCursor()
  3467   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  3469   const nsStyleUserInterface *ui = StyleUserInterface();
  3471   for (nsCursorImage *item = ui->mCursorArray,
  3472          *item_end = ui->mCursorArray + ui->mCursorArrayLength;
  3473        item < item_end; ++item) {
  3474     nsDOMCSSValueList *itemList = GetROCSSValueList(false);
  3475     valueList->AppendCSSValue(itemList);
  3477     nsCOMPtr<nsIURI> uri;
  3478     item->GetImage()->GetURI(getter_AddRefs(uri));
  3480     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3481     itemList->AppendCSSValue(val);
  3482     val->SetURI(uri);
  3484     if (item->mHaveHotspot) {
  3485       nsROCSSPrimitiveValue *valX = new nsROCSSPrimitiveValue;
  3486       itemList->AppendCSSValue(valX);
  3487       nsROCSSPrimitiveValue *valY = new nsROCSSPrimitiveValue;
  3488       itemList->AppendCSSValue(valY);
  3490       valX->SetNumber(item->mHotspotX);
  3491       valY->SetNumber(item->mHotspotY);
  3495   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3496   val->SetIdent(nsCSSProps::ValueToKeywordEnum(ui->mCursor,
  3497                                                nsCSSProps::kCursorKTable));
  3498   valueList->AppendCSSValue(val);
  3499   return valueList;
  3502 CSSValue*
  3503 nsComputedDOMStyle::DoGetAppearance()
  3505   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3506   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mAppearance,
  3507                                                nsCSSProps::kAppearanceKTable));
  3508   return val;
  3512 CSSValue*
  3513 nsComputedDOMStyle::DoGetBoxAlign()
  3515   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3516   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxAlign,
  3517                                                nsCSSProps::kBoxAlignKTable));
  3518   return val;
  3521 CSSValue*
  3522 nsComputedDOMStyle::DoGetBoxDirection()
  3524   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3525   val->SetIdent(
  3526     nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxDirection,
  3527                                    nsCSSProps::kBoxDirectionKTable));
  3528   return val;
  3531 CSSValue*
  3532 nsComputedDOMStyle::DoGetBoxFlex()
  3534   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3535   val->SetNumber(StyleXUL()->mBoxFlex);
  3536   return val;
  3539 CSSValue*
  3540 nsComputedDOMStyle::DoGetBoxOrdinalGroup()
  3542   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3543   val->SetNumber(StyleXUL()->mBoxOrdinal);
  3544   return val;
  3547 CSSValue*
  3548 nsComputedDOMStyle::DoGetBoxOrient()
  3550   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3551   val->SetIdent(
  3552     nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxOrient,
  3553                                    nsCSSProps::kBoxOrientKTable));
  3554   return val;
  3557 CSSValue*
  3558 nsComputedDOMStyle::DoGetBoxPack()
  3560   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3561   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxPack,
  3562                                                nsCSSProps::kBoxPackKTable));
  3563   return val;
  3566 CSSValue*
  3567 nsComputedDOMStyle::DoGetBoxSizing()
  3569   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3570   val->SetIdent(
  3571     nsCSSProps::ValueToKeywordEnum(StylePosition()->mBoxSizing,
  3572                                    nsCSSProps::kBoxSizingKTable));
  3573   return val;
  3576 /* Border image properties */
  3578 CSSValue*
  3579 nsComputedDOMStyle::DoGetBorderImageSource()
  3581   const nsStyleBorder* border = StyleBorder();
  3583   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3584   const nsStyleImage& image = border->mBorderImageSource;
  3585   SetValueToStyleImage(image, val);
  3587   return val;
  3590 CSSValue*
  3591 nsComputedDOMStyle::DoGetBorderImageSlice()
  3593   nsDOMCSSValueList* valueList = GetROCSSValueList(false);
  3595   const nsStyleBorder* border = StyleBorder();
  3596   // Four slice numbers.
  3597   NS_FOR_CSS_SIDES (side) {
  3598     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3599     valueList->AppendCSSValue(val);
  3600     SetValueToCoord(val, border->mBorderImageSlice.Get(side), true, nullptr);
  3603   // Fill keyword.
  3604   if (NS_STYLE_BORDER_IMAGE_SLICE_FILL == border->mBorderImageFill) {
  3605     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3606     valueList->AppendCSSValue(val);
  3607     val->SetIdent(eCSSKeyword_fill);
  3610   return valueList;
  3613 CSSValue*
  3614 nsComputedDOMStyle::DoGetBorderImageWidth()
  3616   const nsStyleBorder* border = StyleBorder();
  3617   nsDOMCSSValueList* valueList = GetROCSSValueList(false);
  3618   NS_FOR_CSS_SIDES (side) {
  3619     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3620     valueList->AppendCSSValue(val);
  3621     SetValueToCoord(val, border->mBorderImageWidth.Get(side),
  3622                     true, nullptr);
  3625   return valueList;
  3628 CSSValue*
  3629 nsComputedDOMStyle::DoGetBorderImageOutset()
  3631   nsDOMCSSValueList *valueList = GetROCSSValueList(false);
  3633   const nsStyleBorder* border = StyleBorder();
  3634   // four slice numbers
  3635   NS_FOR_CSS_SIDES (side) {
  3636     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3637     valueList->AppendCSSValue(val);
  3638     SetValueToCoord(val, border->mBorderImageOutset.Get(side),
  3639                     true, nullptr);
  3642   return valueList;
  3645 CSSValue*
  3646 nsComputedDOMStyle::DoGetBorderImageRepeat()
  3648   nsDOMCSSValueList* valueList = GetROCSSValueList(false);
  3650   const nsStyleBorder* border = StyleBorder();
  3652   // horizontal repeat
  3653   nsROCSSPrimitiveValue* valX = new nsROCSSPrimitiveValue;
  3654   valueList->AppendCSSValue(valX);
  3655   valX->SetIdent(
  3656     nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatH,
  3657                                    nsCSSProps::kBorderImageRepeatKTable));
  3659   // vertical repeat
  3660   nsROCSSPrimitiveValue* valY = new nsROCSSPrimitiveValue;
  3661   valueList->AppendCSSValue(valY);
  3662   valY->SetIdent(
  3663     nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatV,
  3664                                    nsCSSProps::kBorderImageRepeatKTable));
  3665   return valueList;
  3668 CSSValue*
  3669 nsComputedDOMStyle::DoGetAlignContent()
  3671   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3672   val->SetIdent(
  3673     nsCSSProps::ValueToKeywordEnum(StylePosition()->mAlignContent,
  3674                                    nsCSSProps::kAlignContentKTable));
  3675   return val;
  3678 CSSValue*
  3679 nsComputedDOMStyle::DoGetAlignItems()
  3681   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3682   val->SetIdent(
  3683     nsCSSProps::ValueToKeywordEnum(StylePosition()->mAlignItems,
  3684                                    nsCSSProps::kAlignItemsKTable));
  3685   return val;
  3688 CSSValue*
  3689 nsComputedDOMStyle::DoGetAlignSelf()
  3691   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3692   uint8_t computedAlignSelf = StylePosition()->mAlignSelf;
  3694   if (computedAlignSelf == NS_STYLE_ALIGN_SELF_AUTO) {
  3695     // "align-self: auto" needs to compute to parent's align-items value.
  3696     nsStyleContext* parentStyleContext = mStyleContextHolder->GetParent();
  3697     if (parentStyleContext) {
  3698       computedAlignSelf =
  3699         parentStyleContext->StylePosition()->mAlignItems;
  3700     } else {
  3701       // No parent --> use default.
  3702       computedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
  3706   NS_ABORT_IF_FALSE(computedAlignSelf != NS_STYLE_ALIGN_SELF_AUTO,
  3707                     "Should have swapped out 'auto' for something non-auto");
  3708   val->SetIdent(
  3709     nsCSSProps::ValueToKeywordEnum(computedAlignSelf,
  3710                                    nsCSSProps::kAlignSelfKTable));
  3711   return val;
  3714 CSSValue*
  3715 nsComputedDOMStyle::DoGetFlexBasis()
  3717   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3719   // XXXdholbert We could make this more automagic and resolve percentages
  3720   // if we wanted, by passing in a PercentageBaseGetter instead of nullptr
  3721   // below.  Logic would go like this:
  3722   //   if (i'm a flex item) {
  3723   //     if (my flex container is horizontal) {
  3724   //       percentageBaseGetter = &nsComputedDOMStyle::GetCBContentWidth;
  3725   //     } else {
  3726   //       percentageBaseGetter = &nsComputedDOMStyle::GetCBContentHeight;
  3727   //     }
  3728   //   }
  3730   SetValueToCoord(val, StylePosition()->mFlexBasis, true,
  3731                   nullptr, nsCSSProps::kWidthKTable);
  3732   return val;
  3735 CSSValue*
  3736 nsComputedDOMStyle::DoGetFlexDirection()
  3738   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3739   val->SetIdent(
  3740     nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexDirection,
  3741                                    nsCSSProps::kFlexDirectionKTable));
  3742   return val;
  3745 CSSValue*
  3746 nsComputedDOMStyle::DoGetFlexGrow()
  3748   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3749   val->SetNumber(StylePosition()->mFlexGrow);
  3750   return val;
  3753 CSSValue*
  3754 nsComputedDOMStyle::DoGetFlexShrink()
  3756   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3757   val->SetNumber(StylePosition()->mFlexShrink);
  3758   return val;
  3761 CSSValue*
  3762 nsComputedDOMStyle::DoGetFlexWrap()
  3764   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3765   val->SetIdent(
  3766     nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexWrap,
  3767                                    nsCSSProps::kFlexWrapKTable));
  3768   return val;
  3771 CSSValue*
  3772 nsComputedDOMStyle::DoGetOrder()
  3774   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3775   val->SetNumber(StylePosition()->mOrder);
  3776   return val;
  3779 CSSValue*
  3780 nsComputedDOMStyle::DoGetJustifyContent()
  3782   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3783   val->SetIdent(
  3784     nsCSSProps::ValueToKeywordEnum(StylePosition()->mJustifyContent,
  3785                                    nsCSSProps::kJustifyContentKTable));
  3786   return val;
  3789 CSSValue*
  3790 nsComputedDOMStyle::DoGetFloatEdge()
  3792   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3793   val->SetIdent(
  3794     nsCSSProps::ValueToKeywordEnum(StyleBorder()->mFloatEdge,
  3795                                    nsCSSProps::kFloatEdgeKTable));
  3796   return val;
  3799 CSSValue*
  3800 nsComputedDOMStyle::DoGetForceBrokenImageIcon()
  3802   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3803   val->SetNumber(StyleUIReset()->mForceBrokenImageIcon);
  3804   return val;
  3807 CSSValue*
  3808 nsComputedDOMStyle::DoGetImageOrientation()
  3810   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3811   nsAutoString string;
  3812   nsStyleImageOrientation orientation = StyleVisibility()->mImageOrientation;
  3814   if (orientation.IsFromImage()) {
  3815     string.AppendLiteral("from-image");
  3816   } else {
  3817     nsStyleUtil::AppendAngleValue(orientation.AngleAsCoord(), string);
  3819     if (orientation.IsFlipped()) {
  3820       string.AppendLiteral(" flip");
  3824   val->SetString(string);
  3825   return val;
  3828 CSSValue*
  3829 nsComputedDOMStyle::DoGetIMEMode()
  3831   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3832   val->SetIdent(
  3833     nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mIMEMode,
  3834                                    nsCSSProps::kIMEModeKTable));
  3835   return val;
  3838 CSSValue*
  3839 nsComputedDOMStyle::DoGetUserFocus()
  3841   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3842   val->SetIdent(
  3843     nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserFocus,
  3844                                    nsCSSProps::kUserFocusKTable));
  3845   return val;
  3848 CSSValue*
  3849 nsComputedDOMStyle::DoGetUserInput()
  3851   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3852   val->SetIdent(
  3853     nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserInput,
  3854                                    nsCSSProps::kUserInputKTable));
  3855   return val;
  3858 CSSValue*
  3859 nsComputedDOMStyle::DoGetUserModify()
  3861   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3862   val->SetIdent(
  3863     nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserModify,
  3864                                    nsCSSProps::kUserModifyKTable));
  3865   return val;
  3868 CSSValue*
  3869 nsComputedDOMStyle::DoGetUserSelect()
  3871   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3872   val->SetIdent(
  3873     nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mUserSelect,
  3874                                    nsCSSProps::kUserSelectKTable));
  3875   return val;
  3878 CSSValue*
  3879 nsComputedDOMStyle::DoGetDisplay()
  3881   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3882   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mDisplay,
  3883                                                nsCSSProps::kDisplayKTable));
  3884   return val;
  3887 CSSValue*
  3888 nsComputedDOMStyle::DoGetPosition()
  3890   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3891   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mPosition,
  3892                                                nsCSSProps::kPositionKTable));
  3893   return val;
  3896 CSSValue*
  3897 nsComputedDOMStyle::DoGetClip()
  3899   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3901   const nsStyleDisplay* display = StyleDisplay();
  3903   if (display->mClipFlags == NS_STYLE_CLIP_AUTO) {
  3904     val->SetIdent(eCSSKeyword_auto);
  3905   } else {
  3906     // create the cssvalues for the sides, stick them in the rect object
  3907     nsROCSSPrimitiveValue *topVal    = new nsROCSSPrimitiveValue;
  3908     nsROCSSPrimitiveValue *rightVal  = new nsROCSSPrimitiveValue;
  3909     nsROCSSPrimitiveValue *bottomVal = new nsROCSSPrimitiveValue;
  3910     nsROCSSPrimitiveValue *leftVal   = new nsROCSSPrimitiveValue;
  3911     nsDOMCSSRect * domRect = new nsDOMCSSRect(topVal, rightVal,
  3912                                               bottomVal, leftVal);
  3913     if (display->mClipFlags & NS_STYLE_CLIP_TOP_AUTO) {
  3914       topVal->SetIdent(eCSSKeyword_auto);
  3915     } else {
  3916       topVal->SetAppUnits(display->mClip.y);
  3919     if (display->mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO) {
  3920       rightVal->SetIdent(eCSSKeyword_auto);
  3921     } else {
  3922       rightVal->SetAppUnits(display->mClip.width + display->mClip.x);
  3925     if (display->mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO) {
  3926       bottomVal->SetIdent(eCSSKeyword_auto);
  3927     } else {
  3928       bottomVal->SetAppUnits(display->mClip.height + display->mClip.y);
  3931     if (display->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) {
  3932       leftVal->SetIdent(eCSSKeyword_auto);
  3933     } else {
  3934       leftVal->SetAppUnits(display->mClip.x);
  3936     val->SetRect(domRect);
  3939   return val;
  3942 CSSValue*
  3943 nsComputedDOMStyle::DoGetWillChange()
  3945   const nsTArray<nsString>& willChange = StyleDisplay()->mWillChange;
  3947   if (willChange.IsEmpty()) {
  3948     nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  3949     val->SetIdent(eCSSKeyword_auto);
  3950     return val;
  3953   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  3954   for (size_t i = 0; i < willChange.Length(); i++) {
  3955     const nsString& willChangeIdentifier = willChange[i];
  3956     nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue;
  3957     valueList->AppendCSSValue(property);
  3958     property->SetString(willChangeIdentifier);
  3961   return valueList;
  3964 CSSValue*
  3965 nsComputedDOMStyle::DoGetOverflow()
  3967   const nsStyleDisplay* display = StyleDisplay();
  3969   if (display->mOverflowX != display->mOverflowY) {
  3970     // No value to return.  We can't express this combination of
  3971     // values as a shorthand.
  3972     return nullptr;
  3975   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3976   val->SetIdent(nsCSSProps::ValueToKeywordEnum(display->mOverflowX,
  3977                                                nsCSSProps::kOverflowKTable));
  3978   return val;
  3981 CSSValue*
  3982 nsComputedDOMStyle::DoGetOverflowX()
  3984   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3985   val->SetIdent(
  3986     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowX,
  3987                                    nsCSSProps::kOverflowSubKTable));
  3988   return val;
  3991 CSSValue*
  3992 nsComputedDOMStyle::DoGetOverflowY()
  3994   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  3995   val->SetIdent(
  3996     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowY,
  3997                                    nsCSSProps::kOverflowSubKTable));
  3998   return val;
  4001 CSSValue*
  4002 nsComputedDOMStyle::DoGetOverflowClipBox()
  4004   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4005   val->SetIdent(
  4006     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBox,
  4007                                    nsCSSProps::kOverflowClipBoxKTable));
  4008   return val;
  4011 CSSValue*
  4012 nsComputedDOMStyle::DoGetResize()
  4014   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4015   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mResize,
  4016                                                nsCSSProps::kResizeKTable));
  4017   return val;
  4021 CSSValue*
  4022 nsComputedDOMStyle::DoGetPageBreakAfter()
  4024   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4026   const nsStyleDisplay *display = StyleDisplay();
  4028   if (display->mBreakAfter) {
  4029     val->SetIdent(eCSSKeyword_always);
  4030   } else {
  4031     val->SetIdent(eCSSKeyword_auto);
  4034   return val;
  4037 CSSValue*
  4038 nsComputedDOMStyle::DoGetPageBreakBefore()
  4040   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4042   const nsStyleDisplay *display = StyleDisplay();
  4044   if (display->mBreakBefore) {
  4045     val->SetIdent(eCSSKeyword_always);
  4046   } else {
  4047     val->SetIdent(eCSSKeyword_auto);
  4050   return val;
  4053 CSSValue*
  4054 nsComputedDOMStyle::DoGetPageBreakInside()
  4056   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4057   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakInside,
  4058                                                nsCSSProps::kPageBreakInsideKTable));
  4059   return val;
  4062 CSSValue*
  4063 nsComputedDOMStyle::DoGetTouchAction()
  4065   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4067   int32_t intValue = StyleDisplay()->mTouchAction;
  4069   // None and Auto and Manipulation values aren't allowed
  4070   // to be in conjunction with other values.
  4071   // But there are all checks in CSSParserImpl::ParseTouchAction
  4072   nsAutoString valueStr;
  4073   nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_touch_action, intValue,
  4074     NS_STYLE_TOUCH_ACTION_NONE, NS_STYLE_TOUCH_ACTION_MANIPULATION,
  4075     valueStr);
  4076   val->SetString(valueStr);
  4077   return val;
  4080 CSSValue*
  4081 nsComputedDOMStyle::DoGetHeight()
  4083   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4085   bool calcHeight = false;
  4087   if (mInnerFrame) {
  4088     calcHeight = true;
  4090     const nsStyleDisplay* displayData = StyleDisplay();
  4091     if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
  4092         !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
  4093         // An outer SVG frame should behave the same as eReplaced in this case
  4094         mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) {
  4096       calcHeight = false;
  4100   if (calcHeight) {
  4101     AssertFlushedPendingReflows();
  4102     nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
  4103     val->SetAppUnits(mInnerFrame->GetContentRect().height +
  4104       adjustedValues.TopBottom());
  4105   } else {
  4106     const nsStylePosition *positionData = StylePosition();
  4108     nscoord minHeight =
  4109       StyleCoordToNSCoord(positionData->mMinHeight,
  4110                           &nsComputedDOMStyle::GetCBContentHeight, 0, true);
  4112     nscoord maxHeight =
  4113       StyleCoordToNSCoord(positionData->mMaxHeight,
  4114                           &nsComputedDOMStyle::GetCBContentHeight,
  4115                           nscoord_MAX, true);
  4117     SetValueToCoord(val, positionData->mHeight, true, nullptr, nullptr,
  4118                     minHeight, maxHeight);
  4121   return val;
  4124 CSSValue*
  4125 nsComputedDOMStyle::DoGetWidth()
  4127   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4129   bool calcWidth = false;
  4131   if (mInnerFrame) {
  4132     calcWidth = true;
  4134     const nsStyleDisplay *displayData = StyleDisplay();
  4135     if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
  4136         !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
  4137         // An outer SVG frame should behave the same as eReplaced in this case
  4138         mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) {
  4140       calcWidth = false;
  4144   if (calcWidth) {
  4145     AssertFlushedPendingReflows();
  4146     nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
  4147     val->SetAppUnits(mInnerFrame->GetContentRect().width +
  4148       adjustedValues.LeftRight());
  4149   } else {
  4150     const nsStylePosition *positionData = StylePosition();
  4152     nscoord minWidth =
  4153       StyleCoordToNSCoord(positionData->mMinWidth,
  4154                           &nsComputedDOMStyle::GetCBContentWidth, 0, true);
  4156     nscoord maxWidth =
  4157       StyleCoordToNSCoord(positionData->mMaxWidth,
  4158                           &nsComputedDOMStyle::GetCBContentWidth,
  4159                           nscoord_MAX, true);
  4161     SetValueToCoord(val, positionData->mWidth, true, nullptr,
  4162                     nsCSSProps::kWidthKTable, minWidth, maxWidth);
  4165   return val;
  4168 CSSValue*
  4169 nsComputedDOMStyle::DoGetMaxHeight()
  4171   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4172   SetValueToCoord(val, StylePosition()->mMaxHeight, true,
  4173                   &nsComputedDOMStyle::GetCBContentHeight);
  4174   return val;
  4177 CSSValue*
  4178 nsComputedDOMStyle::DoGetMaxWidth()
  4180   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4181   SetValueToCoord(val, StylePosition()->mMaxWidth, true,
  4182                   &nsComputedDOMStyle::GetCBContentWidth,
  4183                   nsCSSProps::kWidthKTable);
  4184   return val;
  4187 CSSValue*
  4188 nsComputedDOMStyle::DoGetMinHeight()
  4190   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4191   SetValueToCoord(val, StylePosition()->mMinHeight, true,
  4192                   &nsComputedDOMStyle::GetCBContentHeight);
  4193   return val;
  4196 CSSValue*
  4197 nsComputedDOMStyle::DoGetMinWidth()
  4199   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4200   SetValueToCoord(val, StylePosition()->mMinWidth, true,
  4201                   &nsComputedDOMStyle::GetCBContentWidth,
  4202                   nsCSSProps::kWidthKTable);
  4203   return val;
  4206 CSSValue*
  4207 nsComputedDOMStyle::DoGetMixBlendMode()
  4209     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4210     val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mMixBlendMode,
  4211                   nsCSSProps::kBlendModeKTable));
  4212     return val;
  4215 CSSValue*
  4216 nsComputedDOMStyle::DoGetLeft()
  4218   return GetOffsetWidthFor(NS_SIDE_LEFT);
  4221 CSSValue*
  4222 nsComputedDOMStyle::DoGetRight()
  4224   return GetOffsetWidthFor(NS_SIDE_RIGHT);
  4227 CSSValue*
  4228 nsComputedDOMStyle::DoGetTop()
  4230   return GetOffsetWidthFor(NS_SIDE_TOP);
  4233 nsDOMCSSValueList*
  4234 nsComputedDOMStyle::GetROCSSValueList(bool aCommaDelimited)
  4236   nsDOMCSSValueList *valueList = new nsDOMCSSValueList(aCommaDelimited, true);
  4237   NS_ASSERTION(valueList != 0, "ran out of memory");
  4239   return valueList;
  4242 CSSValue*
  4243 nsComputedDOMStyle::GetOffsetWidthFor(mozilla::css::Side aSide)
  4245   const nsStyleDisplay* display = StyleDisplay();
  4247   AssertFlushedPendingReflows();
  4249   uint8_t position = display->mPosition;
  4250   if (!mOuterFrame) {
  4251     // GetRelativeOffset and GetAbsoluteOffset don't handle elements
  4252     // without frames in any sensible way.  GetStaticOffset, however,
  4253     // is perfect for that case.
  4254     position = NS_STYLE_POSITION_STATIC;
  4257   switch (position) {
  4258     case NS_STYLE_POSITION_STATIC:
  4259       return GetStaticOffset(aSide);
  4260     case NS_STYLE_POSITION_RELATIVE:
  4261       return GetRelativeOffset(aSide);
  4262     case NS_STYLE_POSITION_STICKY:
  4263       return GetStickyOffset(aSide);
  4264     case NS_STYLE_POSITION_ABSOLUTE:
  4265     case NS_STYLE_POSITION_FIXED:
  4266       return GetAbsoluteOffset(aSide);
  4267     default:
  4268       NS_ERROR("Invalid position");
  4269       return nullptr;
  4273 CSSValue*
  4274 nsComputedDOMStyle::GetAbsoluteOffset(mozilla::css::Side aSide)
  4276   MOZ_ASSERT(mOuterFrame, "need a frame, so we can call GetContainingBlock()");
  4278   nsIFrame* container = mOuterFrame->GetContainingBlock();
  4279   nsMargin margin = mOuterFrame->GetUsedMargin();
  4280   nsMargin border = container->GetUsedBorder();
  4281   nsMargin scrollbarSizes(0, 0, 0, 0);
  4282   nsRect rect = mOuterFrame->GetRect();
  4283   nsRect containerRect = container->GetRect();
  4285   if (container->GetType() == nsGkAtoms::viewportFrame) {
  4286     // For absolutely positioned frames scrollbars are taken into
  4287     // account by virtue of getting a containing block that does
  4288     // _not_ include the scrollbars.  For fixed positioned frames,
  4289     // the containing block is the viewport, which _does_ include
  4290     // scrollbars.  We have to do some extra work.
  4291     // the first child in the default frame list is what we want
  4292     nsIFrame* scrollingChild = container->GetFirstPrincipalChild();
  4293     nsIScrollableFrame *scrollFrame = do_QueryFrame(scrollingChild);
  4294     if (scrollFrame) {
  4295       scrollbarSizes = scrollFrame->GetActualScrollbarSizes();
  4299   nscoord offset = 0;
  4300   switch (aSide) {
  4301     case NS_SIDE_TOP:
  4302       offset = rect.y - margin.top - border.top - scrollbarSizes.top;
  4304       break;
  4305     case NS_SIDE_RIGHT:
  4306       offset = containerRect.width - rect.width -
  4307         rect.x - margin.right - border.right - scrollbarSizes.right;
  4309       break;
  4310     case NS_SIDE_BOTTOM:
  4311       offset = containerRect.height - rect.height -
  4312         rect.y - margin.bottom - border.bottom - scrollbarSizes.bottom;
  4314       break;
  4315     case NS_SIDE_LEFT:
  4316       offset = rect.x - margin.left - border.left - scrollbarSizes.left;
  4318       break;
  4319     default:
  4320       NS_ERROR("Invalid side");
  4321       break;
  4324   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4325   val->SetAppUnits(offset);
  4326   return val;
  4329 static_assert(NS_SIDE_TOP == 0 && NS_SIDE_RIGHT == 1 &&
  4330               NS_SIDE_BOTTOM == 2 && NS_SIDE_LEFT == 3,
  4331               "box side constants not as expected for NS_OPPOSITE_SIDE");
  4332 #define NS_OPPOSITE_SIDE(s_) mozilla::css::Side(((s_) + 2) & 3)
  4334 CSSValue*
  4335 nsComputedDOMStyle::GetRelativeOffset(mozilla::css::Side aSide)
  4337   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4339   const nsStylePosition* positionData = StylePosition();
  4340   int32_t sign = 1;
  4341   nsStyleCoord coord = positionData->mOffset.Get(aSide);
  4343   NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
  4344                coord.GetUnit() == eStyleUnit_Percent ||
  4345                coord.GetUnit() == eStyleUnit_Auto ||
  4346                coord.IsCalcUnit(),
  4347                "Unexpected unit");
  4349   if (coord.GetUnit() == eStyleUnit_Auto) {
  4350     coord = positionData->mOffset.Get(NS_OPPOSITE_SIDE(aSide));
  4351     sign = -1;
  4353   PercentageBaseGetter baseGetter;
  4354   if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) {
  4355     baseGetter = &nsComputedDOMStyle::GetCBContentWidth;
  4356   } else {
  4357     baseGetter = &nsComputedDOMStyle::GetCBContentHeight;
  4360   val->SetAppUnits(sign * StyleCoordToNSCoord(coord, baseGetter, 0, false));
  4361   return val;
  4364 CSSValue*
  4365 nsComputedDOMStyle::GetStickyOffset(mozilla::css::Side aSide)
  4367   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4369   const nsStylePosition* positionData = StylePosition();
  4370   nsStyleCoord coord = positionData->mOffset.Get(aSide);
  4372   NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
  4373                coord.GetUnit() == eStyleUnit_Percent ||
  4374                coord.GetUnit() == eStyleUnit_Auto ||
  4375                coord.IsCalcUnit(),
  4376                "Unexpected unit");
  4378   if (coord.GetUnit() == eStyleUnit_Auto) {
  4379     val->SetIdent(eCSSKeyword_auto);
  4380     return val;
  4382   PercentageBaseGetter baseGetter;
  4383   if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) {
  4384     baseGetter = &nsComputedDOMStyle::GetScrollFrameContentWidth;
  4385   } else {
  4386     baseGetter = &nsComputedDOMStyle::GetScrollFrameContentHeight;
  4389   val->SetAppUnits(StyleCoordToNSCoord(coord, baseGetter, 0, false));
  4390   return val;
  4394 CSSValue*
  4395 nsComputedDOMStyle::GetStaticOffset(mozilla::css::Side aSide)
  4398   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4399   SetValueToCoord(val, StylePosition()->mOffset.Get(aSide), false);
  4400   return val;
  4403 CSSValue*
  4404 nsComputedDOMStyle::GetPaddingWidthFor(mozilla::css::Side aSide)
  4406   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4408   if (!mInnerFrame) {
  4409     SetValueToCoord(val, StylePadding()->mPadding.Get(aSide), true);
  4410   } else {
  4411     AssertFlushedPendingReflows();
  4413     val->SetAppUnits(mInnerFrame->GetUsedPadding().Side(aSide));
  4416   return val;
  4419 bool
  4420 nsComputedDOMStyle::GetLineHeightCoord(nscoord& aCoord)
  4422   AssertFlushedPendingReflows();
  4424   nscoord blockHeight = NS_AUTOHEIGHT;
  4425   if (StyleText()->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
  4426     if (!mInnerFrame)
  4427       return false;
  4429     if (nsLayoutUtils::IsNonWrapperBlock(mInnerFrame)) {
  4430       blockHeight = mInnerFrame->GetContentRect().height;
  4431     } else {
  4432       GetCBContentHeight(blockHeight);
  4436   // lie about font size inflation since we lie about font size (since
  4437   // the inflation only applies to text)
  4438   aCoord = nsHTMLReflowState::CalcLineHeight(mContent, mStyleContextHolder,
  4439                                              blockHeight, 1.0f);
  4441   // CalcLineHeight uses font->mFont.size, but we want to use
  4442   // font->mSize as the font size.  Adjust for that.  Also adjust for
  4443   // the text zoom, if any.
  4444   const nsStyleFont* font = StyleFont();
  4445   float fCoord = float(aCoord);
  4446   if (font->mAllowZoom) {
  4447     fCoord /= mPresShell->GetPresContext()->TextZoom();
  4449   if (font->mFont.size != font->mSize) {
  4450     fCoord = fCoord * (float(font->mSize) / float(font->mFont.size));
  4452   aCoord = NSToCoordRound(fCoord);
  4454   return true;
  4457 CSSValue*
  4458 nsComputedDOMStyle::GetBorderColorsFor(mozilla::css::Side aSide)
  4460   const nsStyleBorder *border = StyleBorder();
  4462   if (border->mBorderColors) {
  4463     nsBorderColors* borderColors = border->mBorderColors[aSide];
  4464     if (borderColors) {
  4465       nsDOMCSSValueList *valueList = GetROCSSValueList(false);
  4467       do {
  4468         nsROCSSPrimitiveValue *primitive = new nsROCSSPrimitiveValue;
  4470         SetToRGBAColor(primitive, borderColors->mColor);
  4472         valueList->AppendCSSValue(primitive);
  4473         borderColors = borderColors->mNext;
  4474       } while (borderColors);
  4476       return valueList;
  4480   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4481   val->SetIdent(eCSSKeyword_none);
  4482   return val;
  4485 CSSValue*
  4486 nsComputedDOMStyle::GetBorderWidthFor(mozilla::css::Side aSide)
  4488   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4490   nscoord width;
  4491   if (mInnerFrame) {
  4492     AssertFlushedPendingReflows();
  4493     width = mInnerFrame->GetUsedBorder().Side(aSide);
  4494   } else {
  4495     width = StyleBorder()->GetComputedBorderWidth(aSide);
  4497   val->SetAppUnits(width);
  4499   return val;
  4502 CSSValue*
  4503 nsComputedDOMStyle::GetBorderColorFor(mozilla::css::Side aSide)
  4505   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4507   nscolor color;
  4508   bool foreground;
  4509   StyleBorder()->GetBorderColor(aSide, color, foreground);
  4510   if (foreground) {
  4511     color = StyleColor()->mColor;
  4514   SetToRGBAColor(val, color);
  4515   return val;
  4518 CSSValue*
  4519 nsComputedDOMStyle::GetMarginWidthFor(mozilla::css::Side aSide)
  4521   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4523   if (!mInnerFrame) {
  4524     SetValueToCoord(val, StyleMargin()->mMargin.Get(aSide), false);
  4525   } else {
  4526     AssertFlushedPendingReflows();
  4528     // For tables, GetUsedMargin always returns an empty margin, so we
  4529     // should read the margin from the outer table frame instead.
  4530     val->SetAppUnits(mOuterFrame->GetUsedMargin().Side(aSide));
  4531     NS_ASSERTION(mOuterFrame == mInnerFrame ||
  4532                  mInnerFrame->GetUsedMargin() == nsMargin(0, 0, 0, 0),
  4533                  "Inner tables must have zero margins");
  4536   return val;
  4539 CSSValue*
  4540 nsComputedDOMStyle::GetBorderStyleFor(mozilla::css::Side aSide)
  4542   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4543   val->SetIdent(
  4544     nsCSSProps::ValueToKeywordEnum(StyleBorder()->GetBorderStyle(aSide),
  4545                                    nsCSSProps::kBorderStyleKTable));
  4546   return val;
  4549 void
  4550 nsComputedDOMStyle::SetValueToCoord(nsROCSSPrimitiveValue* aValue,
  4551                                     const nsStyleCoord& aCoord,
  4552                                     bool aClampNegativeCalc,
  4553                                     PercentageBaseGetter aPercentageBaseGetter,
  4554                                     const KTableValue aTable[],
  4555                                     nscoord aMinAppUnits,
  4556                                     nscoord aMaxAppUnits)
  4558   NS_PRECONDITION(aValue, "Must have a value to work with");
  4560   switch (aCoord.GetUnit()) {
  4561     case eStyleUnit_Normal:
  4562       aValue->SetIdent(eCSSKeyword_normal);
  4563       break;
  4565     case eStyleUnit_Auto:
  4566       aValue->SetIdent(eCSSKeyword_auto);
  4567       break;
  4569     case eStyleUnit_Percent:
  4571         nscoord percentageBase;
  4572         if (aPercentageBaseGetter &&
  4573             (this->*aPercentageBaseGetter)(percentageBase)) {
  4574           nscoord val = NSCoordSaturatingMultiply(percentageBase,
  4575                                                   aCoord.GetPercentValue());
  4576           aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
  4577         } else {
  4578           aValue->SetPercent(aCoord.GetPercentValue());
  4581       break;
  4583     case eStyleUnit_Factor:
  4584       aValue->SetNumber(aCoord.GetFactorValue());
  4585       break;
  4587     case eStyleUnit_Coord:
  4589         nscoord val = aCoord.GetCoordValue();
  4590         aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
  4592       break;
  4594     case eStyleUnit_Integer:
  4595       aValue->SetNumber(aCoord.GetIntValue());
  4596       break;
  4598     case eStyleUnit_Enumerated:
  4599       NS_ASSERTION(aTable, "Must have table to handle this case");
  4600       aValue->SetIdent(nsCSSProps::ValueToKeywordEnum(aCoord.GetIntValue(),
  4601                                                       aTable));
  4602       break;
  4604     case eStyleUnit_None:
  4605       aValue->SetIdent(eCSSKeyword_none);
  4606       break;
  4608     case eStyleUnit_Calc:
  4609       nscoord percentageBase;
  4610       if (!aCoord.CalcHasPercent()) {
  4611         nscoord val = nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
  4612         if (aClampNegativeCalc && val < 0) {
  4613           NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
  4614                             "parser should have rejected value");
  4615           val = 0;
  4617         aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
  4618       } else if (aPercentageBaseGetter &&
  4619                  (this->*aPercentageBaseGetter)(percentageBase)) {
  4620         nscoord val =
  4621           nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase);
  4622         if (aClampNegativeCalc && val < 0) {
  4623           NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
  4624                             "parser should have rejected value");
  4625           val = 0;
  4627         aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
  4628       } else {
  4629         nsStyleCoord::Calc *calc = aCoord.GetCalcValue();
  4630         SetValueToCalc(calc, aValue);
  4632       break;
  4634     case eStyleUnit_Degree:
  4635       aValue->SetDegree(aCoord.GetAngleValue());
  4636       break;
  4638     case eStyleUnit_Grad:
  4639       aValue->SetGrad(aCoord.GetAngleValue());
  4640       break;
  4642     case eStyleUnit_Radian:
  4643       aValue->SetRadian(aCoord.GetAngleValue());
  4644       break;
  4646     case eStyleUnit_Turn:
  4647       aValue->SetTurn(aCoord.GetAngleValue());
  4648       break;
  4650     case eStyleUnit_FlexFraction: {
  4651       nsAutoString tmpStr;
  4652       nsStyleUtil::AppendCSSNumber(aCoord.GetFlexFractionValue(), tmpStr);
  4653       tmpStr.AppendLiteral("fr");
  4654       aValue->SetString(tmpStr);
  4655       break;
  4658     default:
  4659       NS_ERROR("Can't handle this unit");
  4660       break;
  4664 nscoord
  4665 nsComputedDOMStyle::StyleCoordToNSCoord(const nsStyleCoord& aCoord,
  4666                                         PercentageBaseGetter aPercentageBaseGetter,
  4667                                         nscoord aDefaultValue,
  4668                                         bool aClampNegativeCalc)
  4670   NS_PRECONDITION(aPercentageBaseGetter, "Must have a percentage base getter");
  4671   if (aCoord.GetUnit() == eStyleUnit_Coord) {
  4672     return aCoord.GetCoordValue();
  4674   if (aCoord.GetUnit() == eStyleUnit_Percent || aCoord.IsCalcUnit()) {
  4675     nscoord percentageBase;
  4676     if ((this->*aPercentageBaseGetter)(percentageBase)) {
  4677       nscoord result =
  4678         nsRuleNode::ComputeCoordPercentCalc(aCoord, percentageBase);
  4679       if (aClampNegativeCalc && result < 0) {
  4680         NS_ABORT_IF_FALSE(aCoord.IsCalcUnit(),
  4681                           "parser should have rejected value");
  4682         result = 0;
  4684       return result;
  4686     // Fall through to returning aDefaultValue if we have no percentage base.
  4689   return aDefaultValue;
  4692 bool
  4693 nsComputedDOMStyle::GetCBContentWidth(nscoord& aWidth)
  4695   if (!mOuterFrame) {
  4696     return false;
  4699   AssertFlushedPendingReflows();
  4701   nsIFrame* container = mOuterFrame->GetContainingBlock();
  4702   aWidth = container->GetContentRect().width;
  4703   return true;
  4706 bool
  4707 nsComputedDOMStyle::GetCBContentHeight(nscoord& aHeight)
  4709   if (!mOuterFrame) {
  4710     return false;
  4713   AssertFlushedPendingReflows();
  4715   nsIFrame* container = mOuterFrame->GetContainingBlock();
  4716   aHeight = container->GetContentRect().height;
  4717   return true;
  4720 bool
  4721 nsComputedDOMStyle::GetScrollFrameContentWidth(nscoord& aWidth)
  4723   if (!mOuterFrame) {
  4724     return false;
  4727   AssertFlushedPendingReflows();
  4729   nsIScrollableFrame* scrollableFrame =
  4730     nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(),
  4731       nsLayoutUtils::SCROLLABLE_SAME_DOC |
  4732       nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
  4734   if (!scrollableFrame) {
  4735     return false;
  4737   aWidth =
  4738     scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().width;
  4739   return true;
  4742 bool
  4743 nsComputedDOMStyle::GetScrollFrameContentHeight(nscoord& aHeight)
  4745   if (!mOuterFrame) {
  4746     return false;
  4749   AssertFlushedPendingReflows();
  4751   nsIScrollableFrame* scrollableFrame =
  4752     nsLayoutUtils::GetNearestScrollableFrame(mOuterFrame->GetParent(),
  4753       nsLayoutUtils::SCROLLABLE_SAME_DOC |
  4754       nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
  4756   if (!scrollableFrame) {
  4757     return false;
  4759   aHeight =
  4760     scrollableFrame->GetScrolledFrame()->GetContentRectRelativeToSelf().height;
  4761   return true;
  4764 bool
  4765 nsComputedDOMStyle::GetFrameBorderRectWidth(nscoord& aWidth)
  4767   if (!mInnerFrame) {
  4768     return false;
  4771   AssertFlushedPendingReflows();
  4773   aWidth = mInnerFrame->GetSize().width;
  4774   return true;
  4777 bool
  4778 nsComputedDOMStyle::GetFrameBorderRectHeight(nscoord& aHeight)
  4780   if (!mInnerFrame) {
  4781     return false;
  4784   AssertFlushedPendingReflows();
  4786   aHeight = mInnerFrame->GetSize().height;
  4787   return true;
  4790 bool
  4791 nsComputedDOMStyle::GetFrameBoundsWidthForTransform(nscoord& aWidth)
  4793   // We need a frame to work with.
  4794   if (!mInnerFrame) {
  4795     return false;
  4798   AssertFlushedPendingReflows();
  4800   aWidth = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).width;
  4801   return true;
  4804 bool
  4805 nsComputedDOMStyle::GetFrameBoundsHeightForTransform(nscoord& aHeight)
  4807   // We need a frame to work with.
  4808   if (!mInnerFrame) {
  4809     return false;
  4812   AssertFlushedPendingReflows();
  4814   aHeight = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).height;
  4815   return true;
  4818 CSSValue*
  4819 nsComputedDOMStyle::GetSVGPaintFor(bool aFill)
  4821   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4823   const nsStyleSVG* svg = StyleSVG();
  4824   const nsStyleSVGPaint* paint = nullptr;
  4826   if (aFill)
  4827     paint = &svg->mFill;
  4828   else
  4829     paint = &svg->mStroke;
  4831   nsAutoString paintString;
  4833   switch (paint->mType) {
  4834     case eStyleSVGPaintType_None:
  4836       val->SetIdent(eCSSKeyword_none);
  4837       break;
  4839     case eStyleSVGPaintType_Color:
  4841       SetToRGBAColor(val, paint->mPaint.mColor);
  4842       break;
  4844     case eStyleSVGPaintType_Server:
  4846       nsDOMCSSValueList *valueList = GetROCSSValueList(false);
  4847       valueList->AppendCSSValue(val);
  4849       nsROCSSPrimitiveValue* fallback = new nsROCSSPrimitiveValue;
  4850       valueList->AppendCSSValue(fallback);
  4852       val->SetURI(paint->mPaint.mPaintServer);
  4853       SetToRGBAColor(fallback, paint->mFallbackColor);
  4854       return valueList;
  4856     case eStyleSVGPaintType_ContextFill:
  4858       val->SetIdent(eCSSKeyword_context_fill);
  4859       break;
  4861     case eStyleSVGPaintType_ContextStroke:
  4863       val->SetIdent(eCSSKeyword_context_stroke);
  4864       break;
  4868   return val;
  4871 CSSValue*
  4872 nsComputedDOMStyle::DoGetFill()
  4874   return GetSVGPaintFor(true);
  4877 CSSValue*
  4878 nsComputedDOMStyle::DoGetStroke()
  4880   return GetSVGPaintFor(false);
  4883 CSSValue*
  4884 nsComputedDOMStyle::DoGetMarkerEnd()
  4886   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4888   const nsStyleSVG* svg = StyleSVG();
  4890   if (svg->mMarkerEnd)
  4891     val->SetURI(svg->mMarkerEnd);
  4892   else
  4893     val->SetIdent(eCSSKeyword_none);
  4895   return val;
  4898 CSSValue*
  4899 nsComputedDOMStyle::DoGetMarkerMid()
  4901   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4903   const nsStyleSVG* svg = StyleSVG();
  4905   if (svg->mMarkerMid)
  4906     val->SetURI(svg->mMarkerMid);
  4907   else
  4908     val->SetIdent(eCSSKeyword_none);
  4910   return val;
  4913 CSSValue*
  4914 nsComputedDOMStyle::DoGetMarkerStart()
  4916   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4918   const nsStyleSVG* svg = StyleSVG();
  4920   if (svg->mMarkerStart)
  4921     val->SetURI(svg->mMarkerStart);
  4922   else
  4923     val->SetIdent(eCSSKeyword_none);
  4925   return val;
  4928 CSSValue*
  4929 nsComputedDOMStyle::DoGetStrokeDasharray()
  4931   const nsStyleSVG* svg = StyleSVG();
  4933   if (!svg->mStrokeDasharrayLength || !svg->mStrokeDasharray) {
  4934     nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4935     val->SetIdent(eCSSKeyword_none);
  4936     return val;
  4939   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  4941   for (uint32_t i = 0; i < svg->mStrokeDasharrayLength; i++) {
  4942     nsROCSSPrimitiveValue* dash = new nsROCSSPrimitiveValue;
  4943     valueList->AppendCSSValue(dash);
  4945     SetValueToCoord(dash, svg->mStrokeDasharray[i], true);
  4948   return valueList;
  4951 CSSValue*
  4952 nsComputedDOMStyle::DoGetStrokeDashoffset()
  4954   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4955   SetValueToCoord(val, StyleSVG()->mStrokeDashoffset, false);
  4956   return val;
  4959 CSSValue*
  4960 nsComputedDOMStyle::DoGetStrokeWidth()
  4962   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  4963   SetValueToCoord(val, StyleSVG()->mStrokeWidth, true);
  4964   return val;
  4967 CSSValue*
  4968 nsComputedDOMStyle::DoGetVectorEffect()
  4970   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4971   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mVectorEffect,
  4972                                                nsCSSProps::kVectorEffectKTable));
  4973   return val;
  4976 CSSValue*
  4977 nsComputedDOMStyle::DoGetFillOpacity()
  4979   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4980   val->SetNumber(StyleSVG()->mFillOpacity);
  4981   return val;
  4984 CSSValue*
  4985 nsComputedDOMStyle::DoGetFloodOpacity()
  4987   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4988   val->SetNumber(StyleSVGReset()->mFloodOpacity);
  4989   return val;
  4992 CSSValue*
  4993 nsComputedDOMStyle::DoGetStopOpacity()
  4995   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  4996   val->SetNumber(StyleSVGReset()->mStopOpacity);
  4997   return val;
  5000 CSSValue*
  5001 nsComputedDOMStyle::DoGetStrokeMiterlimit()
  5003   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5004   val->SetNumber(StyleSVG()->mStrokeMiterlimit);
  5005   return val;
  5008 CSSValue*
  5009 nsComputedDOMStyle::DoGetStrokeOpacity()
  5011   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5012   val->SetNumber(StyleSVG()->mStrokeOpacity);
  5013   return val;
  5016 CSSValue*
  5017 nsComputedDOMStyle::DoGetClipRule()
  5019   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5020   val->SetIdent(nsCSSProps::ValueToKeywordEnum(
  5021                   StyleSVG()->mClipRule, nsCSSProps::kFillRuleKTable));
  5022   return val;
  5025 CSSValue*
  5026 nsComputedDOMStyle::DoGetFillRule()
  5028   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5029   val->SetIdent(nsCSSProps::ValueToKeywordEnum(
  5030                   StyleSVG()->mFillRule, nsCSSProps::kFillRuleKTable));
  5031   return val;
  5034 CSSValue*
  5035 nsComputedDOMStyle::DoGetStrokeLinecap()
  5037   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5038   val->SetIdent(
  5039     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinecap,
  5040                                    nsCSSProps::kStrokeLinecapKTable));
  5041   return val;
  5044 CSSValue*
  5045 nsComputedDOMStyle::DoGetStrokeLinejoin()
  5047   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5048   val->SetIdent(
  5049     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinejoin,
  5050                                    nsCSSProps::kStrokeLinejoinKTable));
  5051   return val;
  5054 CSSValue*
  5055 nsComputedDOMStyle::DoGetTextAnchor()
  5057   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5058   val->SetIdent(
  5059     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mTextAnchor,
  5060                                    nsCSSProps::kTextAnchorKTable));
  5061   return val;
  5064 CSSValue*
  5065 nsComputedDOMStyle::DoGetColorInterpolation()
  5067   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5068   val->SetIdent(
  5069     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolation,
  5070                                    nsCSSProps::kColorInterpolationKTable));
  5071   return val;
  5074 CSSValue*
  5075 nsComputedDOMStyle::DoGetColorInterpolationFilters()
  5077   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5078   val->SetIdent(
  5079     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolationFilters,
  5080                                    nsCSSProps::kColorInterpolationKTable));
  5081   return val;
  5084 CSSValue*
  5085 nsComputedDOMStyle::DoGetDominantBaseline()
  5087   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5088   val->SetIdent(
  5089     nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mDominantBaseline,
  5090                                    nsCSSProps::kDominantBaselineKTable));
  5091   return val;
  5094 CSSValue*
  5095 nsComputedDOMStyle::DoGetImageRendering()
  5097   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5098   val->SetIdent(
  5099     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mImageRendering,
  5100                                    nsCSSProps::kImageRenderingKTable));
  5101   return val;
  5104 CSSValue*
  5105 nsComputedDOMStyle::DoGetShapeRendering()
  5107   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5108   val->SetIdent(
  5109     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mShapeRendering,
  5110                                    nsCSSProps::kShapeRenderingKTable));
  5111   return val;
  5114 CSSValue*
  5115 nsComputedDOMStyle::DoGetTextRendering()
  5117   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5118   val->SetIdent(
  5119     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mTextRendering,
  5120                                    nsCSSProps::kTextRenderingKTable));
  5121   return val;
  5124 CSSValue*
  5125 nsComputedDOMStyle::DoGetFloodColor()
  5127   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5128   SetToRGBAColor(val, StyleSVGReset()->mFloodColor);
  5129   return val;
  5132 CSSValue*
  5133 nsComputedDOMStyle::DoGetLightingColor()
  5135   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5136   SetToRGBAColor(val, StyleSVGReset()->mLightingColor);
  5137   return val;
  5140 CSSValue*
  5141 nsComputedDOMStyle::DoGetStopColor()
  5143   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5144   SetToRGBAColor(val, StyleSVGReset()->mStopColor);
  5145   return val;
  5148 CSSValue*
  5149 nsComputedDOMStyle::DoGetClipPath()
  5151   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  5153   const nsStyleSVGReset* svg = StyleSVGReset();
  5155   if (svg->mClipPath)
  5156     val->SetURI(svg->mClipPath);
  5157   else
  5158     val->SetIdent(eCSSKeyword_none);
  5160   return val;
  5163 void
  5164 nsComputedDOMStyle::SetCssTextToCoord(nsAString& aCssText,
  5165                                       const nsStyleCoord& aCoord)
  5167   nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
  5168   bool clampNegativeCalc = true;
  5169   SetValueToCoord(value, aCoord, clampNegativeCalc);
  5170   value->GetCssText(aCssText);
  5171   delete value;
  5174 CSSValue*
  5175 nsComputedDOMStyle::CreatePrimitiveValueForStyleFilter(
  5176   const nsStyleFilter& aStyleFilter)
  5178   nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
  5179   // Handle url().
  5180   if (aStyleFilter.GetType() == NS_STYLE_FILTER_URL) {
  5181     value->SetURI(aStyleFilter.GetURL());
  5182     return value;
  5185   // Filter function name and opening parenthesis.
  5186   nsAutoString filterFunctionString;
  5187   AppendASCIItoUTF16(
  5188     nsCSSProps::ValueToKeyword(aStyleFilter.GetType(),
  5189                                nsCSSProps::kFilterFunctionKTable),
  5190                                filterFunctionString);
  5191   filterFunctionString.AppendLiteral("(");
  5193   nsAutoString argumentString;
  5194   if (aStyleFilter.GetType() == NS_STYLE_FILTER_DROP_SHADOW) {
  5195     // Handle drop-shadow()
  5196     nsRefPtr<CSSValue> shadowValue =
  5197       GetCSSShadowArray(aStyleFilter.GetDropShadow(),
  5198                         StyleColor()->mColor,
  5199                         false);
  5200     ErrorResult dummy;
  5201     shadowValue->GetCssText(argumentString, dummy);
  5202   } else {
  5203     // Filter function argument.
  5204     SetCssTextToCoord(argumentString, aStyleFilter.GetFilterParameter());
  5206   filterFunctionString.Append(argumentString);
  5208   // Filter function closing parenthesis.
  5209   filterFunctionString.AppendLiteral(")");
  5211   value->SetString(filterFunctionString);
  5212   return value;
  5215 CSSValue*
  5216 nsComputedDOMStyle::DoGetFilter()
  5218   const nsTArray<nsStyleFilter>& filters = StyleSVGReset()->mFilters;
  5220   if (filters.IsEmpty()) {
  5221     nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
  5222     value->SetIdent(eCSSKeyword_none);
  5223     return value;
  5226   nsDOMCSSValueList* valueList = GetROCSSValueList(false);
  5227   for(uint32_t i = 0; i < filters.Length(); i++) {
  5228     CSSValue* value = CreatePrimitiveValueForStyleFilter(filters[i]);
  5229     valueList->AppendCSSValue(value);
  5231   return valueList;
  5234 CSSValue*
  5235 nsComputedDOMStyle::DoGetMask()
  5237   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  5239   const nsStyleSVGReset* svg = StyleSVGReset();
  5241   if (svg->mMask)
  5242     val->SetURI(svg->mMask);
  5243   else
  5244     val->SetIdent(eCSSKeyword_none);
  5246   return val;
  5249 CSSValue*
  5250 nsComputedDOMStyle::DoGetMaskType()
  5252   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5253   val->SetIdent(
  5254     nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mMaskType,
  5255                                    nsCSSProps::kMaskTypeKTable));
  5256   return val;
  5259 CSSValue*
  5260 nsComputedDOMStyle::DoGetPaintOrder()
  5262   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
  5263   nsAutoString string;
  5264   uint8_t paintOrder = StyleSVG()->mPaintOrder;
  5265   nsStyleUtil::AppendPaintOrderValue(paintOrder, string);
  5266   val->SetString(string);
  5267   return val;
  5270 CSSValue*
  5271 nsComputedDOMStyle::DoGetTransitionDelay()
  5273   const nsStyleDisplay* display = StyleDisplay();
  5275   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5277   NS_ABORT_IF_FALSE(display->mTransitionDelayCount > 0,
  5278                     "first item must be explicit");
  5279   uint32_t i = 0;
  5280   do {
  5281     const nsTransition *transition = &display->mTransitions[i];
  5282     nsROCSSPrimitiveValue* delay = new nsROCSSPrimitiveValue;
  5283     valueList->AppendCSSValue(delay);
  5284     delay->SetTime((float)transition->GetDelay() / (float)PR_MSEC_PER_SEC);
  5285   } while (++i < display->mTransitionDelayCount);
  5287   return valueList;
  5290 CSSValue*
  5291 nsComputedDOMStyle::DoGetTransitionDuration()
  5293   const nsStyleDisplay* display = StyleDisplay();
  5295   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5297   NS_ABORT_IF_FALSE(display->mTransitionDurationCount > 0,
  5298                     "first item must be explicit");
  5299   uint32_t i = 0;
  5300   do {
  5301     const nsTransition *transition = &display->mTransitions[i];
  5302     nsROCSSPrimitiveValue* duration = new nsROCSSPrimitiveValue;
  5303     valueList->AppendCSSValue(duration);
  5305     duration->SetTime((float)transition->GetDuration() / (float)PR_MSEC_PER_SEC);
  5306   } while (++i < display->mTransitionDurationCount);
  5308   return valueList;
  5311 CSSValue*
  5312 nsComputedDOMStyle::DoGetTransitionProperty()
  5314   const nsStyleDisplay* display = StyleDisplay();
  5316   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5318   NS_ABORT_IF_FALSE(display->mTransitionPropertyCount > 0,
  5319                     "first item must be explicit");
  5320   uint32_t i = 0;
  5321   do {
  5322     const nsTransition *transition = &display->mTransitions[i];
  5323     nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue;
  5324     valueList->AppendCSSValue(property);
  5325     nsCSSProperty cssprop = transition->GetProperty();
  5326     if (cssprop == eCSSPropertyExtra_all_properties)
  5327       property->SetIdent(eCSSKeyword_all);
  5328     else if (cssprop == eCSSPropertyExtra_no_properties)
  5329       property->SetIdent(eCSSKeyword_none);
  5330     else if (cssprop == eCSSProperty_UNKNOWN)
  5332       nsAutoString escaped;
  5333       nsStyleUtil::AppendEscapedCSSIdent(
  5334         nsDependentAtomString(transition->GetUnknownProperty()), escaped);
  5335       property->SetString(escaped); // really want SetIdent
  5337     else
  5338       property->SetString(nsCSSProps::GetStringValue(cssprop));
  5339   } while (++i < display->mTransitionPropertyCount);
  5341   return valueList;
  5344 void
  5345 nsComputedDOMStyle::AppendTimingFunction(nsDOMCSSValueList *aValueList,
  5346                                          const nsTimingFunction& aTimingFunction)
  5348   nsROCSSPrimitiveValue* timingFunction = new nsROCSSPrimitiveValue;
  5349   aValueList->AppendCSSValue(timingFunction);
  5351   nsAutoString tmp;
  5353   if (aTimingFunction.mType == nsTimingFunction::Function) {
  5354     // set the value from the cubic-bezier control points
  5355     // (We could try to regenerate the keywords if we want.)
  5356     tmp.AppendLiteral("cubic-bezier(");
  5357     tmp.AppendFloat(aTimingFunction.mFunc.mX1);
  5358     tmp.AppendLiteral(", ");
  5359     tmp.AppendFloat(aTimingFunction.mFunc.mY1);
  5360     tmp.AppendLiteral(", ");
  5361     tmp.AppendFloat(aTimingFunction.mFunc.mX2);
  5362     tmp.AppendLiteral(", ");
  5363     tmp.AppendFloat(aTimingFunction.mFunc.mY2);
  5364     tmp.AppendLiteral(")");
  5365   } else {
  5366     tmp.AppendLiteral("steps(");
  5367     tmp.AppendInt(aTimingFunction.mSteps);
  5368     if (aTimingFunction.mType == nsTimingFunction::StepStart) {
  5369       tmp.AppendLiteral(", start)");
  5370     } else {
  5371       tmp.AppendLiteral(", end)");
  5374   timingFunction->SetString(tmp);
  5377 CSSValue*
  5378 nsComputedDOMStyle::DoGetTransitionTimingFunction()
  5380   const nsStyleDisplay* display = StyleDisplay();
  5382   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5384   NS_ABORT_IF_FALSE(display->mTransitionTimingFunctionCount > 0,
  5385                     "first item must be explicit");
  5386   uint32_t i = 0;
  5387   do {
  5388     AppendTimingFunction(valueList,
  5389                          display->mTransitions[i].GetTimingFunction());
  5390   } while (++i < display->mTransitionTimingFunctionCount);
  5392   return valueList;
  5395 CSSValue*
  5396 nsComputedDOMStyle::DoGetAnimationName()
  5398   const nsStyleDisplay* display = StyleDisplay();
  5400   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5402   NS_ABORT_IF_FALSE(display->mAnimationNameCount > 0,
  5403                     "first item must be explicit");
  5404   uint32_t i = 0;
  5405   do {
  5406     const nsAnimation *animation = &display->mAnimations[i];
  5407     nsROCSSPrimitiveValue* property = new nsROCSSPrimitiveValue;
  5408     valueList->AppendCSSValue(property);
  5410     const nsString& name = animation->GetName();
  5411     if (name.IsEmpty()) {
  5412       property->SetIdent(eCSSKeyword_none);
  5413     } else {
  5414       nsAutoString escaped;
  5415       nsStyleUtil::AppendEscapedCSSIdent(animation->GetName(), escaped);
  5416       property->SetString(escaped); // really want SetIdent
  5418   } while (++i < display->mAnimationNameCount);
  5420   return valueList;
  5423 CSSValue*
  5424 nsComputedDOMStyle::DoGetAnimationDelay()
  5426   const nsStyleDisplay* display = StyleDisplay();
  5428   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5430   NS_ABORT_IF_FALSE(display->mAnimationDelayCount > 0,
  5431                     "first item must be explicit");
  5432   uint32_t i = 0;
  5433   do {
  5434     const nsAnimation *animation = &display->mAnimations[i];
  5435     nsROCSSPrimitiveValue* delay = new nsROCSSPrimitiveValue;
  5436     valueList->AppendCSSValue(delay);
  5437     delay->SetTime((float)animation->GetDelay() / (float)PR_MSEC_PER_SEC);
  5438   } while (++i < display->mAnimationDelayCount);
  5440   return valueList;
  5443 CSSValue*
  5444 nsComputedDOMStyle::DoGetAnimationDuration()
  5446   const nsStyleDisplay* display = StyleDisplay();
  5448   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5450   NS_ABORT_IF_FALSE(display->mAnimationDurationCount > 0,
  5451                     "first item must be explicit");
  5452   uint32_t i = 0;
  5453   do {
  5454     const nsAnimation *animation = &display->mAnimations[i];
  5455     nsROCSSPrimitiveValue* duration = new nsROCSSPrimitiveValue;
  5456     valueList->AppendCSSValue(duration);
  5458     duration->SetTime((float)animation->GetDuration() / (float)PR_MSEC_PER_SEC);
  5459   } while (++i < display->mAnimationDurationCount);
  5461   return valueList;
  5464 CSSValue*
  5465 nsComputedDOMStyle::DoGetAnimationTimingFunction()
  5467   const nsStyleDisplay* display = StyleDisplay();
  5469   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5471   NS_ABORT_IF_FALSE(display->mAnimationTimingFunctionCount > 0,
  5472                     "first item must be explicit");
  5473   uint32_t i = 0;
  5474   do {
  5475     AppendTimingFunction(valueList,
  5476                          display->mAnimations[i].GetTimingFunction());
  5477   } while (++i < display->mAnimationTimingFunctionCount);
  5479   return valueList;
  5482 CSSValue*
  5483 nsComputedDOMStyle::DoGetAnimationDirection()
  5485   const nsStyleDisplay* display = StyleDisplay();
  5487   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5489   NS_ABORT_IF_FALSE(display->mAnimationDirectionCount > 0,
  5490                     "first item must be explicit");
  5491   uint32_t i = 0;
  5492   do {
  5493     const nsAnimation *animation = &display->mAnimations[i];
  5494     nsROCSSPrimitiveValue* direction = new nsROCSSPrimitiveValue;
  5495     valueList->AppendCSSValue(direction);
  5496     direction->SetIdent(
  5497       nsCSSProps::ValueToKeywordEnum(animation->GetDirection(),
  5498                                      nsCSSProps::kAnimationDirectionKTable));
  5499   } while (++i < display->mAnimationDirectionCount);
  5501   return valueList;
  5504 CSSValue*
  5505 nsComputedDOMStyle::DoGetAnimationFillMode()
  5507   const nsStyleDisplay* display = StyleDisplay();
  5509   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5511   NS_ABORT_IF_FALSE(display->mAnimationFillModeCount > 0,
  5512                     "first item must be explicit");
  5513   uint32_t i = 0;
  5514   do {
  5515     const nsAnimation *animation = &display->mAnimations[i];
  5516     nsROCSSPrimitiveValue* fillMode = new nsROCSSPrimitiveValue;
  5517     valueList->AppendCSSValue(fillMode);
  5518     fillMode->SetIdent(
  5519       nsCSSProps::ValueToKeywordEnum(animation->GetFillMode(),
  5520                                      nsCSSProps::kAnimationFillModeKTable));
  5521   } while (++i < display->mAnimationFillModeCount);
  5523   return valueList;
  5526 CSSValue*
  5527 nsComputedDOMStyle::DoGetAnimationIterationCount()
  5529   const nsStyleDisplay* display = StyleDisplay();
  5531   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5533   NS_ABORT_IF_FALSE(display->mAnimationIterationCountCount > 0,
  5534                     "first item must be explicit");
  5535   uint32_t i = 0;
  5536   do {
  5537     const nsAnimation *animation = &display->mAnimations[i];
  5538     nsROCSSPrimitiveValue* iterationCount = new nsROCSSPrimitiveValue;
  5539     valueList->AppendCSSValue(iterationCount);
  5541     float f = animation->GetIterationCount();
  5542     /* Need a nasty hack here to work around an optimizer bug in gcc
  5543        4.2 on Mac, which somehow gets confused when directly comparing
  5544        a float to the return value of NS_IEEEPositiveInfinity when
  5545        building 32-bit builds. */
  5546 #ifdef XP_MACOSX
  5547     volatile
  5548 #endif
  5549       float inf = NS_IEEEPositiveInfinity();
  5550     if (f == inf) {
  5551       iterationCount->SetIdent(eCSSKeyword_infinite);
  5552     } else {
  5553       iterationCount->SetNumber(f);
  5555   } while (++i < display->mAnimationIterationCountCount);
  5557   return valueList;
  5560 CSSValue*
  5561 nsComputedDOMStyle::DoGetAnimationPlayState()
  5563   const nsStyleDisplay* display = StyleDisplay();
  5565   nsDOMCSSValueList *valueList = GetROCSSValueList(true);
  5567   NS_ABORT_IF_FALSE(display->mAnimationPlayStateCount > 0,
  5568                     "first item must be explicit");
  5569   uint32_t i = 0;
  5570   do {
  5571     const nsAnimation *animation = &display->mAnimations[i];
  5572     nsROCSSPrimitiveValue* playState = new nsROCSSPrimitiveValue;
  5573     valueList->AppendCSSValue(playState);
  5574     playState->SetIdent(
  5575       nsCSSProps::ValueToKeywordEnum(animation->GetPlayState(),
  5576                                      nsCSSProps::kAnimationPlayStateKTable));
  5577   } while (++i < display->mAnimationPlayStateCount);
  5579   return valueList;
  5582 static void
  5583 MarkComputedStyleMapDirty(const char* aPref, void* aData)
  5585   static_cast<nsComputedStyleMap*>(aData)->MarkDirty();
  5588 CSSValue*
  5589 nsComputedDOMStyle::DoGetCustomProperty(const nsAString& aPropertyName)
  5591   MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
  5593   const nsStyleVariables* variables = StyleVariables();
  5595   nsString variableValue;
  5596   const nsAString& name = Substring(aPropertyName,
  5597                                     CSS_CUSTOM_NAME_PREFIX_LENGTH);
  5598   if (!variables->mVariables.Get(name, variableValue)) {
  5599     return nullptr;
  5602   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
  5603   val->SetString(variableValue);
  5605   return val;
  5608 /* static */ nsComputedStyleMap*
  5609 nsComputedDOMStyle::GetComputedStyleMap()
  5611   static nsComputedStyleMap map = {
  5613 #define COMPUTED_STYLE_PROP(prop_, method_) \
  5614   { eCSSProperty_##prop_, &nsComputedDOMStyle::DoGet##method_ },
  5615 #include "nsComputedDOMStylePropertyList.h"
  5616 #undef COMPUTED_STYLE_PROP
  5618   };
  5619   return &map;
  5622 /* static */ void
  5623 nsComputedDOMStyle::RegisterPrefChangeCallbacks()
  5625   // Note that this will register callbacks for all properties with prefs, not
  5626   // just those that are implemented on computed style objects, as it's not
  5627   // easy to grab specific property data from nsCSSPropList.h based on the
  5628   // entries iterated in nsComputedDOMStylePropertyList.h.
  5629   nsComputedStyleMap* data = GetComputedStyleMap();
  5630 #define REGISTER_CALLBACK(pref_)                                             \
  5631   if (pref_[0]) {                                                            \
  5632     Preferences::RegisterCallback(MarkComputedStyleMapDirty, pref_, data);   \
  5634 #define CSS_PROP(prop_, id_, method_, flags_, pref_, parsevariant_,          \
  5635                  kwtable_, stylestruct_, stylestructoffset_, animtype_)      \
  5636   REGISTER_CALLBACK(pref_)
  5637 #include "nsCSSPropList.h"
  5638 #undef CSS_PROP
  5639 #undef REGISTER_CALLBACK
  5642 /* static */ void
  5643 nsComputedDOMStyle::UnregisterPrefChangeCallbacks()
  5645   nsComputedStyleMap* data = GetComputedStyleMap();
  5646 #define UNREGISTER_CALLBACK(pref_)                                             \
  5647   if (pref_[0]) {                                                              \
  5648     Preferences::UnregisterCallback(MarkComputedStyleMapDirty, pref_, data);   \
  5650 #define CSS_PROP(prop_, id_, method_, flags_, pref_, parsevariant_,            \
  5651                  kwtable_, stylestruct_, stylestructoffset_, animtype_)        \
  5652   UNREGISTER_CALLBACK(pref_)
  5653 #include "nsCSSPropList.h"
  5654 #undef CSS_PROP
  5655 #undef UNREGISTER_CALLBACK

mercurial