layout/style/nsRuleNode.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 ts=2 et sw=2 tw=78: */
     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 /*
     8  * a node in the lexicographic tree of rules that match an element,
     9  * responsible for converting the rules' information into computed style
    10  */
    12 #include <algorithm>
    14 #include "mozilla/ArrayUtils.h"
    15 #include "mozilla/Assertions.h"
    16 #include "mozilla/DebugOnly.h"
    17 #include "mozilla/Likely.h"
    18 #include "mozilla/LookAndFeel.h"
    20 #include "nsRuleNode.h"
    21 #include "nscore.h"
    22 #include "nsIWidget.h"
    23 #include "nsIPresShell.h"
    24 #include "nsFontMetrics.h"
    25 #include "gfxFont.h"
    26 #include "nsCSSPseudoElements.h"
    27 #include "nsThemeConstants.h"
    28 #include "pldhash.h"
    29 #include "nsStyleContext.h"
    30 #include "nsStyleSet.h"
    31 #include "nsStyleStruct.h"
    32 #include "nsSize.h"
    33 #include "nsRuleData.h"
    34 #include "gfxUserFontSet.h"
    35 #include "nsIStyleRule.h"
    36 #include "nsBidiUtils.h"
    37 #include "nsStyleStructInlines.h"
    38 #include "nsCSSProps.h"
    39 #include "nsTArray.h"
    40 #include "nsContentUtils.h"
    41 #include "CSSCalc.h"
    42 #include "nsPrintfCString.h"
    43 #include "nsRenderingContext.h"
    44 #include "nsStyleUtil.h"
    45 #include "nsIDocument.h"
    46 #include "prtime.h"
    47 #include "CSSVariableResolver.h"
    48 #include "nsCSSParser.h"
    50 #if defined(_MSC_VER) || defined(__MINGW32__)
    51 #include <malloc.h>
    52 #ifdef _MSC_VER
    53 #define alloca _alloca
    54 #endif
    55 #endif
    56 #ifdef SOLARIS
    57 #include <alloca.h>
    58 #endif
    60 using std::max;
    61 using std::min;
    62 using namespace mozilla;
    63 using namespace mozilla::dom;
    65 #define NS_SET_IMAGE_REQUEST(method_, context_, request_)                   \
    66   if ((context_)->PresContext()->IsDynamic()) {                               \
    67     method_(request_);                                                      \
    68   } else {                                                                  \
    69     nsRefPtr<imgRequestProxy> req = nsContentUtils::GetStaticRequest(request_); \
    70     method_(req);                                                           \
    71   }
    73 #define NS_SET_IMAGE_REQUEST_WITH_DOC(method_, context_, requestgetter_)      \
    74   {                                                                           \
    75     nsIDocument* doc = (context_)->PresContext()->Document();                 \
    76     NS_SET_IMAGE_REQUEST(method_, context_, requestgetter_(doc))              \
    77   }
    79 /*
    80  * For storage of an |nsRuleNode|'s children in a PLDHashTable.
    81  */
    83 struct ChildrenHashEntry : public PLDHashEntryHdr {
    84   // key is |mRuleNode->GetKey()|
    85   nsRuleNode *mRuleNode;
    86 };
    88 /* static */ PLDHashNumber
    89 nsRuleNode::ChildrenHashHashKey(PLDHashTable *aTable, const void *aKey)
    90 {
    91   const nsRuleNode::Key *key =
    92     static_cast<const nsRuleNode::Key*>(aKey);
    93   // Disagreement on importance and level for the same rule is extremely
    94   // rare, so hash just on the rule.
    95   return PL_DHashVoidPtrKeyStub(aTable, key->mRule);
    96 }
    98 /* static */ bool
    99 nsRuleNode::ChildrenHashMatchEntry(PLDHashTable *aTable,
   100                                    const PLDHashEntryHdr *aHdr,
   101                                    const void *aKey)
   102 {
   103   const ChildrenHashEntry *entry =
   104     static_cast<const ChildrenHashEntry*>(aHdr);
   105   const nsRuleNode::Key *key =
   106     static_cast<const nsRuleNode::Key*>(aKey);
   107   return entry->mRuleNode->GetKey() == *key;
   108 }
   110 /* static */ const PLDHashTableOps
   111 nsRuleNode::ChildrenHashOps = {
   112   // It's probably better to allocate the table itself using malloc and
   113   // free rather than the pres shell's arena because the table doesn't
   114   // grow very often and the pres shell's arena doesn't recycle very
   115   // large size allocations.
   116   PL_DHashAllocTable,
   117   PL_DHashFreeTable,
   118   ChildrenHashHashKey,
   119   ChildrenHashMatchEntry,
   120   PL_DHashMoveEntryStub,
   121   PL_DHashClearEntryStub,
   122   PL_DHashFinalizeStub,
   123   nullptr
   124 };
   127 // EnsureBlockDisplay:
   128 //  - if the display value (argument) is not a block-type
   129 //    then we set it to a valid block display value
   130 //  - For enforcing the floated/positioned element CSS2 rules
   131 //  - We allow the behavior of "list-item" to be customized.
   132 //    CSS21 says that position/float do not convert 'list-item' to 'block',
   133 //    but it explicitly does not define whether 'list-item' should be
   134 //    converted to block *on the root node*. To allow for flexibility
   135 //    (so that we don't have to support a list-item root node), this method
   136 //    lets the caller pick either behavior, using the 'aConvertListItem' arg.
   137 //    Reference: http://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo
   138 /* static */
   139 void
   140 nsRuleNode::EnsureBlockDisplay(uint8_t& display,
   141                                bool aConvertListItem /* = false */)
   142 {
   143   // see if the display value is already a block
   144   switch (display) {
   145   case NS_STYLE_DISPLAY_LIST_ITEM :
   146     if (aConvertListItem) {
   147       display = NS_STYLE_DISPLAY_BLOCK;
   148       break;
   149     } // else, fall through to share the 'break' for non-changing display vals
   150   case NS_STYLE_DISPLAY_NONE :
   151     // never change display:none *ever*
   152   case NS_STYLE_DISPLAY_TABLE :
   153   case NS_STYLE_DISPLAY_BLOCK :
   154   case NS_STYLE_DISPLAY_FLEX :
   155   case NS_STYLE_DISPLAY_GRID :
   156     // do not muck with these at all - already blocks
   157     // This is equivalent to nsStyleDisplay::IsBlockOutside.  (XXX Maybe we
   158     // should just call that?)
   159     // This needs to match the check done in
   160     // nsCSSFrameConstructor::FindMathMLData for <math>.
   161     break;
   163   case NS_STYLE_DISPLAY_INLINE_TABLE :
   164     // make inline tables into tables
   165     display = NS_STYLE_DISPLAY_TABLE;
   166     break;
   168   case NS_STYLE_DISPLAY_INLINE_FLEX:
   169     // make inline flex containers into flex containers
   170     display = NS_STYLE_DISPLAY_FLEX;
   171     break;
   173   case NS_STYLE_DISPLAY_INLINE_GRID:
   174     // make inline grid containers into grid containers
   175     display = NS_STYLE_DISPLAY_GRID;
   176     break;
   178   default :
   179     // make it a block
   180     display = NS_STYLE_DISPLAY_BLOCK;
   181   }
   182 }
   184 static nscoord CalcLengthWith(const nsCSSValue& aValue,
   185                               nscoord aFontSize,
   186                               const nsStyleFont* aStyleFont,
   187                               nsStyleContext* aStyleContext,
   188                               nsPresContext* aPresContext,
   189                               bool aUseProvidedRootEmSize,
   190                               bool aUseUserFontSet,
   191                               bool& aCanStoreInRuleTree);
   193 struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
   194                            public css::NumbersAlreadyNormalizedOps
   195 {
   196   // All of the parameters to CalcLengthWith except aValue.
   197   const nscoord mFontSize;
   198   const nsStyleFont* const mStyleFont;
   199   nsStyleContext* const mStyleContext;
   200   nsPresContext* const mPresContext;
   201   const bool mUseProvidedRootEmSize;
   202   const bool mUseUserFontSet;
   203   bool& mCanStoreInRuleTree;
   205   CalcLengthCalcOps(nscoord aFontSize, const nsStyleFont* aStyleFont,
   206                     nsStyleContext* aStyleContext, nsPresContext* aPresContext,
   207                     bool aUseProvidedRootEmSize, bool aUseUserFontSet,
   208                     bool& aCanStoreInRuleTree)
   209     : mFontSize(aFontSize),
   210       mStyleFont(aStyleFont),
   211       mStyleContext(aStyleContext),
   212       mPresContext(aPresContext),
   213       mUseProvidedRootEmSize(aUseProvidedRootEmSize),
   214       mUseUserFontSet(aUseUserFontSet),
   215       mCanStoreInRuleTree(aCanStoreInRuleTree)
   216   {
   217   }
   219   result_type ComputeLeafValue(const nsCSSValue& aValue)
   220   {
   221     return CalcLengthWith(aValue, mFontSize, mStyleFont,
   222                           mStyleContext, mPresContext, mUseProvidedRootEmSize,
   223                           mUseUserFontSet, mCanStoreInRuleTree);
   224   }
   225 };
   227 static inline nscoord ScaleCoord(const nsCSSValue &aValue, float factor)
   228 {
   229   return NSToCoordRoundWithClamp(aValue.GetFloatValue() * factor);
   230 }
   232 already_AddRefed<nsFontMetrics>
   233 GetMetricsFor(nsPresContext* aPresContext,
   234               nsStyleContext* aStyleContext,
   235               const nsStyleFont* aStyleFont,
   236               nscoord aFontSize, // overrides value from aStyleFont
   237               bool aUseUserFontSet)
   238 {
   239   nsFont font = aStyleFont->mFont;
   240   font.size = aFontSize;
   241   gfxUserFontSet *fs = nullptr;
   242   if (aUseUserFontSet) {
   243     fs = aPresContext->GetUserFontSet();
   244   }
   245   gfxTextPerfMetrics *tp = aPresContext->GetTextPerfMetrics();
   246   nsRefPtr<nsFontMetrics> fm;
   247   aPresContext->DeviceContext()->GetMetricsFor(font,
   248                                                aStyleFont->mLanguage,
   249                                                fs, tp, *getter_AddRefs(fm));
   250   return fm.forget();
   251 }
   254 static nsSize CalcViewportUnitsScale(nsPresContext* aPresContext)
   255 {
   256   // The caller is making use of viewport units, so notify the pres context
   257   // that it will need to rebuild the rule tree if the size of the viewport
   258   // changes.
   259   aPresContext->SetUsesViewportUnits(true);
   261   // The default (when we have 'overflow: auto' on the root element, or
   262   // trivially for 'overflow: hidden' since we never have scrollbars in that
   263   // case) is to define the scale of the viewport units without considering
   264   // scrollbars.
   265   nsSize viewportSize(aPresContext->GetVisibleArea().Size());
   267   // Check for 'overflow: scroll' styles on the root scroll frame. If we find
   268   // any, the standard requires us to take scrollbars into account.
   269   nsIScrollableFrame* scrollFrame =
   270     aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
   271   if (scrollFrame) {
   272     ScrollbarStyles styles(scrollFrame->GetScrollbarStyles());
   274     if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL ||
   275         styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
   276       // Gather scrollbar size information.
   277       nsRefPtr<nsRenderingContext> context =
   278         aPresContext->PresShell()->CreateReferenceRenderingContext();
   279       nsMargin sizes(scrollFrame->GetDesiredScrollbarSizes(aPresContext, context));
   281       if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
   282         // 'overflow-x: scroll' means we must consider the horizontal scrollbar,
   283         // which affects the scale of viewport height units.
   284         viewportSize.height -= sizes.TopBottom();
   285       }
   287       if (styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
   288         // 'overflow-y: scroll' means we must consider the vertical scrollbar,
   289         // which affects the scale of viewport width units.
   290         viewportSize.width -= sizes.LeftRight();
   291       }
   292     }
   293   }
   295   return viewportSize;
   296 }
   298 static nscoord CalcLengthWith(const nsCSSValue& aValue,
   299                               nscoord aFontSize,
   300                               const nsStyleFont* aStyleFont,
   301                               nsStyleContext* aStyleContext,
   302                               nsPresContext* aPresContext,
   303                               bool aUseProvidedRootEmSize,
   304                               // aUseUserFontSet should always be true
   305                               // except when called from
   306                               // CalcLengthWithInitialFont.
   307                               bool aUseUserFontSet,
   308                               bool& aCanStoreInRuleTree)
   309 {
   310   NS_ASSERTION(aValue.IsLengthUnit() || aValue.IsCalcUnit(),
   311                "not a length or calc unit");
   312   NS_ASSERTION(aStyleFont || aStyleContext,
   313                "Must have style data");
   314   NS_ASSERTION(!aStyleFont || !aStyleContext,
   315                "Duplicate sources of data");
   316   NS_ASSERTION(aPresContext, "Must have prescontext");
   318   if (aValue.IsFixedLengthUnit()) {
   319     return aValue.GetFixedLength(aPresContext);
   320   }
   321   if (aValue.IsPixelLengthUnit()) {
   322     return aValue.GetPixelLength();
   323   }
   324   if (aValue.IsCalcUnit()) {
   325     // For properties for which lengths are the *only* units accepted in
   326     // calc(), we can handle calc() here and just compute a final
   327     // result.  We ensure that we don't get to this code for other
   328     // properties by not calling CalcLength in those cases:  SetCoord
   329     // only calls CalcLength for a calc when it is appropriate to do so.
   330     CalcLengthCalcOps ops(aFontSize, aStyleFont,
   331                           aStyleContext, aPresContext,
   332                           aUseProvidedRootEmSize, aUseUserFontSet,
   333                           aCanStoreInRuleTree);
   334     return css::ComputeCalc(aValue, ops);
   335   }
   336   switch (aValue.GetUnit()) {
   337     // nsPresContext::SetVisibleArea and
   338     // nsPresContext::MediaFeatureValuesChanged handle dynamic changes
   339     // of the basis for viewport units by rebuilding the rule tree and
   340     // style context tree.  Not caching them in the rule tree wouldn't
   341     // be sufficient to handle these changes because we also need a way
   342     // to get rid of cached values in the style context tree without any
   343     // changes in specified style.  We can either do this by not caching
   344     // in the rule tree and then throwing away the style context tree
   345     // for dynamic viewport size changes, or by allowing caching in the
   346     // rule tree and using the existing rebuild style data path that
   347     // throws away the style context and the rule tree.
   348     // Thus we do cache viewport units in the rule tree.  This allows us
   349     // to benefit from the performance advantages of the rule tree
   350     // (e.g., faster dynamic changes on other things, like transforms)
   351     // and allows us not to need an additional code path, in exchange
   352     // for an increased cost to dynamic changes to the viewport size
   353     // when viewport units are in use.
   354     case eCSSUnit_ViewportWidth: {
   355       return ScaleCoord(aValue, 0.01f * CalcViewportUnitsScale(aPresContext).width);
   356     }
   357     case eCSSUnit_ViewportHeight: {
   358       return ScaleCoord(aValue, 0.01f * CalcViewportUnitsScale(aPresContext).height);
   359     }
   360     case eCSSUnit_ViewportMin: {
   361       nsSize vuScale(CalcViewportUnitsScale(aPresContext));
   362       return ScaleCoord(aValue, 0.01f * min(vuScale.width, vuScale.height));
   363     }
   364     case eCSSUnit_ViewportMax: {
   365       nsSize vuScale(CalcViewportUnitsScale(aPresContext));
   366       return ScaleCoord(aValue, 0.01f * max(vuScale.width, vuScale.height));
   367     }
   368     // While we could deal with 'rem' units correctly by simply not
   369     // caching any data that uses them in the rule tree, it's valuable
   370     // to store them in the rule tree (for faster dynamic changes of
   371     // other things).  And since the font size of the root element
   372     // changes rarely, we instead handle dynamic changes to the root
   373     // element's font size by rebuilding all style data in
   374     // nsCSSFrameConstructor::RestyleElement.
   375     case eCSSUnit_RootEM: {
   376       aPresContext->SetUsesRootEMUnits(true);
   377       nscoord rootFontSize;
   379       // NOTE: Be very careful with |styleFont|, since we haven't set
   380       // aCanStoreInRuleTree to false yet, so we don't want to introduce
   381       // any dependencies on aStyleContext's data here.
   382       const nsStyleFont *styleFont =
   383         aStyleFont ? aStyleFont : aStyleContext->StyleFont();
   385       if (aUseProvidedRootEmSize) {
   386         // We should use the provided aFontSize as the reference length to
   387         // scale. This only happens when we are calculating font-size or
   388         // an equivalent (scriptminsize or CalcLengthWithInitialFont) on
   389         // the root element, in which case aFontSize is already the
   390         // value we want.
   391         if (aFontSize == -1) {
   392           // XXX Should this be styleFont->mSize instead to avoid taking
   393           // minfontsize prefs into account?
   394           aFontSize = styleFont->mFont.size;
   395         }
   396         rootFontSize = aFontSize;
   397       } else if (aStyleContext && !aStyleContext->GetParent()) {
   398         // This is the root element (XXX we don't really know this, but
   399         // nsRuleNode::SetFont makes the same assumption!), so we should
   400         // use StyleFont on this context to get the root element's
   401         // font size.
   402         rootFontSize = styleFont->mFont.size;
   403       } else {
   404         // This is not the root element or we are calculating something other
   405         // than font size, so rem is relative to the root element's font size.
   406         nsRefPtr<nsStyleContext> rootStyle;
   407         const nsStyleFont *rootStyleFont = styleFont;
   408         Element* docElement = aPresContext->Document()->GetRootElement();
   410         if (docElement) {
   411           rootStyle = aPresContext->StyleSet()->ResolveStyleFor(docElement,
   412                                                                 nullptr);
   413           rootStyleFont = rootStyle->StyleFont();
   414         }
   416         rootFontSize = rootStyleFont->mFont.size;
   417       }
   419       return ScaleCoord(aValue, float(rootFontSize));
   420     }
   421     default:
   422       // Fall through to the code for units that can't be stored in the
   423       // rule tree because they depend on font data.
   424       break;
   425   }
   426   // Common code for units that depend on the element's font data and
   427   // thus can't be stored in the rule tree:
   428   aCanStoreInRuleTree = false;
   429   const nsStyleFont *styleFont =
   430     aStyleFont ? aStyleFont : aStyleContext->StyleFont();
   431   if (aFontSize == -1) {
   432     // XXX Should this be styleFont->mSize instead to avoid taking minfontsize
   433     // prefs into account?
   434     aFontSize = styleFont->mFont.size;
   435   }
   436   switch (aValue.GetUnit()) {
   437     case eCSSUnit_EM: {
   438       // CSS2.1 specifies that this unit scales to the computed font
   439       // size, not the em-width in the font metrics, despite the name.
   440       return ScaleCoord(aValue, float(aFontSize));
   441     }
   442     case eCSSUnit_XHeight: {
   443       nsRefPtr<nsFontMetrics> fm =
   444         GetMetricsFor(aPresContext, aStyleContext, styleFont,
   445                       aFontSize, aUseUserFontSet);
   446       return ScaleCoord(aValue, float(fm->XHeight()));
   447     }
   448     case eCSSUnit_Char: {
   449       nsRefPtr<nsFontMetrics> fm =
   450         GetMetricsFor(aPresContext, aStyleContext, styleFont,
   451                       aFontSize, aUseUserFontSet);
   452       gfxFloat zeroWidth = (fm->GetThebesFontGroup()->GetFontAt(0)
   453                             ->GetMetrics().zeroOrAveCharWidth);
   455       return ScaleCoord(aValue, ceil(aPresContext->AppUnitsPerDevPixel() *
   456                                      zeroWidth));
   457     }
   458     default:
   459       NS_NOTREACHED("unexpected unit");
   460       break;
   461   }
   462   return 0;
   463 }
   465 /* static */ nscoord
   466 nsRuleNode::CalcLength(const nsCSSValue& aValue,
   467                        nsStyleContext* aStyleContext,
   468                        nsPresContext* aPresContext,
   469                        bool& aCanStoreInRuleTree)
   470 {
   471   NS_ASSERTION(aStyleContext, "Must have style data");
   473   return CalcLengthWith(aValue, -1, nullptr,
   474                         aStyleContext, aPresContext,
   475                         false, true, aCanStoreInRuleTree);
   476 }
   478 /* Inline helper function to redirect requests to CalcLength. */
   479 static inline nscoord CalcLength(const nsCSSValue& aValue,
   480                                  nsStyleContext* aStyleContext,
   481                                  nsPresContext* aPresContext,
   482                                  bool& aCanStoreInRuleTree)
   483 {
   484   return nsRuleNode::CalcLength(aValue, aStyleContext,
   485                                 aPresContext, aCanStoreInRuleTree);
   486 }
   488 /* static */ nscoord
   489 nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
   490                                       const nsCSSValue& aValue)
   491 {
   492   nsStyleFont defaultFont(aPresContext); // FIXME: best language?
   493   bool canStoreInRuleTree;
   494   return CalcLengthWith(aValue, -1, &defaultFont,
   495                         nullptr, aPresContext,
   496                         true, false, canStoreInRuleTree);
   497 }
   499 struct LengthPercentPairCalcOps : public css::NumbersAlreadyNormalizedOps
   500 {
   501   typedef nsRuleNode::ComputedCalc result_type;
   503   LengthPercentPairCalcOps(nsStyleContext* aContext,
   504                            nsPresContext* aPresContext,
   505                            bool& aCanStoreInRuleTree)
   506     : mContext(aContext),
   507       mPresContext(aPresContext),
   508       mCanStoreInRuleTree(aCanStoreInRuleTree),
   509       mHasPercent(false) {}
   511   nsStyleContext* mContext;
   512   nsPresContext* mPresContext;
   513   bool& mCanStoreInRuleTree;
   514   bool mHasPercent;
   516   result_type ComputeLeafValue(const nsCSSValue& aValue)
   517   {
   518     if (aValue.GetUnit() == eCSSUnit_Percent) {
   519       mHasPercent = true;
   520       return result_type(0, aValue.GetPercentValue());
   521     }
   522     return result_type(CalcLength(aValue, mContext, mPresContext,
   523                                   mCanStoreInRuleTree),
   524                        0.0f);
   525   }
   527   result_type
   528   MergeAdditive(nsCSSUnit aCalcFunction,
   529                 result_type aValue1, result_type aValue2)
   530   {
   531     if (aCalcFunction == eCSSUnit_Calc_Plus) {
   532       return result_type(NSCoordSaturatingAdd(aValue1.mLength,
   533                                               aValue2.mLength),
   534                          aValue1.mPercent + aValue2.mPercent);
   535     }
   536     NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Minus,
   537                       "min() and max() are not allowed in calc() on "
   538                       "transform");
   539     return result_type(NSCoordSaturatingSubtract(aValue1.mLength,
   540                                                  aValue2.mLength, 0),
   541                        aValue1.mPercent - aValue2.mPercent);
   542   }
   544   result_type
   545   MergeMultiplicativeL(nsCSSUnit aCalcFunction,
   546                        float aValue1, result_type aValue2)
   547   {
   548     NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_L,
   549                       "unexpected unit");
   550     return result_type(NSCoordSaturatingMultiply(aValue2.mLength, aValue1),
   551                        aValue1 * aValue2.mPercent);
   552   }
   554   result_type
   555   MergeMultiplicativeR(nsCSSUnit aCalcFunction,
   556                        result_type aValue1, float aValue2)
   557   {
   558     NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_R ||
   559                       aCalcFunction == eCSSUnit_Calc_Divided,
   560                       "unexpected unit");
   561     if (aCalcFunction == eCSSUnit_Calc_Divided) {
   562       aValue2 = 1.0f / aValue2;
   563     }
   564     return result_type(NSCoordSaturatingMultiply(aValue1.mLength, aValue2),
   565                        aValue1.mPercent * aValue2);
   566   }
   568 };
   570 static void
   571 SpecifiedCalcToComputedCalc(const nsCSSValue& aValue, nsStyleCoord& aCoord, 
   572                             nsStyleContext* aStyleContext,
   573                             bool& aCanStoreInRuleTree)
   574 {
   575   LengthPercentPairCalcOps ops(aStyleContext, aStyleContext->PresContext(),
   576                                aCanStoreInRuleTree);
   577   nsRuleNode::ComputedCalc vals = ComputeCalc(aValue, ops);
   579   nsStyleCoord::Calc *calcObj =
   580     new (aStyleContext->Alloc(sizeof(nsStyleCoord::Calc))) nsStyleCoord::Calc;
   581   // Because we use aStyleContext->Alloc(), we have to store the result
   582   // on the style context and not in the rule tree.
   583   aCanStoreInRuleTree = false;
   585   calcObj->mLength = vals.mLength;
   586   calcObj->mPercent = vals.mPercent;
   587   calcObj->mHasPercent = ops.mHasPercent;
   589   aCoord.SetCalcValue(calcObj);
   590 }
   592 /* static */ nsRuleNode::ComputedCalc
   593 nsRuleNode::SpecifiedCalcToComputedCalc(const nsCSSValue& aValue,
   594                                         nsStyleContext* aStyleContext,
   595                                         nsPresContext* aPresContext,
   596                                         bool& aCanStoreInRuleTree)
   597 {
   598   LengthPercentPairCalcOps ops(aStyleContext, aPresContext,
   599                                aCanStoreInRuleTree);
   600   return ComputeCalc(aValue, ops);
   601 }
   603 // This is our public API for handling calc() expressions that involve
   604 // percentages.
   605 /* static */ nscoord
   606 nsRuleNode::ComputeComputedCalc(const nsStyleCoord& aValue,
   607                                 nscoord aPercentageBasis)
   608 {
   609   nsStyleCoord::Calc *calc = aValue.GetCalcValue();
   610   return calc->mLength +
   611          NSToCoordFloorClamped(aPercentageBasis * calc->mPercent);
   612 }
   614 /* static */ nscoord
   615 nsRuleNode::ComputeCoordPercentCalc(const nsStyleCoord& aCoord,
   616                                     nscoord aPercentageBasis)
   617 {
   618   switch (aCoord.GetUnit()) {
   619     case eStyleUnit_Coord:
   620       return aCoord.GetCoordValue();
   621     case eStyleUnit_Percent:
   622       return NSToCoordFloorClamped(aPercentageBasis * aCoord.GetPercentValue());
   623     case eStyleUnit_Calc:
   624       return ComputeComputedCalc(aCoord, aPercentageBasis);
   625     default:
   626       NS_ABORT_IF_FALSE(false, "unexpected unit");
   627       return 0;
   628   }
   629 }
   631 /* Given an enumerated value that represents a box position, converts it to
   632  * a float representing the percentage of the box it corresponds to.  For
   633  * example, "center" becomes 0.5f.
   634  *
   635  * @param aEnumValue The enumerated value.
   636  * @return The float percent it corresponds to.
   637  */
   638 static float
   639 GetFloatFromBoxPosition(int32_t aEnumValue)
   640 {
   641   switch (aEnumValue) {
   642   case NS_STYLE_BG_POSITION_LEFT:
   643   case NS_STYLE_BG_POSITION_TOP:
   644     return 0.0f;
   645   case NS_STYLE_BG_POSITION_RIGHT:
   646   case NS_STYLE_BG_POSITION_BOTTOM:
   647     return 1.0f;
   648   default:
   649     NS_NOTREACHED("unexpected value");
   650     // fall through
   651   case NS_STYLE_BG_POSITION_CENTER:
   652     return 0.5f;
   653   }
   654 }
   656 #define SETCOORD_NORMAL                 0x01   // N
   657 #define SETCOORD_AUTO                   0x02   // A
   658 #define SETCOORD_INHERIT                0x04   // H
   659 #define SETCOORD_PERCENT                0x08   // P
   660 #define SETCOORD_FACTOR                 0x10   // F
   661 #define SETCOORD_LENGTH                 0x20   // L
   662 #define SETCOORD_INTEGER                0x40   // I
   663 #define SETCOORD_ENUMERATED             0x80   // E
   664 #define SETCOORD_NONE                   0x100  // O
   665 #define SETCOORD_INITIAL_ZERO           0x200
   666 #define SETCOORD_INITIAL_AUTO           0x400
   667 #define SETCOORD_INITIAL_NONE           0x800
   668 #define SETCOORD_INITIAL_NORMAL         0x1000
   669 #define SETCOORD_INITIAL_HALF           0x2000
   670 #define SETCOORD_INITIAL_HUNDRED_PCT    0x00004000
   671 #define SETCOORD_INITIAL_FACTOR_ONE     0x00008000
   672 #define SETCOORD_INITIAL_FACTOR_ZERO    0x00010000
   673 #define SETCOORD_CALC_LENGTH_ONLY       0x00020000
   674 #define SETCOORD_CALC_CLAMP_NONNEGATIVE 0x00040000 // modifier for CALC_LENGTH_ONLY
   675 #define SETCOORD_STORE_CALC             0x00080000
   676 #define SETCOORD_BOX_POSITION           0x00100000 // exclusive with _ENUMERATED
   677 #define SETCOORD_ANGLE                  0x00200000
   678 #define SETCOORD_UNSET_INHERIT          0x00400000
   679 #define SETCOORD_UNSET_INITIAL          0x00800000
   681 #define SETCOORD_LP     (SETCOORD_LENGTH | SETCOORD_PERCENT)
   682 #define SETCOORD_LH     (SETCOORD_LENGTH | SETCOORD_INHERIT)
   683 #define SETCOORD_AH     (SETCOORD_AUTO | SETCOORD_INHERIT)
   684 #define SETCOORD_LAH    (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT)
   685 #define SETCOORD_LPH    (SETCOORD_LP | SETCOORD_INHERIT)
   686 #define SETCOORD_LPAH   (SETCOORD_LP | SETCOORD_AH)
   687 #define SETCOORD_LPE    (SETCOORD_LP | SETCOORD_ENUMERATED)
   688 #define SETCOORD_LPEH   (SETCOORD_LPE | SETCOORD_INHERIT)
   689 #define SETCOORD_LPAEH  (SETCOORD_LPAH | SETCOORD_ENUMERATED)
   690 #define SETCOORD_LPO    (SETCOORD_LP | SETCOORD_NONE)
   691 #define SETCOORD_LPOH   (SETCOORD_LPH | SETCOORD_NONE)
   692 #define SETCOORD_LPOEH  (SETCOORD_LPOH | SETCOORD_ENUMERATED)
   693 #define SETCOORD_LE     (SETCOORD_LENGTH | SETCOORD_ENUMERATED)
   694 #define SETCOORD_LEH    (SETCOORD_LE | SETCOORD_INHERIT)
   695 #define SETCOORD_IA     (SETCOORD_INTEGER | SETCOORD_AUTO)
   696 #define SETCOORD_LAE    (SETCOORD_LENGTH | SETCOORD_AUTO | SETCOORD_ENUMERATED)
   698 // changes aCoord iff it returns true
   699 static bool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
   700                        const nsStyleCoord& aParentCoord,
   701                        int32_t aMask, nsStyleContext* aStyleContext,
   702                        nsPresContext* aPresContext,
   703                        bool& aCanStoreInRuleTree)
   704 {
   705   bool result = true;
   706   if (aValue.GetUnit() == eCSSUnit_Null) {
   707     result = false;
   708   }
   709   else if ((((aMask & SETCOORD_LENGTH) != 0) &&
   710             aValue.IsLengthUnit()) ||
   711            (((aMask & SETCOORD_CALC_LENGTH_ONLY) != 0) &&
   712             aValue.IsCalcUnit())) {
   713     nscoord len = CalcLength(aValue, aStyleContext, aPresContext,
   714                              aCanStoreInRuleTree);
   715     if ((aMask & SETCOORD_CALC_CLAMP_NONNEGATIVE) && len < 0) {
   716       NS_ASSERTION(aValue.IsCalcUnit(),
   717                    "parser should have ensured no nonnegative lengths");
   718       len = 0;
   719     }
   720     aCoord.SetCoordValue(len);
   721   }
   722   else if (((aMask & SETCOORD_PERCENT) != 0) &&
   723            (aValue.GetUnit() == eCSSUnit_Percent)) {
   724     aCoord.SetPercentValue(aValue.GetPercentValue());
   725   }
   726   else if (((aMask & SETCOORD_INTEGER) != 0) &&
   727            (aValue.GetUnit() == eCSSUnit_Integer)) {
   728     aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Integer);
   729   }
   730   else if (((aMask & SETCOORD_ENUMERATED) != 0) &&
   731            (aValue.GetUnit() == eCSSUnit_Enumerated)) {
   732     aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Enumerated);
   733   }
   734   else if (((aMask & SETCOORD_BOX_POSITION) != 0) &&
   735            (aValue.GetUnit() == eCSSUnit_Enumerated)) {
   736     aCoord.SetPercentValue(GetFloatFromBoxPosition(aValue.GetIntValue()));
   737   }
   738   else if (((aMask & SETCOORD_AUTO) != 0) &&
   739            (aValue.GetUnit() == eCSSUnit_Auto)) {
   740     aCoord.SetAutoValue();
   741   }
   742   else if ((((aMask & SETCOORD_INHERIT) != 0) &&
   743             aValue.GetUnit() == eCSSUnit_Inherit) ||
   744            (((aMask & SETCOORD_UNSET_INHERIT) != 0) &&
   745             aValue.GetUnit() == eCSSUnit_Unset)) {
   746     aCoord = aParentCoord;  // just inherit value from parent
   747     aCanStoreInRuleTree = false;
   748   }
   749   else if (((aMask & SETCOORD_NORMAL) != 0) &&
   750            (aValue.GetUnit() == eCSSUnit_Normal)) {
   751     aCoord.SetNormalValue();
   752   }
   753   else if (((aMask & SETCOORD_NONE) != 0) &&
   754            (aValue.GetUnit() == eCSSUnit_None)) {
   755     aCoord.SetNoneValue();
   756   }
   757   else if (((aMask & SETCOORD_FACTOR) != 0) &&
   758            (aValue.GetUnit() == eCSSUnit_Number)) {
   759     aCoord.SetFactorValue(aValue.GetFloatValue());
   760   }
   761   else if (((aMask & SETCOORD_STORE_CALC) != 0) &&
   762            (aValue.IsCalcUnit())) {
   763     SpecifiedCalcToComputedCalc(aValue, aCoord, aStyleContext,
   764                                 aCanStoreInRuleTree);
   765   }
   766   else if (aValue.GetUnit() == eCSSUnit_Initial ||
   767            (aValue.GetUnit() == eCSSUnit_Unset &&
   768             ((aMask & SETCOORD_UNSET_INITIAL) != 0))) {
   769     if ((aMask & SETCOORD_INITIAL_AUTO) != 0) {
   770       aCoord.SetAutoValue();
   771     }
   772     else if ((aMask & SETCOORD_INITIAL_ZERO) != 0) {
   773       aCoord.SetCoordValue(0);
   774     }
   775     else if ((aMask & SETCOORD_INITIAL_FACTOR_ZERO) != 0) {
   776       aCoord.SetFactorValue(0.0f);
   777     }
   778     else if ((aMask & SETCOORD_INITIAL_NONE) != 0) {
   779       aCoord.SetNoneValue();
   780     }
   781     else if ((aMask & SETCOORD_INITIAL_NORMAL) != 0) {
   782       aCoord.SetNormalValue();
   783     }
   784     else if ((aMask & SETCOORD_INITIAL_HALF) != 0) {
   785       aCoord.SetPercentValue(0.5f);
   786     }
   787     else if ((aMask & SETCOORD_INITIAL_HUNDRED_PCT) != 0) {
   788       aCoord.SetPercentValue(1.0f);
   789     }
   790     else if ((aMask & SETCOORD_INITIAL_FACTOR_ONE) != 0) {
   791       aCoord.SetFactorValue(1.0f);
   792     }
   793     else {
   794       result = false;  // didn't set anything
   795     }
   796   }
   797   else if ((aMask & SETCOORD_ANGLE) != 0 &&
   798            (aValue.IsAngularUnit())) {
   799     nsStyleUnit unit;
   800     switch (aValue.GetUnit()) {
   801       case eCSSUnit_Degree: unit = eStyleUnit_Degree; break;
   802       case eCSSUnit_Grad:   unit = eStyleUnit_Grad; break;
   803       case eCSSUnit_Radian: unit = eStyleUnit_Radian; break;
   804       case eCSSUnit_Turn:   unit = eStyleUnit_Turn; break;
   805       default: NS_NOTREACHED("unrecognized angular unit");
   806         unit = eStyleUnit_Degree;
   807     }
   808     aCoord.SetAngleValue(aValue.GetAngleValue(), unit);
   809   }
   810   else {
   811     result = false;  // didn't set anything
   812   }
   813   return result;
   814 }
   816 // This inline function offers a shortcut for SetCoord() by refusing to accept
   817 // SETCOORD_LENGTH, SETCOORD_INHERIT and SETCOORD_UNSET_* masks.
   818 static inline bool SetAbsCoord(const nsCSSValue& aValue,
   819                                  nsStyleCoord& aCoord,
   820                                  int32_t aMask)
   821 {
   822   NS_ABORT_IF_FALSE((aMask & (SETCOORD_LH | SETCOORD_UNSET_INHERIT |
   823                               SETCOORD_UNSET_INITIAL)) == 0,
   824                     "does not handle SETCOORD_LENGTH, SETCOORD_INHERIT and "
   825                     "SETCOORD_UNSET_*");
   827   // The values of the following variables will never be used; so it does not
   828   // matter what to set.
   829   const nsStyleCoord dummyParentCoord;
   830   nsStyleContext* dummyStyleContext = nullptr;
   831   nsPresContext* dummyPresContext = nullptr;
   832   bool dummyCanStoreInRuleTree = true;
   834   bool rv = SetCoord(aValue, aCoord, dummyParentCoord, aMask,
   835                        dummyStyleContext, dummyPresContext,
   836                        dummyCanStoreInRuleTree);
   837   NS_ABORT_IF_FALSE(dummyCanStoreInRuleTree,
   838                     "SetCoord() should not modify dummyCanStoreInRuleTree.");
   840   return rv;
   841 }
   843 /* Given a specified value that might be a pair value, call SetCoord twice,
   844  * either using each member of the pair, or using the unpaired value twice.
   845  */
   846 static bool
   847 SetPairCoords(const nsCSSValue& aValue,
   848               nsStyleCoord& aCoordX, nsStyleCoord& aCoordY,
   849               const nsStyleCoord& aParentX, const nsStyleCoord& aParentY,
   850               int32_t aMask, nsStyleContext* aStyleContext,
   851               nsPresContext* aPresContext, bool& aCanStoreInRuleTree)
   852 {
   853   const nsCSSValue& valX =
   854     aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mXValue : aValue;
   855   const nsCSSValue& valY =
   856     aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mYValue : aValue;
   858   bool cX = SetCoord(valX, aCoordX, aParentX, aMask, aStyleContext,
   859                        aPresContext, aCanStoreInRuleTree);
   860   mozilla::DebugOnly<bool> cY = SetCoord(valY, aCoordY, aParentY, aMask, 
   861                        aStyleContext, aPresContext, aCanStoreInRuleTree);
   862   NS_ABORT_IF_FALSE(cX == cY, "changed one but not the other");
   863   return cX;
   864 }
   866 static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
   867                        nsPresContext* aPresContext, nsStyleContext *aContext,
   868                        nscolor& aResult, bool& aCanStoreInRuleTree)
   869 {
   870   bool    result = false;
   871   nsCSSUnit unit = aValue.GetUnit();
   873   if (aValue.IsNumericColorUnit()) {
   874     aResult = aValue.GetColorValue();
   875     result = true;
   876   }
   877   else if (eCSSUnit_Ident == unit) {
   878     nsAutoString  value;
   879     aValue.GetStringValue(value);
   880     nscolor rgba;
   881     if (NS_ColorNameToRGB(value, &rgba)) {
   882       aResult = rgba;
   883       result = true;
   884     }
   885   }
   886   else if (eCSSUnit_EnumColor == unit) {
   887     int32_t intValue = aValue.GetIntValue();
   888     if (0 <= intValue) {
   889       LookAndFeel::ColorID colorID = (LookAndFeel::ColorID) intValue;
   890       bool useStandinsForNativeColors = aPresContext &&
   891                                         !aPresContext->IsChrome();
   892       if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID,
   893                                     useStandinsForNativeColors, &aResult))) {
   894         result = true;
   895       }
   896     }
   897     else {
   898       aResult = NS_RGB(0, 0, 0);
   899       result = false;
   900       switch (intValue) {
   901         case NS_COLOR_MOZ_HYPERLINKTEXT:
   902           if (aPresContext) {
   903             aResult = aPresContext->DefaultLinkColor();
   904             result = true;
   905           }
   906           break;
   907         case NS_COLOR_MOZ_VISITEDHYPERLINKTEXT:
   908           if (aPresContext) {
   909             aResult = aPresContext->DefaultVisitedLinkColor();
   910             result = true;
   911           }
   912           break;
   913         case NS_COLOR_MOZ_ACTIVEHYPERLINKTEXT:
   914           if (aPresContext) {
   915             aResult = aPresContext->DefaultActiveLinkColor();
   916             result = true;
   917           }
   918           break;
   919         case NS_COLOR_CURRENTCOLOR:
   920           // The data computed from this can't be shared in the rule tree
   921           // because they could be used on a node with a different color
   922           aCanStoreInRuleTree = false;
   923           if (aContext) {
   924             aResult = aContext->StyleColor()->mColor;
   925             result = true;
   926           }
   927           break;
   928         case NS_COLOR_MOZ_DEFAULT_COLOR:
   929           if (aPresContext) {
   930             aResult = aPresContext->DefaultColor();
   931             result = true;
   932           }
   933           break;
   934         case NS_COLOR_MOZ_DEFAULT_BACKGROUND_COLOR:
   935           if (aPresContext) {
   936             aResult = aPresContext->DefaultBackgroundColor();
   937             result = true;
   938           }
   939           break;
   940         default:
   941           NS_NOTREACHED("Should never have an unknown negative colorID.");
   942           break;
   943       }
   944     }
   945   }
   946   else if (eCSSUnit_Inherit == unit) {
   947     aResult = aParentColor;
   948     result = true;
   949     aCanStoreInRuleTree = false;
   950   }
   951   else if (eCSSUnit_Enumerated == unit &&
   952            aValue.GetIntValue() == NS_STYLE_COLOR_INHERIT_FROM_BODY) {
   953     NS_ASSERTION(aPresContext->CompatibilityMode() == eCompatibility_NavQuirks,
   954                  "Should only get this value in quirks mode");
   955     // We just grab the color from the prescontext, and rely on the fact that
   956     // if the body color ever changes all its descendants will get new style
   957     // contexts (but NOT necessarily new rulenodes).
   958     aResult = aPresContext->BodyTextColor();
   959     result = true;
   960     aCanStoreInRuleTree = false;
   961   }
   962   return result;
   963 }
   965 static void SetGradientCoord(const nsCSSValue& aValue, nsPresContext* aPresContext,
   966                              nsStyleContext* aContext, nsStyleCoord& aResult,
   967                              bool& aCanStoreInRuleTree)
   968 {
   969   // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
   970   if (!SetCoord(aValue, aResult, nsStyleCoord(),
   971                 SETCOORD_LPO | SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC,
   972                 aContext, aPresContext, aCanStoreInRuleTree)) {
   973     NS_NOTREACHED("unexpected unit for gradient anchor point");
   974     aResult.SetNoneValue();
   975   }
   976 }
   978 static void SetGradient(const nsCSSValue& aValue, nsPresContext* aPresContext,
   979                         nsStyleContext* aContext, nsStyleGradient& aResult,
   980                         bool& aCanStoreInRuleTree)
   981 {
   982   NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Gradient,
   983                     "The given data is not a gradient");
   985   const nsCSSValueGradient* gradient = aValue.GetGradientValue();
   987   if (gradient->mIsExplicitSize) {
   988     SetCoord(gradient->GetRadiusX(), aResult.mRadiusX, nsStyleCoord(),
   989              SETCOORD_LP | SETCOORD_STORE_CALC,
   990              aContext, aPresContext, aCanStoreInRuleTree);
   991     if (gradient->GetRadiusY().GetUnit() != eCSSUnit_None) {
   992       SetCoord(gradient->GetRadiusY(), aResult.mRadiusY, nsStyleCoord(),
   993                SETCOORD_LP | SETCOORD_STORE_CALC,
   994                aContext, aPresContext, aCanStoreInRuleTree);
   995       aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
   996     } else {
   997       aResult.mRadiusY = aResult.mRadiusX;
   998       aResult.mShape = NS_STYLE_GRADIENT_SHAPE_CIRCULAR;
   999     }
  1000     aResult.mSize = NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE;
  1001   } else if (gradient->mIsRadial) {
  1002     if (gradient->GetRadialShape().GetUnit() == eCSSUnit_Enumerated) {
  1003       aResult.mShape = gradient->GetRadialShape().GetIntValue();
  1004     } else {
  1005       NS_ASSERTION(gradient->GetRadialShape().GetUnit() == eCSSUnit_None,
  1006                    "bad unit for radial shape");
  1007       aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
  1009     if (gradient->GetRadialSize().GetUnit() == eCSSUnit_Enumerated) {
  1010       aResult.mSize = gradient->GetRadialSize().GetIntValue();
  1011     } else {
  1012       NS_ASSERTION(gradient->GetRadialSize().GetUnit() == eCSSUnit_None,
  1013                    "bad unit for radial shape");
  1014       aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
  1016   } else {
  1017     NS_ASSERTION(gradient->GetRadialShape().GetUnit() == eCSSUnit_None,
  1018                  "bad unit for linear shape");
  1019     NS_ASSERTION(gradient->GetRadialSize().GetUnit() == eCSSUnit_None,
  1020                  "bad unit for linear size");
  1021     aResult.mShape = NS_STYLE_GRADIENT_SHAPE_LINEAR;
  1022     aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
  1025   aResult.mLegacySyntax = gradient->mIsLegacySyntax;
  1027   // bg-position
  1028   SetGradientCoord(gradient->mBgPos.mXValue, aPresContext, aContext,
  1029                    aResult.mBgPosX, aCanStoreInRuleTree);
  1031   SetGradientCoord(gradient->mBgPos.mYValue, aPresContext, aContext,
  1032                    aResult.mBgPosY, aCanStoreInRuleTree);
  1034   aResult.mRepeating = gradient->mIsRepeating;
  1036   // angle
  1037   const nsStyleCoord dummyParentCoord;
  1038   if (!SetCoord(gradient->mAngle, aResult.mAngle, dummyParentCoord, SETCOORD_ANGLE,
  1039                 aContext, aPresContext, aCanStoreInRuleTree)) {
  1040     NS_ASSERTION(gradient->mAngle.GetUnit() == eCSSUnit_None,
  1041                  "bad unit for gradient angle");
  1042     aResult.mAngle.SetNoneValue();
  1045   // stops
  1046   for (uint32_t i = 0; i < gradient->mStops.Length(); i++) {
  1047     nsStyleGradientStop stop;
  1048     const nsCSSValueGradientStop &valueStop = gradient->mStops[i];
  1050     if (!SetCoord(valueStop.mLocation, stop.mLocation,
  1051                   nsStyleCoord(), SETCOORD_LPO | SETCOORD_STORE_CALC,
  1052                   aContext, aPresContext, aCanStoreInRuleTree)) {
  1053       NS_NOTREACHED("unexpected unit for gradient stop location");
  1056     // inherit is not a valid color for stops, so we pass in a dummy
  1057     // parent color
  1058     NS_ASSERTION(valueStop.mColor.GetUnit() != eCSSUnit_Inherit,
  1059                  "inherit is not a valid color for gradient stops");
  1060     SetColor(valueStop.mColor, NS_RGB(0, 0, 0), aPresContext,
  1061              aContext, stop.mColor, aCanStoreInRuleTree);
  1063     aResult.mStops.AppendElement(stop);
  1067 // -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
  1068 static void SetStyleImageToImageRect(nsStyleContext* aStyleContext,
  1069                                      const nsCSSValue& aValue,
  1070                                      nsStyleImage& aResult)
  1072   NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Function &&
  1073                     aValue.EqualsFunction(eCSSKeyword__moz_image_rect),
  1074                     "the value is not valid -moz-image-rect()");
  1076   nsCSSValue::Array* arr = aValue.GetArrayValue();
  1077   NS_ABORT_IF_FALSE(arr && arr->Count() == 6, "invalid number of arguments");
  1079   // <uri>
  1080   if (arr->Item(1).GetUnit() == eCSSUnit_Image) {
  1081     NS_SET_IMAGE_REQUEST_WITH_DOC(aResult.SetImageData,
  1082                                   aStyleContext,
  1083                                   arr->Item(1).GetImageValue)
  1084   } else {
  1085     NS_WARNING("nsCSSValue::Image::Image() failed?");
  1088   // <top>, <right>, <bottom>, <left>
  1089   nsStyleSides cropRect;
  1090   NS_FOR_CSS_SIDES(side) {
  1091     nsStyleCoord coord;
  1092     const nsCSSValue& val = arr->Item(2 + side);
  1094 #ifdef DEBUG
  1095     bool unitOk =
  1096 #endif
  1097       SetAbsCoord(val, coord, SETCOORD_FACTOR | SETCOORD_PERCENT);
  1098     NS_ABORT_IF_FALSE(unitOk, "Incorrect data structure created by CSS parser");
  1099     cropRect.Set(side, coord);
  1101   aResult.SetCropRect(&cropRect);
  1104 static void SetStyleImage(nsStyleContext* aStyleContext,
  1105                           const nsCSSValue& aValue,
  1106                           nsStyleImage& aResult,
  1107                           bool& aCanStoreInRuleTree)
  1109   if (aValue.GetUnit() == eCSSUnit_Null) {
  1110     return;
  1113   aResult.SetNull();
  1115   switch (aValue.GetUnit()) {
  1116     case eCSSUnit_Image:
  1117       NS_SET_IMAGE_REQUEST_WITH_DOC(aResult.SetImageData,
  1118                                     aStyleContext,
  1119                                     aValue.GetImageValue)
  1120       break;
  1121     case eCSSUnit_Function:
  1122       if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
  1123         SetStyleImageToImageRect(aStyleContext, aValue, aResult);
  1124       } else {
  1125         NS_NOTREACHED("-moz-image-rect() is the only expected function");
  1127       break;
  1128     case eCSSUnit_Gradient:
  1130       nsStyleGradient* gradient = new nsStyleGradient();
  1131       if (gradient) {
  1132         SetGradient(aValue, aStyleContext->PresContext(), aStyleContext,
  1133                     *gradient, aCanStoreInRuleTree);
  1134         aResult.SetGradientData(gradient);
  1136       break;
  1138     case eCSSUnit_Element:
  1139       aResult.SetElementId(aValue.GetStringBufferValue());
  1140       break;
  1141     case eCSSUnit_Initial:
  1142     case eCSSUnit_Unset:
  1143     case eCSSUnit_None:
  1144       break;
  1145     default:
  1146       // We might have eCSSUnit_URL values for if-visited style
  1147       // contexts, which we can safely treat like 'none'.  Otherwise
  1148       // this is an unexpected unit.
  1149       NS_ASSERTION(aStyleContext->IsStyleIfVisited() &&
  1150                    aValue.GetUnit() == eCSSUnit_URL,
  1151                    "unexpected unit; maybe nsCSSValue::Image::Image() failed?");
  1152       break;
  1156 // flags for SetDiscrete - align values with SETCOORD_* constants
  1157 // where possible
  1159 #define SETDSC_NORMAL                 0x01   // N
  1160 #define SETDSC_AUTO                   0x02   // A
  1161 #define SETDSC_INTEGER                0x40   // I
  1162 #define SETDSC_ENUMERATED             0x80   // E
  1163 #define SETDSC_NONE                   0x100  // O
  1164 #define SETDSC_SYSTEM_FONT            0x2000
  1165 #define SETDSC_UNSET_INHERIT          0x00400000
  1166 #define SETDSC_UNSET_INITIAL          0x00800000
  1168 // no caller cares whether aField was changed or not
  1169 template <typename FieldT,
  1170           typename T1, typename T2, typename T3, typename T4, typename T5>
  1171 static void
  1172 SetDiscrete(const nsCSSValue& aValue, FieldT & aField,
  1173             bool& aCanStoreInRuleTree, uint32_t aMask,
  1174             FieldT aParentValue,
  1175             T1 aInitialValue,
  1176             T2 aAutoValue,
  1177             T3 aNoneValue,
  1178             T4 aNormalValue,
  1179             T5 aSystemFontValue)
  1181   switch (aValue.GetUnit()) {
  1182   case eCSSUnit_Null:
  1183     return;
  1185     // every caller of SetDiscrete provides inherit and initial
  1186     // alternatives, so we don't require them to say so in the mask
  1187   case eCSSUnit_Inherit:
  1188     aCanStoreInRuleTree = false;
  1189     aField = aParentValue;
  1190     return;
  1192   case eCSSUnit_Initial:
  1193     aField = aInitialValue;
  1194     return;
  1196     // every caller provides one or other of these alternatives,
  1197     // but they have to say which
  1198   case eCSSUnit_Enumerated:
  1199     if (aMask & SETDSC_ENUMERATED) {
  1200       aField = aValue.GetIntValue();
  1201       return;
  1203     break;
  1205   case eCSSUnit_Integer:
  1206     if (aMask & SETDSC_INTEGER) {
  1207       aField = aValue.GetIntValue();
  1208       return;
  1210     break;
  1212     // remaining possibilities in descending order of frequency of use
  1213   case eCSSUnit_Auto:
  1214     if (aMask & SETDSC_AUTO) {
  1215       aField = aAutoValue;
  1216       return;
  1218     break;
  1220   case eCSSUnit_None:
  1221     if (aMask & SETDSC_NONE) {
  1222       aField = aNoneValue;
  1223       return;
  1225     break;
  1227   case eCSSUnit_Normal:
  1228     if (aMask & SETDSC_NORMAL) {
  1229       aField = aNormalValue;
  1230       return;
  1232     break;
  1234   case eCSSUnit_System_Font:
  1235     if (aMask & SETDSC_SYSTEM_FONT) {
  1236       aField = aSystemFontValue;
  1237       return;
  1239     break;
  1241   case eCSSUnit_Unset:
  1242     if (aMask & SETDSC_UNSET_INHERIT) {
  1243       aCanStoreInRuleTree = false;
  1244       aField = aParentValue;
  1245       return;
  1247     if (aMask & SETDSC_UNSET_INITIAL) {
  1248       aField = aInitialValue;
  1249       return;
  1251     break;
  1253   default:
  1254     break;
  1257   NS_NOTREACHED("SetDiscrete: inappropriate unit");
  1260 // flags for SetFactor
  1261 #define SETFCT_POSITIVE 0x01        // assert value is >= 0.0f
  1262 #define SETFCT_OPACITY  0x02        // clamp value to [0.0f .. 1.0f]
  1263 #define SETFCT_NONE     0x04        // allow _None (uses aInitialValue).
  1264 #define SETFCT_UNSET_INHERIT  0x00400000
  1265 #define SETFCT_UNSET_INITIAL  0x00800000
  1267 static void
  1268 SetFactor(const nsCSSValue& aValue, float& aField, bool& aCanStoreInRuleTree,
  1269           float aParentValue, float aInitialValue, uint32_t aFlags = 0)
  1271   switch (aValue.GetUnit()) {
  1272   case eCSSUnit_Null:
  1273     return;
  1275   case eCSSUnit_Number:
  1276     aField = aValue.GetFloatValue();
  1277     if (aFlags & SETFCT_POSITIVE) {
  1278       NS_ASSERTION(aField >= 0.0f, "negative value for positive-only property");
  1279       if (aField < 0.0f)
  1280         aField = 0.0f;
  1282     if (aFlags & SETFCT_OPACITY) {
  1283       if (aField < 0.0f)
  1284         aField = 0.0f;
  1285       if (aField > 1.0f)
  1286         aField = 1.0f;
  1288     return;
  1290   case eCSSUnit_Inherit:
  1291     aCanStoreInRuleTree = false;
  1292     aField = aParentValue;
  1293     return;
  1295   case eCSSUnit_Initial:
  1296     aField = aInitialValue;
  1297     return;
  1299   case eCSSUnit_None:
  1300     if (aFlags & SETFCT_NONE) {
  1301       aField = aInitialValue;
  1302       return;
  1304     break;
  1306   case eCSSUnit_Unset:
  1307     if (aFlags & SETFCT_UNSET_INHERIT) {
  1308       aCanStoreInRuleTree = false;
  1309       aField = aParentValue;
  1310       return;
  1312     if (aFlags & SETFCT_UNSET_INITIAL) {
  1313       aField = aInitialValue;
  1314       return;
  1316     break;
  1318   default:
  1319     break;
  1322   NS_NOTREACHED("SetFactor: inappropriate unit");
  1325 // Overloaded new operator. Initializes the memory to 0 and relies on an arena
  1326 // (which comes from the presShell) to perform the allocation.
  1327 void*
  1328 nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
  1330   // Check the recycle list first.
  1331   return aPresContext->PresShell()->AllocateByObjectID(nsPresArena::nsRuleNode_id, sz);
  1334 /* static */ PLDHashOperator
  1335 nsRuleNode::EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
  1336                                     uint32_t number, void *arg)
  1338   ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
  1339   nsRuleNode ***destroyQueueTail = static_cast<nsRuleNode***>(arg);
  1340   **destroyQueueTail = entry->mRuleNode;
  1341   *destroyQueueTail = &entry->mRuleNode->mNextSibling;
  1342   return PL_DHASH_NEXT;
  1345 // Overridden to prevent the global delete from being called, since the memory
  1346 // came out of an nsIArena instead of the global delete operator's heap.
  1347 void
  1348 nsRuleNode::DestroyInternal(nsRuleNode ***aDestroyQueueTail)
  1350   nsRuleNode *destroyQueue, **destroyQueueTail;
  1351   if (aDestroyQueueTail) {
  1352     destroyQueueTail = *aDestroyQueueTail;
  1353   } else {
  1354     destroyQueue = nullptr;
  1355     destroyQueueTail = &destroyQueue;
  1358   if (ChildrenAreHashed()) {
  1359     PLDHashTable *children = ChildrenHash();
  1360     PL_DHashTableEnumerate(children, EnqueueRuleNodeChildren,
  1361                            &destroyQueueTail);
  1362     *destroyQueueTail = nullptr; // ensure null-termination
  1363     PL_DHashTableDestroy(children);
  1364   } else if (HaveChildren()) {
  1365     *destroyQueueTail = ChildrenList();
  1366     do {
  1367       destroyQueueTail = &(*destroyQueueTail)->mNextSibling;
  1368     } while (*destroyQueueTail);
  1370   mChildren.asVoid = nullptr;
  1372   if (aDestroyQueueTail) {
  1373     // Our caller destroys the queue.
  1374     *aDestroyQueueTail = destroyQueueTail;
  1375   } else {
  1376     // We have to do destroy the queue.  When we destroy each node, it
  1377     // will add its children to the queue.
  1378     while (destroyQueue) {
  1379       nsRuleNode *cur = destroyQueue;
  1380       destroyQueue = destroyQueue->mNextSibling;
  1381       if (!destroyQueue) {
  1382         NS_ASSERTION(destroyQueueTail == &cur->mNextSibling, "mangled list");
  1383         destroyQueueTail = &destroyQueue;
  1385       cur->DestroyInternal(&destroyQueueTail);
  1389   // Destroy ourselves.
  1390   this->~nsRuleNode();
  1392   // Don't let the memory be freed, since it will be recycled
  1393   // instead. Don't call the global operator delete.
  1394   mPresContext->PresShell()->FreeByObjectID(nsPresArena::nsRuleNode_id, this);
  1397 nsRuleNode* nsRuleNode::CreateRootNode(nsPresContext* aPresContext)
  1399   return new (aPresContext)
  1400     nsRuleNode(aPresContext, nullptr, nullptr, 0xff, false);
  1403 nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
  1404                        nsIStyleRule* aRule, uint8_t aLevel,
  1405                        bool aIsImportant)
  1406   : mPresContext(aContext),
  1407     mParent(aParent),
  1408     mRule(aRule),
  1409     mDependentBits((uint32_t(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
  1410                    (aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
  1411     mNoneBits(0),
  1412     mRefCnt(0)
  1414   MOZ_ASSERT(aContext);
  1415   NS_ABORT_IF_FALSE(IsRoot() == !aRule,
  1416                     "non-root rule nodes must have a rule");
  1418   mChildren.asVoid = nullptr;
  1419   MOZ_COUNT_CTOR(nsRuleNode);
  1421   if (mRule) {
  1422     mRule->AddRef();
  1425   NS_ASSERTION(IsRoot() || GetLevel() == aLevel, "not enough bits");
  1426   NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes");
  1427   /* If IsRoot(), then aContext->StyleSet() is typically null at this
  1428      point.  In any case, we don't want to treat the root rulenode as
  1429      unused.  */
  1430   if (!IsRoot()) {
  1431     mParent->AddRef();
  1432     aContext->StyleSet()->RuleNodeUnused();
  1435   // nsStyleSet::GetContext depends on there being only one animation
  1436   // rule.
  1437   NS_ABORT_IF_FALSE(IsRoot() || GetLevel() != nsStyleSet::eAnimationSheet ||
  1438                     mParent->IsRoot() ||
  1439                     mParent->GetLevel() != nsStyleSet::eAnimationSheet,
  1440                     "must be only one rule at animation level");
  1443 nsRuleNode::~nsRuleNode()
  1445   MOZ_COUNT_DTOR(nsRuleNode);
  1446   if (mStyleData.mResetData || mStyleData.mInheritedData)
  1447     mStyleData.Destroy(mDependentBits, mPresContext);
  1448   if (mRule) {
  1449     mRule->Release();
  1453 nsRuleNode*
  1454 nsRuleNode::Transition(nsIStyleRule* aRule, uint8_t aLevel,
  1455                        bool aIsImportantRule)
  1457   nsRuleNode* next = nullptr;
  1458   nsRuleNode::Key key(aRule, aLevel, aIsImportantRule);
  1460   if (HaveChildren() && !ChildrenAreHashed()) {
  1461     int32_t numKids = 0;
  1462     nsRuleNode* curr = ChildrenList();
  1463     while (curr && curr->GetKey() != key) {
  1464       curr = curr->mNextSibling;
  1465       ++numKids;
  1467     if (curr)
  1468       next = curr;
  1469     else if (numKids >= kMaxChildrenInList)
  1470       ConvertChildrenToHash();
  1473   if (ChildrenAreHashed()) {
  1474     ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>
  1475                                           (PL_DHashTableOperate(ChildrenHash(), &key, PL_DHASH_ADD));
  1476     if (!entry) {
  1477       NS_WARNING("out of memory");
  1478       return this;
  1480     if (entry->mRuleNode)
  1481       next = entry->mRuleNode;
  1482     else {
  1483       next = entry->mRuleNode = new (mPresContext)
  1484         nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
  1485       if (!next) {
  1486         PL_DHashTableRawRemove(ChildrenHash(), entry);
  1487         NS_WARNING("out of memory");
  1488         return this;
  1491   } else if (!next) {
  1492     // Create the new entry in our list.
  1493     next = new (mPresContext)
  1494       nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
  1495     if (!next) {
  1496       NS_WARNING("out of memory");
  1497       return this;
  1499     next->mNextSibling = ChildrenList();
  1500     SetChildrenList(next);
  1503   return next;
  1506 void nsRuleNode::SetUsedDirectly()
  1508   mDependentBits |= NS_RULE_NODE_USED_DIRECTLY;
  1510   // Maintain the invariant that any rule node that is used directly has
  1511   // all structs that live in the rule tree cached (which
  1512   // nsRuleNode::GetStyleData depends on for speed).
  1513   if (mDependentBits & NS_STYLE_INHERIT_MASK) {
  1514     for (nsStyleStructID sid = nsStyleStructID(0); sid < nsStyleStructID_Length;
  1515          sid = nsStyleStructID(sid + 1)) {
  1516       uint32_t bit = nsCachedStyleData::GetBitForSID(sid);
  1517       if (mDependentBits & bit) {
  1518         nsRuleNode *source = mParent;
  1519         while ((source->mDependentBits & bit) && !source->IsUsedDirectly()) {
  1520           source = source->mParent;
  1522         void *data = source->mStyleData.GetStyleData(sid);
  1523         NS_ASSERTION(data, "unexpected null struct");
  1524         mStyleData.SetStyleData(sid, mPresContext, data);
  1530 void
  1531 nsRuleNode::ConvertChildrenToHash()
  1533   NS_ASSERTION(!ChildrenAreHashed() && HaveChildren(),
  1534                "must have a non-empty list of children");
  1535   PLDHashTable *hash = PL_NewDHashTable(&ChildrenHashOps, nullptr,
  1536                                         sizeof(ChildrenHashEntry),
  1537                                         kMaxChildrenInList * 4);
  1538   if (!hash)
  1539     return;
  1540   for (nsRuleNode* curr = ChildrenList(); curr; curr = curr->mNextSibling) {
  1541     // This will never fail because of the initial size we gave the table.
  1542     ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(
  1543       PL_DHashTableOperate(hash, curr->mRule, PL_DHASH_ADD));
  1544     NS_ASSERTION(!entry->mRuleNode, "duplicate entries in list");
  1545     entry->mRuleNode = curr;
  1547   SetChildrenHash(hash);
  1550 inline void
  1551 nsRuleNode::PropagateNoneBit(uint32_t aBit, nsRuleNode* aHighestNode)
  1553   nsRuleNode* curr = this;
  1554   for (;;) {
  1555     NS_ASSERTION(!(curr->mNoneBits & aBit), "propagating too far");
  1556     curr->mNoneBits |= aBit;
  1557     if (curr == aHighestNode)
  1558       break;
  1559     curr = curr->mParent;
  1563 inline void
  1564 nsRuleNode::PropagateDependentBit(nsStyleStructID aSID, nsRuleNode* aHighestNode,
  1565                                   void* aStruct)
  1567   NS_ASSERTION(aStruct, "expected struct");
  1569   uint32_t bit = nsCachedStyleData::GetBitForSID(aSID);
  1570   for (nsRuleNode* curr = this; curr != aHighestNode; curr = curr->mParent) {
  1571     if (curr->mDependentBits & bit) {
  1572 #ifdef DEBUG
  1573       while (curr != aHighestNode) {
  1574         NS_ASSERTION(curr->mDependentBits & bit, "bit not set");
  1575         curr = curr->mParent;
  1577 #endif
  1578       break;
  1581     curr->mDependentBits |= bit;
  1583     if (curr->IsUsedDirectly()) {
  1584       curr->mStyleData.SetStyleData(aSID, mPresContext, aStruct);
  1589 /*
  1590  * The following "Check" functions are used for determining what type of
  1591  * sharing can be used for the data on this rule node.  MORE HERE...
  1592  */
  1594 /*
  1595  * a callback function that that can revise the result of
  1596  * CheckSpecifiedProperties before finishing; aResult is the current
  1597  * result, and it returns the revised one.
  1598  */
  1599 typedef nsRuleNode::RuleDetail
  1600   (* CheckCallbackFn)(const nsRuleData* aRuleData,
  1601                       nsRuleNode::RuleDetail aResult);
  1603 /**
  1604  * @param aValue the value being examined
  1605  * @param aSpecifiedCount to be incremented by one if the value is specified
  1606  * @param aInheritedCount to be incremented by one if the value is set to inherit
  1607  * @param aUnsetCount to be incremented by one if the value is set to unset
  1608  */
  1609 inline void
  1610 ExamineCSSValue(const nsCSSValue& aValue,
  1611                 uint32_t& aSpecifiedCount,
  1612                 uint32_t& aInheritedCount,
  1613                 uint32_t& aUnsetCount)
  1615   if (aValue.GetUnit() != eCSSUnit_Null) {
  1616     ++aSpecifiedCount;
  1617     if (aValue.GetUnit() == eCSSUnit_Inherit) {
  1618       ++aInheritedCount;
  1619     } else if (aValue.GetUnit() == eCSSUnit_Unset) {
  1620       ++aUnsetCount;
  1625 static nsRuleNode::RuleDetail
  1626 CheckFontCallback(const nsRuleData* aRuleData,
  1627                   nsRuleNode::RuleDetail aResult)
  1629   // em, ex, percent, 'larger', and 'smaller' values on font-size depend
  1630   // on the parent context's font-size
  1631   // Likewise, 'lighter' and 'bolder' values of 'font-weight', and 'wider'
  1632   // and 'narrower' values of 'font-stretch' depend on the parent.
  1633   const nsCSSValue& size = *aRuleData->ValueForFontSize();
  1634   const nsCSSValue& weight = *aRuleData->ValueForFontWeight();
  1635   if ((size.IsRelativeLengthUnit() && size.GetUnit() != eCSSUnit_RootEM) ||
  1636       size.GetUnit() == eCSSUnit_Percent ||
  1637       (size.GetUnit() == eCSSUnit_Enumerated &&
  1638        (size.GetIntValue() == NS_STYLE_FONT_SIZE_SMALLER ||
  1639         size.GetIntValue() == NS_STYLE_FONT_SIZE_LARGER)) ||
  1640       aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Integer ||
  1641       (weight.GetUnit() == eCSSUnit_Enumerated &&
  1642        (weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_BOLDER ||
  1643         weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_LIGHTER))) {
  1644     NS_ASSERTION(aResult == nsRuleNode::eRulePartialReset ||
  1645                  aResult == nsRuleNode::eRuleFullReset ||
  1646                  aResult == nsRuleNode::eRulePartialMixed ||
  1647                  aResult == nsRuleNode::eRuleFullMixed,
  1648                  "we know we already have a reset-counted property");
  1649     // Promote reset to mixed since we have something that depends on
  1650     // the parent.  But never promote to inherited since that could
  1651     // cause inheritance of the exact value.
  1652     if (aResult == nsRuleNode::eRulePartialReset)
  1653       aResult = nsRuleNode::eRulePartialMixed;
  1654     else if (aResult == nsRuleNode::eRuleFullReset)
  1655       aResult = nsRuleNode::eRuleFullMixed;
  1658   return aResult;
  1661 static nsRuleNode::RuleDetail
  1662 CheckColorCallback(const nsRuleData* aRuleData,
  1663                    nsRuleNode::RuleDetail aResult)
  1665   // currentColor values for color require inheritance
  1666   const nsCSSValue* colorValue = aRuleData->ValueForColor();
  1667   if (colorValue->GetUnit() == eCSSUnit_EnumColor &&
  1668       colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
  1669     NS_ASSERTION(aResult == nsRuleNode::eRuleFullReset,
  1670                  "we should already be counted as full-reset");
  1671     aResult = nsRuleNode::eRuleFullInherited;
  1674   return aResult;
  1677 static nsRuleNode::RuleDetail
  1678 CheckTextCallback(const nsRuleData* aRuleData,
  1679                   nsRuleNode::RuleDetail aResult)
  1681   const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
  1682   if (textAlignValue->GetUnit() == eCSSUnit_Enumerated &&
  1683       textAlignValue->GetIntValue() ==
  1684         NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT) {
  1685     // Promote reset to mixed since we have something that depends on
  1686     // the parent.
  1687     if (aResult == nsRuleNode::eRulePartialReset)
  1688       aResult = nsRuleNode::eRulePartialMixed;
  1689     else if (aResult == nsRuleNode::eRuleFullReset)
  1690       aResult = nsRuleNode::eRuleFullMixed;
  1693   return aResult;
  1696 static nsRuleNode::RuleDetail
  1697 CheckVariablesCallback(const nsRuleData* aRuleData,
  1698                        nsRuleNode::RuleDetail aResult)
  1700   // We don't actually have any properties on nsStyleVariables, so we do
  1701   // all of the RuleDetail calculation in here.
  1702   if (aRuleData->mVariables) {
  1703     return nsRuleNode::eRulePartialMixed;
  1705   return nsRuleNode::eRuleNone;
  1708 #define FLAG_DATA_FOR_PROPERTY(name_, id_, method_, flags_, pref_,          \
  1709                                parsevariant_, kwtable_, stylestructoffset_, \
  1710                                animtype_)                                   \
  1711   flags_,
  1713 // The order here must match the enums in *CheckCounter in nsCSSProps.cpp.
  1715 static const uint32_t gFontFlags[] = {
  1716 #define CSS_PROP_FONT FLAG_DATA_FOR_PROPERTY
  1717 #include "nsCSSPropList.h"
  1718 #undef CSS_PROP_FONT
  1719 };
  1721 static const uint32_t gDisplayFlags[] = {
  1722 #define CSS_PROP_DISPLAY FLAG_DATA_FOR_PROPERTY
  1723 #include "nsCSSPropList.h"
  1724 #undef CSS_PROP_DISPLAY
  1725 };
  1727 static const uint32_t gVisibilityFlags[] = {
  1728 #define CSS_PROP_VISIBILITY FLAG_DATA_FOR_PROPERTY
  1729 #include "nsCSSPropList.h"
  1730 #undef CSS_PROP_VISIBILITY
  1731 };
  1733 static const uint32_t gMarginFlags[] = {
  1734 #define CSS_PROP_MARGIN FLAG_DATA_FOR_PROPERTY
  1735 #include "nsCSSPropList.h"
  1736 #undef CSS_PROP_MARGIN
  1737 };
  1739 static const uint32_t gBorderFlags[] = {
  1740 #define CSS_PROP_BORDER FLAG_DATA_FOR_PROPERTY
  1741 #include "nsCSSPropList.h"
  1742 #undef CSS_PROP_BORDER
  1743 };
  1745 static const uint32_t gPaddingFlags[] = {
  1746 #define CSS_PROP_PADDING FLAG_DATA_FOR_PROPERTY
  1747 #include "nsCSSPropList.h"
  1748 #undef CSS_PROP_PADDING
  1749 };
  1751 static const uint32_t gOutlineFlags[] = {
  1752 #define CSS_PROP_OUTLINE FLAG_DATA_FOR_PROPERTY
  1753 #include "nsCSSPropList.h"
  1754 #undef CSS_PROP_OUTLINE
  1755 };
  1757 static const uint32_t gListFlags[] = {
  1758 #define CSS_PROP_LIST FLAG_DATA_FOR_PROPERTY
  1759 #include "nsCSSPropList.h"
  1760 #undef CSS_PROP_LIST
  1761 };
  1763 static const uint32_t gColorFlags[] = {
  1764 #define CSS_PROP_COLOR FLAG_DATA_FOR_PROPERTY
  1765 #include "nsCSSPropList.h"
  1766 #undef CSS_PROP_COLOR
  1767 };
  1769 static const uint32_t gBackgroundFlags[] = {
  1770 #define CSS_PROP_BACKGROUND FLAG_DATA_FOR_PROPERTY
  1771 #include "nsCSSPropList.h"
  1772 #undef CSS_PROP_BACKGROUND
  1773 };
  1775 static const uint32_t gPositionFlags[] = {
  1776 #define CSS_PROP_POSITION FLAG_DATA_FOR_PROPERTY
  1777 #include "nsCSSPropList.h"
  1778 #undef CSS_PROP_POSITION
  1779 };
  1781 static const uint32_t gTableFlags[] = {
  1782 #define CSS_PROP_TABLE FLAG_DATA_FOR_PROPERTY
  1783 #include "nsCSSPropList.h"
  1784 #undef CSS_PROP_TABLE
  1785 };
  1787 static const uint32_t gTableBorderFlags[] = {
  1788 #define CSS_PROP_TABLEBORDER FLAG_DATA_FOR_PROPERTY
  1789 #include "nsCSSPropList.h"
  1790 #undef CSS_PROP_TABLEBORDER
  1791 };
  1793 static const uint32_t gContentFlags[] = {
  1794 #define CSS_PROP_CONTENT FLAG_DATA_FOR_PROPERTY
  1795 #include "nsCSSPropList.h"
  1796 #undef CSS_PROP_CONTENT
  1797 };
  1799 static const uint32_t gQuotesFlags[] = {
  1800 #define CSS_PROP_QUOTES FLAG_DATA_FOR_PROPERTY
  1801 #include "nsCSSPropList.h"
  1802 #undef CSS_PROP_QUOTES
  1803 };
  1805 static const uint32_t gTextFlags[] = {
  1806 #define CSS_PROP_TEXT FLAG_DATA_FOR_PROPERTY
  1807 #include "nsCSSPropList.h"
  1808 #undef CSS_PROP_TEXT
  1809 };
  1811 static const uint32_t gTextResetFlags[] = {
  1812 #define CSS_PROP_TEXTRESET FLAG_DATA_FOR_PROPERTY
  1813 #include "nsCSSPropList.h"
  1814 #undef CSS_PROP_TEXTRESET
  1815 };
  1817 static const uint32_t gUserInterfaceFlags[] = {
  1818 #define CSS_PROP_USERINTERFACE FLAG_DATA_FOR_PROPERTY
  1819 #include "nsCSSPropList.h"
  1820 #undef CSS_PROP_USERINTERFACE
  1821 };
  1823 static const uint32_t gUIResetFlags[] = {
  1824 #define CSS_PROP_UIRESET FLAG_DATA_FOR_PROPERTY
  1825 #include "nsCSSPropList.h"
  1826 #undef CSS_PROP_UIRESET
  1827 };
  1829 static const uint32_t gXULFlags[] = {
  1830 #define CSS_PROP_XUL FLAG_DATA_FOR_PROPERTY
  1831 #include "nsCSSPropList.h"
  1832 #undef CSS_PROP_XUL
  1833 };
  1835 static const uint32_t gSVGFlags[] = {
  1836 #define CSS_PROP_SVG FLAG_DATA_FOR_PROPERTY
  1837 #include "nsCSSPropList.h"
  1838 #undef CSS_PROP_SVG
  1839 };
  1841 static const uint32_t gSVGResetFlags[] = {
  1842 #define CSS_PROP_SVGRESET FLAG_DATA_FOR_PROPERTY
  1843 #include "nsCSSPropList.h"
  1844 #undef CSS_PROP_SVGRESET
  1845 };
  1847 static const uint32_t gColumnFlags[] = {
  1848 #define CSS_PROP_COLUMN FLAG_DATA_FOR_PROPERTY
  1849 #include "nsCSSPropList.h"
  1850 #undef CSS_PROP_COLUMN
  1851 };
  1853 // There are no properties in nsStyleVariables, but we can't have a
  1854 // zero length array.
  1855 static const uint32_t gVariablesFlags[] = {
  1856   0,
  1857 #define CSS_PROP_VARIABLES FLAG_DATA_FOR_PROPERTY
  1858 #include "nsCSSPropList.h"
  1859 #undef CSS_PROP_VARIABLES
  1860 };
  1861 static_assert(sizeof(gVariablesFlags) == sizeof(uint32_t),
  1862               "if nsStyleVariables has properties now you can remove the dummy "
  1863               "gVariablesFlags entry");
  1865 #undef FLAG_DATA_FOR_PROPERTY
  1867 static const uint32_t* gFlagsByStruct[] = {
  1869 #define STYLE_STRUCT(name, checkdata_cb) \
  1870   g##name##Flags,
  1871 #include "nsStyleStructList.h"
  1872 #undef STYLE_STRUCT
  1874 };
  1876 static const CheckCallbackFn gCheckCallbacks[] = {
  1878 #define STYLE_STRUCT(name, checkdata_cb) \
  1879   checkdata_cb,
  1880 #include "nsStyleStructList.h"
  1881 #undef STYLE_STRUCT
  1883 };
  1885 #ifdef DEBUG
  1886 static bool
  1887 AreAllMathMLPropertiesUndefined(const nsRuleData* aRuleData)
  1889   return
  1890     aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Null &&
  1891     aRuleData->ValueForScriptSizeMultiplier()->GetUnit() == eCSSUnit_Null &&
  1892     aRuleData->ValueForScriptMinSize()->GetUnit() == eCSSUnit_Null &&
  1893     aRuleData->ValueForMathVariant()->GetUnit() == eCSSUnit_Null &&
  1894     aRuleData->ValueForMathDisplay()->GetUnit() == eCSSUnit_Null;
  1896 #endif
  1898 inline nsRuleNode::RuleDetail
  1899 nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID,
  1900                                      const nsRuleData* aRuleData)
  1902   // Build a count of the:
  1903   uint32_t total = 0,      // total number of props in the struct
  1904            specified = 0,  // number that were specified for this node
  1905            inherited = 0,  // number that were 'inherit' (and not
  1906                            //   eCSSUnit_Inherit) for this node
  1907            unset = 0;      // number that were 'unset'
  1909   // See comment in nsRuleData.h above mValueOffsets.
  1910   NS_ABORT_IF_FALSE(aRuleData->mValueOffsets[aSID] == 0,
  1911                     "we assume the value offset is zero instead of adding it");
  1912   for (nsCSSValue *values = aRuleData->mValueStorage,
  1913               *values_end = values + nsCSSProps::PropertyCountInStruct(aSID);
  1914        values != values_end; ++values) {
  1915     ++total;
  1916     ExamineCSSValue(*values, specified, inherited, unset);
  1919   if (!nsCachedStyleData::IsReset(aSID)) {
  1920     // For inherited properties, 'unset' means the same as 'inherit'.
  1921     inherited += unset;
  1922     unset = 0;
  1925 #if 0
  1926   printf("CheckSpecifiedProperties: SID=%d total=%d spec=%d inh=%d.\n",
  1927          aSID, total, specified, inherited);
  1928 #endif
  1930   NS_ASSERTION(aSID != eStyleStruct_Font ||
  1931                mPresContext->Document()->GetMathMLEnabled() ||
  1932                AreAllMathMLPropertiesUndefined(aRuleData),
  1933                "MathML style property was defined even though MathML is disabled");
  1935   /*
  1936    * Return the most specific information we can: prefer None or Full
  1937    * over Partial, and Reset or Inherited over Mixed, since we can
  1938    * optimize based on the edge cases and not the in-between cases.
  1939    */
  1940   nsRuleNode::RuleDetail result;
  1941   if (inherited == total)
  1942     result = eRuleFullInherited;
  1943   else if (specified == total
  1944            // MathML defines 5 properties in Font that will never be set when
  1945            // MathML is not in use. Therefore if all but five
  1946            // properties have been set, and MathML is not enabled, we can treat
  1947            // this as fully specified. Code in nsMathMLElementFactory will
  1948            // rebuild the rule tree and style data when MathML is first enabled
  1949            // (see nsMathMLElement::BindToTree).
  1950            || (aSID == eStyleStruct_Font && specified + 5 == total &&
  1951                !mPresContext->Document()->GetMathMLEnabled())
  1952           ) {
  1953     if (inherited == 0)
  1954       result = eRuleFullReset;
  1955     else
  1956       result = eRuleFullMixed;
  1957   } else if (specified == 0)
  1958     result = eRuleNone;
  1959   else if (specified == inherited)
  1960     result = eRulePartialInherited;
  1961   else if (inherited == 0)
  1962     result = eRulePartialReset;
  1963   else
  1964     result = eRulePartialMixed;
  1966   CheckCallbackFn cb = gCheckCallbacks[aSID];
  1967   if (cb) {
  1968     result = (*cb)(aRuleData, result);
  1971   return result;
  1974 // If we need to restrict which properties apply to the style context,
  1975 // return the bit to check in nsCSSProp's flags table.  Otherwise,
  1976 // return 0.
  1977 inline uint32_t
  1978 GetPseudoRestriction(nsStyleContext *aContext)
  1980   // This needs to match nsStyleSet::WalkRestrictionRule.
  1981   uint32_t pseudoRestriction = 0;
  1982   nsIAtom *pseudoType = aContext->GetPseudo();
  1983   if (pseudoType) {
  1984     if (pseudoType == nsCSSPseudoElements::firstLetter) {
  1985       pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LETTER;
  1986     } else if (pseudoType == nsCSSPseudoElements::firstLine) {
  1987       pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LINE;
  1988     } else if (pseudoType == nsCSSPseudoElements::mozPlaceholder) {
  1989       pseudoRestriction = CSS_PROPERTY_APPLIES_TO_PLACEHOLDER;
  1992   return pseudoRestriction;
  1995 static void
  1996 UnsetPropertiesWithoutFlags(const nsStyleStructID aSID,
  1997                             nsRuleData* aRuleData,
  1998                             uint32_t aFlags)
  2000   NS_ASSERTION(aFlags != 0, "aFlags must be nonzero");
  2002   const uint32_t *flagData = gFlagsByStruct[aSID];
  2004   // See comment in nsRuleData.h above mValueOffsets.
  2005   NS_ABORT_IF_FALSE(aRuleData->mValueOffsets[aSID] == 0,
  2006                     "we assume the value offset is zero instead of adding it");
  2007   nsCSSValue *values = aRuleData->mValueStorage;
  2009   for (size_t i = 0, i_end = nsCSSProps::PropertyCountInStruct(aSID);
  2010        i != i_end; ++i) {
  2011     if ((flagData[i] & aFlags) != aFlags)
  2012       values[i].Reset();
  2016 /**
  2017  * We allocate arrays of CSS values with alloca.  (These arrays are a
  2018  * fixed size per style struct, but we don't want to waste the
  2019  * allocation and construction/destruction costs of the big structs when
  2020  * we're handling much smaller ones.)  Since the lifetime of an alloca
  2021  * allocation is the life of the calling function, the caller must call
  2022  * alloca.  However, to ensure that constructors and destructors are
  2023  * balanced, we do the constructor and destructor calling from this RAII
  2024  * class, AutoCSSValueArray.
  2025  */
  2026 struct AutoCSSValueArray {
  2027   /**
  2028    * aStorage must be the result of alloca(aCount * sizeof(nsCSSValue))
  2029    */
  2030   AutoCSSValueArray(void* aStorage, size_t aCount) {
  2031     NS_ABORT_IF_FALSE(size_t(aStorage) % NS_ALIGNMENT_OF(nsCSSValue) == 0,
  2032                       "bad alignment from alloca");
  2033     mCount = aCount;
  2034     // Don't use placement new[], since it might store extra data
  2035     // for the count (on Windows!).
  2036     mArray = static_cast<nsCSSValue*>(aStorage);
  2037     for (size_t i = 0; i < mCount; ++i) {
  2038       new (mArray + i) nsCSSValue();
  2042   ~AutoCSSValueArray() {
  2043     for (size_t i = 0; i < mCount; ++i) {
  2044       mArray[i].~nsCSSValue();
  2048   nsCSSValue* get() { return mArray; }
  2050 private:
  2051   nsCSSValue *mArray;
  2052   size_t mCount;
  2053 };
  2055 /* static */ bool
  2056 nsRuleNode::ResolveVariableReferences(const nsStyleStructID aSID,
  2057                                       nsRuleData* aRuleData,
  2058                                       nsStyleContext* aContext)
  2060   MOZ_ASSERT(aSID != eStyleStruct_Variables);
  2061   MOZ_ASSERT(aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(aSID));
  2062   MOZ_ASSERT(aRuleData->mValueOffsets[aSID] == 0);
  2064   nsCSSParser parser;
  2065   bool anyTokenStreams = false;
  2067   // Look at each property in the nsRuleData for the given style struct.
  2068   size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
  2069   for (nsCSSValue* value = aRuleData->mValueStorage,
  2070                   *values_end = aRuleData->mValueStorage + nprops;
  2071        value != values_end; value++) {
  2072     if (value->GetUnit() != eCSSUnit_TokenStream) {
  2073       continue;
  2076     const CSSVariableValues* variables =
  2077       &aContext->StyleVariables()->mVariables;
  2078     nsCSSValueTokenStream* tokenStream = value->GetTokenStreamValue();
  2080     // Note that ParsePropertyWithVariableReferences relies on the fact
  2081     // that the nsCSSValue in aRuleData for the property we are re-parsing
  2082     // is still the token stream value.  When
  2083     // ParsePropertyWithVariableReferences calls
  2084     // nsCSSExpandedDataBlock::MapRuleInfoInto, that function will add
  2085     // the ImageValue that is created into the token stream object's
  2086     // mImageValues table; see the comment above mImageValues for why.
  2088     // XXX Should pass in sheet here (see bug 952338).
  2089     parser.ParsePropertyWithVariableReferences(
  2090         tokenStream->mPropertyID, tokenStream->mShorthandPropertyID,
  2091         tokenStream->mTokenStream, variables, aRuleData,
  2092         tokenStream->mSheetURI, tokenStream->mBaseURI,
  2093         tokenStream->mSheetPrincipal, nullptr,
  2094         tokenStream->mLineNumber, tokenStream->mLineOffset);
  2095     aRuleData->mCanStoreInRuleTree = false;
  2096     anyTokenStreams = true;
  2099   return anyTokenStreams;
  2102 const void*
  2103 nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
  2104                          nsStyleContext* aContext)
  2106   // use placement new[] on the result of alloca() to allocate a
  2107   // variable-sized stack array, including execution of constructors,
  2108   // and use an RAII class to run the destructors too.
  2109   size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
  2110   void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
  2111   AutoCSSValueArray dataArray(dataStorage, nprops);
  2113   nsRuleData ruleData(nsCachedStyleData::GetBitForSID(aSID),
  2114                       dataArray.get(), mPresContext, aContext);
  2115   ruleData.mValueOffsets[aSID] = 0;
  2117   // We start at the most specific rule in the tree.
  2118   void* startStruct = nullptr;
  2120   nsRuleNode* ruleNode = this;
  2121   nsRuleNode* highestNode = nullptr; // The highest node in the rule tree
  2122                                     // that has the same properties
  2123                                     // specified for struct |aSID| as
  2124                                     // |this| does.
  2125   nsRuleNode* rootNode = this; // After the loop below, this will be the
  2126                                // highest node that we've walked without
  2127                                // finding cached data on the rule tree.
  2128                                // If we don't find any cached data, it
  2129                                // will be the root.  (XXX misnamed)
  2130   RuleDetail detail = eRuleNone;
  2131   uint32_t bit = nsCachedStyleData::GetBitForSID(aSID);
  2133   while (ruleNode) {
  2134     // See if this rule node has cached the fact that the remaining
  2135     // nodes along this path specify no data whatsoever.
  2136     if (ruleNode->mNoneBits & bit)
  2137       break;
  2139     // If the dependent bit is set on a rule node for this struct, that
  2140     // means its rule won't have any information to add, so skip it.
  2141     // NOTE: If we exit the loop because of the !IsUsedDirectly() check,
  2142     // then we're guaranteed to break immediately afterwards due to a
  2143     // non-null startStruct.
  2144     while ((ruleNode->mDependentBits & bit) && !ruleNode->IsUsedDirectly()) {
  2145       NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nullptr,
  2146                    "dependent bit with cached data makes no sense");
  2147       // Climb up to the next rule in the tree (a less specific rule).
  2148       rootNode = ruleNode;
  2149       ruleNode = ruleNode->mParent;
  2150       NS_ASSERTION(!(ruleNode->mNoneBits & bit), "can't have both bits set");
  2153     // Check for cached data after the inner loop above -- otherwise
  2154     // we'll miss it.
  2155     startStruct = ruleNode->mStyleData.GetStyleData(aSID);
  2156     if (startStruct)
  2157       break; // We found a rule with fully specified data.  We don't
  2158              // need to go up the tree any further, since the remainder
  2159              // of this branch has already been computed.
  2161     // Ask the rule to fill in the properties that it specifies.
  2162     nsIStyleRule *rule = ruleNode->mRule;
  2163     if (rule) {
  2164       ruleData.mLevel = ruleNode->GetLevel();
  2165       ruleData.mIsImportantRule = ruleNode->IsImportantRule();
  2166       rule->MapRuleInfoInto(&ruleData);
  2169     // Now we check to see how many properties have been specified by
  2170     // the rules we've examined so far.
  2171     RuleDetail oldDetail = detail;
  2172     detail = CheckSpecifiedProperties(aSID, &ruleData);
  2174     if (oldDetail == eRuleNone && detail != eRuleNone)
  2175       highestNode = ruleNode;
  2177     if (detail == eRuleFullReset ||
  2178         detail == eRuleFullMixed ||
  2179         detail == eRuleFullInherited)
  2180       break; // We don't need to examine any more rules.  All properties
  2181              // have been fully specified.
  2183     // Climb up to the next rule in the tree (a less specific rule).
  2184     rootNode = ruleNode;
  2185     ruleNode = ruleNode->mParent;
  2188   bool recomputeDetail = false;
  2190   // If we are computing a style struct other than nsStyleVariables, and
  2191   // ruleData has any properties with variable references (nsCSSValues of
  2192   // type eCSSUnit_TokenStream), then we need to resolve these.
  2193   if (aSID != eStyleStruct_Variables) {
  2194     // A property's value might have became 'inherit' after resolving
  2195     // variable references.  (This happens when an inherited property
  2196     // fails to parse its resolved value.)  We need to recompute
  2197     // |detail| in case this happened.
  2198     recomputeDetail = ResolveVariableReferences(aSID, &ruleData, aContext);
  2201   // If needed, unset the properties that don't have a flag that allows
  2202   // them to be set for this style context.  (For example, only some
  2203   // properties apply to :first-line and :first-letter.)
  2204   uint32_t pseudoRestriction = GetPseudoRestriction(aContext);
  2205   if (pseudoRestriction) {
  2206     UnsetPropertiesWithoutFlags(aSID, &ruleData, pseudoRestriction);
  2208     // We need to recompute |detail| based on the restrictions we just applied.
  2209     // We can adjust |detail| arbitrarily because of the restriction
  2210     // rule added in nsStyleSet::WalkRestrictionRule.
  2211     recomputeDetail = true;
  2214   if (recomputeDetail) {
  2215     detail = CheckSpecifiedProperties(aSID, &ruleData);
  2218   NS_ASSERTION(!startStruct || (detail != eRuleFullReset &&
  2219                                 detail != eRuleFullMixed &&
  2220                                 detail != eRuleFullInherited),
  2221                "can't have start struct and be fully specified");
  2223   bool isReset = nsCachedStyleData::IsReset(aSID);
  2224   if (!highestNode)
  2225     highestNode = rootNode;
  2227   if (!ruleData.mCanStoreInRuleTree)
  2228     detail = eRulePartialMixed; // Treat as though some data is specified to avoid
  2229                                 // the optimizations and force data computation.
  2231   if (detail == eRuleNone && startStruct) {
  2232     // We specified absolutely no rule information, but a parent rule in the tree
  2233     // specified all the rule information.  We set a bit along the branch from our
  2234     // node in the tree to the node that specified the data that tells nodes on that
  2235     // branch that they never need to examine their rules for this particular struct type
  2236     // ever again.
  2237     PropagateDependentBit(aSID, ruleNode, startStruct);
  2238     return startStruct;
  2240   if ((!startStruct && !isReset &&
  2241        (detail == eRuleNone || detail == eRulePartialInherited)) ||
  2242       detail == eRuleFullInherited) {
  2243     // We specified no non-inherited information and neither did any of
  2244     // our parent rules.
  2246     // We set a bit along the branch from the highest node (ruleNode)
  2247     // down to our node (this) indicating that no non-inherited data was
  2248     // specified.  This bit is guaranteed to be set already on the path
  2249     // from the highest node to the root node in the case where
  2250     // (detail == eRuleNone), which is the most common case here.
  2251     // We must check |!isReset| because the Compute*Data functions for
  2252     // reset structs wouldn't handle none bits correctly.
  2253     if (highestNode != this && !isReset)
  2254       PropagateNoneBit(bit, highestNode);
  2256     // All information must necessarily be inherited from our parent style context.
  2257     // In the absence of any computed data in the rule tree and with
  2258     // no rules specified that didn't have values of 'inherit', we should check our parent.
  2259     nsStyleContext* parentContext = aContext->GetParent();
  2260     if (isReset) {
  2261       /* Reset structs don't inherit from first-line. */
  2262       /* See similar code in COMPUTE_START_RESET */
  2263       while (parentContext &&
  2264              parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) {
  2265         parentContext = parentContext->GetParent();
  2268     if (parentContext) {
  2269       // We have a parent, and so we should just inherit from the parent.
  2270       // Set the inherit bits on our context.  These bits tell the style context that
  2271       // it never has to go back to the rule tree for data.  Instead the style context tree
  2272       // should be walked to find the data.
  2273       const void* parentStruct = parentContext->StyleData(aSID);
  2274       aContext->AddStyleBit(bit); // makes const_cast OK.
  2275       aContext->SetStyle(aSID, const_cast<void*>(parentStruct));
  2276       return parentStruct;
  2278     else
  2279       // We are the root.  In the case of fonts, the default values just
  2280       // come from the pres context.
  2281       return SetDefaultOnRoot(aSID, aContext);
  2284   // We need to compute the data from the information that the rules specified.
  2285   const void* res;
  2286 #define STYLE_STRUCT_TEST aSID
  2287 #define STYLE_STRUCT(name, checkdata_cb)                                      \
  2288   res = Compute##name##Data(startStruct, &ruleData, aContext,                 \
  2289                             highestNode, detail, ruleData.mCanStoreInRuleTree);
  2290 #include "nsStyleStructList.h"
  2291 #undef STYLE_STRUCT
  2292 #undef STYLE_STRUCT_TEST
  2294   // Now return the result.
  2295   return res;
  2298 const void*
  2299 nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
  2301   switch (aSID) {
  2302     case eStyleStruct_Font:
  2304       nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
  2305       nscoord minimumFontSize = mPresContext->MinFontSize(fontData->mLanguage);
  2307       if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
  2308         fontData->mFont.size = std::max(fontData->mSize, minimumFontSize);
  2310       else {
  2311         fontData->mFont.size = fontData->mSize;
  2313       aContext->SetStyle(eStyleStruct_Font, fontData);
  2314       return fontData;
  2316     case eStyleStruct_Display:
  2318       nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay();
  2319       aContext->SetStyle(eStyleStruct_Display, disp);
  2320       return disp;
  2322     case eStyleStruct_Visibility:
  2324       nsStyleVisibility* vis = new (mPresContext) nsStyleVisibility(mPresContext);
  2325       aContext->SetStyle(eStyleStruct_Visibility, vis);
  2326       return vis;
  2328     case eStyleStruct_Text:
  2330       nsStyleText* text = new (mPresContext) nsStyleText();
  2331       aContext->SetStyle(eStyleStruct_Text, text);
  2332       return text;
  2334     case eStyleStruct_TextReset:
  2336       nsStyleTextReset* text = new (mPresContext) nsStyleTextReset();
  2337       aContext->SetStyle(eStyleStruct_TextReset, text);
  2338       return text;
  2340     case eStyleStruct_Color:
  2342       nsStyleColor* color = new (mPresContext) nsStyleColor(mPresContext);
  2343       aContext->SetStyle(eStyleStruct_Color, color);
  2344       return color;
  2346     case eStyleStruct_Background:
  2348       nsStyleBackground* bg = new (mPresContext) nsStyleBackground();
  2349       aContext->SetStyle(eStyleStruct_Background, bg);
  2350       return bg;
  2352     case eStyleStruct_Margin:
  2354       nsStyleMargin* margin = new (mPresContext) nsStyleMargin();
  2355       aContext->SetStyle(eStyleStruct_Margin, margin);
  2356       return margin;
  2358     case eStyleStruct_Border:
  2360       nsStyleBorder* border = new (mPresContext) nsStyleBorder(mPresContext);
  2361       aContext->SetStyle(eStyleStruct_Border, border);
  2362       return border;
  2364     case eStyleStruct_Padding:
  2366       nsStylePadding* padding = new (mPresContext) nsStylePadding();
  2367       aContext->SetStyle(eStyleStruct_Padding, padding);
  2368       return padding;
  2370     case eStyleStruct_Outline:
  2372       nsStyleOutline* outline = new (mPresContext) nsStyleOutline(mPresContext);
  2373       aContext->SetStyle(eStyleStruct_Outline, outline);
  2374       return outline;
  2376     case eStyleStruct_List:
  2378       nsStyleList* list = new (mPresContext) nsStyleList();
  2379       aContext->SetStyle(eStyleStruct_List, list);
  2380       return list;
  2382     case eStyleStruct_Position:
  2384       nsStylePosition* pos = new (mPresContext) nsStylePosition();
  2385       aContext->SetStyle(eStyleStruct_Position, pos);
  2386       return pos;
  2388     case eStyleStruct_Table:
  2390       nsStyleTable* table = new (mPresContext) nsStyleTable();
  2391       aContext->SetStyle(eStyleStruct_Table, table);
  2392       return table;
  2394     case eStyleStruct_TableBorder:
  2396       nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder(mPresContext);
  2397       aContext->SetStyle(eStyleStruct_TableBorder, table);
  2398       return table;
  2400     case eStyleStruct_Content:
  2402       nsStyleContent* content = new (mPresContext) nsStyleContent();
  2403       aContext->SetStyle(eStyleStruct_Content, content);
  2404       return content;
  2406     case eStyleStruct_Quotes:
  2408       nsStyleQuotes* quotes = new (mPresContext) nsStyleQuotes();
  2409       aContext->SetStyle(eStyleStruct_Quotes, quotes);
  2410       return quotes;
  2412     case eStyleStruct_UserInterface:
  2414       nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface();
  2415       aContext->SetStyle(eStyleStruct_UserInterface, ui);
  2416       return ui;
  2418     case eStyleStruct_UIReset:
  2420       nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset();
  2421       aContext->SetStyle(eStyleStruct_UIReset, ui);
  2422       return ui;
  2424     case eStyleStruct_XUL:
  2426       nsStyleXUL* xul = new (mPresContext) nsStyleXUL();
  2427       aContext->SetStyle(eStyleStruct_XUL, xul);
  2428       return xul;
  2430     case eStyleStruct_Column:
  2432       nsStyleColumn* column = new (mPresContext) nsStyleColumn(mPresContext);
  2433       aContext->SetStyle(eStyleStruct_Column, column);
  2434       return column;
  2436     case eStyleStruct_SVG:
  2438       nsStyleSVG* svg = new (mPresContext) nsStyleSVG();
  2439       aContext->SetStyle(eStyleStruct_SVG, svg);
  2440       return svg;
  2442     case eStyleStruct_SVGReset:
  2444       nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset();
  2445       aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
  2446       return svgReset;
  2448     case eStyleStruct_Variables:
  2450       nsStyleVariables* vars = new (mPresContext) nsStyleVariables();
  2451       aContext->SetStyle(eStyleStruct_Variables, vars);
  2452       return vars;
  2454     default:
  2455       /*
  2456        * unhandled case: nsStyleStructID_Length.
  2457        * last item of nsStyleStructID, to know its length.
  2458        */
  2459       NS_ABORT_IF_FALSE(false, "unexpected SID");
  2460       return nullptr;
  2462   return nullptr;
  2465 /*
  2466  * This function handles cascading of *-left or *-right box properties
  2467  * against *-start (which is L for LTR and R for RTL) or *-end (which is
  2468  * R for LTR and L for RTL).
  2470  * Cascading these properties correctly is hard because we need to
  2471  * cascade two properties as one, but which two properties depends on a
  2472  * third property ('direction').  We solve this by treating each of
  2473  * these properties (say, 'margin-start') as a shorthand that sets a
  2474  * property containing the value of the property specified
  2475  * ('margin-start-value') and sets a pair of properties
  2476  * ('margin-left-ltr-source' and 'margin-right-rtl-source') saying which
  2477  * of the properties we use.  Thus, when we want to compute the value of
  2478  * 'margin-left' when 'direction' is 'ltr', we look at the value of
  2479  * 'margin-left-ltr-source', which tells us whether to use the highest
  2480  * 'margin-left' in the cascade or the highest 'margin-start'.
  2482  * Finally, since we can compute the normal (*-left and *-right)
  2483  * properties in a loop, this function works by modifying the data we
  2484  * will use in that loop (which the caller must copy from the const
  2485  * input).
  2486  */
  2487 void
  2488 nsRuleNode::AdjustLogicalBoxProp(nsStyleContext* aContext,
  2489                                  const nsCSSValue& aLTRSource,
  2490                                  const nsCSSValue& aRTLSource,
  2491                                  const nsCSSValue& aLTRLogicalValue,
  2492                                  const nsCSSValue& aRTLLogicalValue,
  2493                                  mozilla::css::Side aSide,
  2494                                  nsCSSRect& aValueRect,
  2495                                  bool& aCanStoreInRuleTree)
  2497   bool LTRlogical = aLTRSource.GetUnit() == eCSSUnit_Enumerated &&
  2498                       aLTRSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
  2499   bool RTLlogical = aRTLSource.GetUnit() == eCSSUnit_Enumerated &&
  2500                       aRTLSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
  2501   if (LTRlogical || RTLlogical) {
  2502     // We can't cache anything on the rule tree if we use any data from
  2503     // the style context, since data cached in the rule tree could be
  2504     // used with a style context with a different value.
  2505     aCanStoreInRuleTree = false;
  2506     uint8_t dir = aContext->StyleVisibility()->mDirection;
  2508     if (dir == NS_STYLE_DIRECTION_LTR) {
  2509       if (LTRlogical)
  2510         aValueRect.*(nsCSSRect::sides[aSide]) = aLTRLogicalValue;
  2511     } else {
  2512       if (RTLlogical)
  2513         aValueRect.*(nsCSSRect::sides[aSide]) = aRTLLogicalValue;
  2515   } else if (aLTRLogicalValue.GetUnit() == eCSSUnit_Inherit ||
  2516              aRTLLogicalValue.GetUnit() == eCSSUnit_Inherit) {
  2517     // It actually is valid to store this in the ruletree, since
  2518     // LTRlogical and RTLlogical are both false, but doing that will
  2519     // trigger asserts.  Silence those.
  2520     aCanStoreInRuleTree = false;
  2524 /**
  2525  * Begin an nsRuleNode::Compute*Data function for an inherited struct.
  2527  * @param type_ The nsStyle* type this function computes.
  2528  * @param ctorargs_ The arguments used for the default nsStyle* constructor.
  2529  * @param data_ Variable (declared here) holding the result of this
  2530  *              function.
  2531  * @param parentdata_ Variable (declared here) holding the parent style
  2532  *                    context's data for this struct.
  2533  */
  2534 #define COMPUTE_START_INHERITED(type_, ctorargs_, data_, parentdata_)         \
  2535   NS_ASSERTION(aRuleDetail != eRuleFullInherited,                             \
  2536                "should not have bothered calling Compute*Data");              \
  2538   nsStyleContext* parentContext = aContext->GetParent();                      \
  2540   nsStyle##type_* data_ = nullptr;                                            \
  2541   mozilla::Maybe<nsStyle##type_> maybeFakeParentData;                         \
  2542   const nsStyle##type_* parentdata_ = nullptr;                                \
  2543   bool canStoreInRuleTree = aCanStoreInRuleTree;                              \
  2545   /* If |canStoreInRuleTree| might be true by the time we're done, we */      \
  2546   /* can't call parentContext->Style##type_() since it could recur into */    \
  2547   /* setting the same struct on the same rule node, causing a leak. */        \
  2548   if (aRuleDetail != eRuleFullReset &&                                        \
  2549       (!aStartStruct || (aRuleDetail != eRulePartialReset &&                  \
  2550                          aRuleDetail != eRuleNone))) {                        \
  2551     if (parentContext) {                                                      \
  2552       parentdata_ = parentContext->Style##type_();                            \
  2553     } else {                                                                  \
  2554       maybeFakeParentData.construct ctorargs_;                                \
  2555       parentdata_ = maybeFakeParentData.addr();                               \
  2556     }                                                                         \
  2557   }                                                                           \
  2558   if (aStartStruct)                                                           \
  2559     /* We only need to compute the delta between this computed data and */    \
  2560     /* our computed data. */                                                  \
  2561     data_ = new (mPresContext)                                                \
  2562             nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct));      \
  2563   else {                                                                      \
  2564     if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {     \
  2565       /* No question. We will have to inherit. Go ahead and init */           \
  2566       /* with inherited vals from parent. */                                  \
  2567       canStoreInRuleTree = false;                                          \
  2568       if (parentdata_)                                                        \
  2569         data_ = new (mPresContext) nsStyle##type_(*parentdata_);              \
  2570       else                                                                    \
  2571         data_ = new (mPresContext) nsStyle##type_ ctorargs_;                  \
  2572     }                                                                         \
  2573     else                                                                      \
  2574       data_ = new (mPresContext) nsStyle##type_ ctorargs_;                    \
  2575   }                                                                           \
  2577   if (!parentdata_)                                                           \
  2578     parentdata_ = data_;
  2580 /**
  2581  * Begin an nsRuleNode::Compute*Data function for a reset struct.
  2583  * @param type_ The nsStyle* type this function computes.
  2584  * @param ctorargs_ The arguments used for the default nsStyle* constructor.
  2585  * @param data_ Variable (declared here) holding the result of this
  2586  *              function.
  2587  * @param parentdata_ Variable (declared here) holding the parent style
  2588  *                    context's data for this struct.
  2589  */
  2590 #define COMPUTE_START_RESET(type_, ctorargs_, data_, parentdata_)             \
  2591   NS_ASSERTION(aRuleDetail != eRuleFullInherited,                             \
  2592                "should not have bothered calling Compute*Data");              \
  2594   nsStyleContext* parentContext = aContext->GetParent();                      \
  2595   /* Reset structs don't inherit from first-line */                           \
  2596   /* See similar code in WalkRuleTree */                                      \
  2597   while (parentContext &&                                                     \
  2598          parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) {      \
  2599     parentContext = parentContext->GetParent();                               \
  2600   }                                                                           \
  2602   nsStyle##type_* data_;                                                      \
  2603   if (aStartStruct)                                                           \
  2604     /* We only need to compute the delta between this computed data and */    \
  2605     /* our computed data. */                                                  \
  2606     data_ = new (mPresContext)                                                \
  2607             nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct));      \
  2608   else                                                                        \
  2609     data_ = new (mPresContext) nsStyle##type_ ctorargs_;                      \
  2611   /* If |canStoreInRuleTree| might be true by the time we're done, we */      \
  2612   /* can't call parentContext->Style##type_() since it could recur into */    \
  2613   /* setting the same struct on the same rule node, causing a leak. */        \
  2614   mozilla::Maybe<nsStyle##type_> maybeFakeParentData;                         \
  2615   const nsStyle##type_* parentdata_ = data_;                                  \
  2616   if (aRuleDetail != eRuleFullReset &&                                        \
  2617       aRuleDetail != eRulePartialReset &&                                     \
  2618       aRuleDetail != eRuleNone) {                                             \
  2619     if (parentContext) {                                                      \
  2620       parentdata_ = parentContext->Style##type_();                            \
  2621     } else {                                                                  \
  2622       maybeFakeParentData.construct ctorargs_;                                \
  2623       parentdata_ = maybeFakeParentData.addr();                               \
  2624     }                                                                         \
  2625   }                                                                           \
  2626   bool canStoreInRuleTree = aCanStoreInRuleTree;
  2628 /**
  2629  * End an nsRuleNode::Compute*Data function for an inherited struct.
  2631  * @param type_ The nsStyle* type this function computes.
  2632  * @param data_ Variable holding the result of this function.
  2633  */
  2634 #define COMPUTE_END_INHERITED(type_, data_)                                   \
  2635   NS_POSTCONDITION(!canStoreInRuleTree || aRuleDetail == eRuleFullReset ||    \
  2636                    (aStartStruct && aRuleDetail == eRulePartialReset),        \
  2637                    "canStoreInRuleTree must be false for inherited structs "  \
  2638                    "unless all properties have been specified with values "   \
  2639                    "other than inherit");                                     \
  2640   if (canStoreInRuleTree) {                                                   \
  2641     /* We were fully specified and can therefore be cached right on the */    \
  2642     /* rule node. */                                                          \
  2643     if (!aHighestNode->mStyleData.mInheritedData) {                           \
  2644       aHighestNode->mStyleData.mInheritedData =                               \
  2645         new (mPresContext) nsInheritedStyleData;                              \
  2646     }                                                                         \
  2647     NS_ASSERTION(!aHighestNode->mStyleData.mInheritedData->                   \
  2648                    mStyleStructs[eStyleStruct_##type_],                       \
  2649                  "Going to leak style data");                                 \
  2650     aHighestNode->mStyleData.mInheritedData->                                 \
  2651       mStyleStructs[eStyleStruct_##type_] = data_;                            \
  2652     /* Propagate the bit down. */                                             \
  2653     PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_);         \
  2654     /* Tell the style context that it doesn't own the data */                 \
  2655     aContext->                                                                \
  2656       AddStyleBit(nsCachedStyleData::GetBitForSID(eStyleStruct_##type_));     \
  2657   }                                                                           \
  2658   /* Always cache inherited data on the style context */                      \
  2659   aContext->SetStyle##type_(data_);                                           \
  2661   return data_;
  2663 /**
  2664  * End an nsRuleNode::Compute*Data function for a reset struct.
  2666  * @param type_ The nsStyle* type this function computes.
  2667  * @param data_ Variable holding the result of this function.
  2668  */
  2669 #define COMPUTE_END_RESET(type_, data_)                                       \
  2670   NS_POSTCONDITION(!canStoreInRuleTree ||                                     \
  2671                    aRuleDetail == eRuleNone ||                                \
  2672                    aRuleDetail == eRulePartialReset ||                        \
  2673                    aRuleDetail == eRuleFullReset,                             \
  2674                    "canStoreInRuleTree must be false for reset structs "      \
  2675                    "if any properties were specified as inherit");            \
  2676   if (!canStoreInRuleTree)                                                    \
  2677     /* We can't be cached in the rule node.  We have to be put right */       \
  2678     /* on the style context. */                                               \
  2679     aContext->SetStyle(eStyleStruct_##type_, data_);                          \
  2680   else {                                                                      \
  2681     /* We were fully specified and can therefore be cached right on the */    \
  2682     /* rule node. */                                                          \
  2683     if (!aHighestNode->mStyleData.mResetData) {                               \
  2684       aHighestNode->mStyleData.mResetData =                                   \
  2685         new (mPresContext) nsResetStyleData;                                  \
  2686     }                                                                         \
  2687     NS_ASSERTION(!aHighestNode->mStyleData.mResetData->                       \
  2688                    mStyleStructs[eStyleStruct_##type_],                       \
  2689                  "Going to leak style data");                                 \
  2690     aHighestNode->mStyleData.mResetData->                                     \
  2691       mStyleStructs[eStyleStruct_##type_] = data_;                            \
  2692     /* Propagate the bit down. */                                             \
  2693     PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_);         \
  2694   }                                                                           \
  2696   return data_;
  2698 // This function figures out how much scaling should be suppressed to
  2699 // satisfy scriptminsize. This is our attempt to implement
  2700 // http://www.w3.org/TR/MathML2/chapter3.html#id.3.3.4.2.2
  2701 // This is called after mScriptLevel, mScriptMinSize and mScriptSizeMultiplier
  2702 // have been set in aFont.
  2703 //
  2704 // Here are the invariants we enforce:
  2705 // 1) A decrease in size must not reduce the size below minscriptsize.
  2706 // 2) An increase in size must not increase the size above the size we would
  2707 // have if minscriptsize had not been applied anywhere.
  2708 // 3) The scriptlevel-induced size change must between 1.0 and the parent's
  2709 // scriptsizemultiplier^(new script level - old script level), as close to the
  2710 // latter as possible subject to constraints 1 and 2.
  2711 static nscoord
  2712 ComputeScriptLevelSize(const nsStyleFont* aFont, const nsStyleFont* aParentFont,
  2713                        nsPresContext* aPresContext, nscoord* aUnconstrainedSize)
  2715   int32_t scriptLevelChange =
  2716     aFont->mScriptLevel - aParentFont->mScriptLevel;
  2717   if (scriptLevelChange == 0) {
  2718     *aUnconstrainedSize = aParentFont->mScriptUnconstrainedSize;
  2719     // Constraint #3 says that we cannot change size, and #1 and #2 are always
  2720     // satisfied with no change. It's important this be fast because it covers
  2721     // all non-MathML content.
  2722     return aParentFont->mSize;
  2725   // Compute actual value of minScriptSize
  2726   nscoord minScriptSize = aParentFont->mScriptMinSize;
  2727   if (aFont->mAllowZoom) {
  2728     minScriptSize = nsStyleFont::ZoomText(aPresContext, minScriptSize);
  2731   double scriptLevelScale =
  2732     pow(aParentFont->mScriptSizeMultiplier, scriptLevelChange);
  2733   // Compute the size we would have had if minscriptsize had never been
  2734   // applied, also prevent overflow (bug 413274)
  2735   *aUnconstrainedSize =
  2736     NSToCoordRound(std::min(aParentFont->mScriptUnconstrainedSize*scriptLevelScale,
  2737                           double(nscoord_MAX)));
  2738   // Compute the size we could get via scriptlevel change
  2739   nscoord scriptLevelSize =
  2740     NSToCoordRound(std::min(aParentFont->mSize*scriptLevelScale,
  2741                           double(nscoord_MAX)));
  2742   if (scriptLevelScale <= 1.0) {
  2743     if (aParentFont->mSize <= minScriptSize) {
  2744       // We can't decrease the font size at all, so just stick to no change
  2745       // (authors are allowed to explicitly set the font size smaller than
  2746       // minscriptsize)
  2747       return aParentFont->mSize;
  2749     // We can decrease, so apply constraint #1
  2750     return std::max(minScriptSize, scriptLevelSize);
  2751   } else {
  2752     // scriptminsize can only make sizes larger than the unconstrained size
  2753     NS_ASSERTION(*aUnconstrainedSize <= scriptLevelSize, "How can this ever happen?");
  2754     // Apply constraint #2
  2755     return std::min(scriptLevelSize, std::max(*aUnconstrainedSize, minScriptSize));
  2760 /* static */ nscoord
  2761 nsRuleNode::CalcFontPointSize(int32_t aHTMLSize, int32_t aBasePointSize,
  2762                               nsPresContext* aPresContext,
  2763                               nsFontSizeType aFontSizeType)
  2765 #define sFontSizeTableMin  9 
  2766 #define sFontSizeTableMax 16 
  2768 // This table seems to be the one used by MacIE5. We hope its adoption in Mozilla
  2769 // and eventually in WinIE5.5 will help to establish a standard rendering across
  2770 // platforms and browsers. For now, it is used only in Strict mode. More can be read
  2771 // in the document written by Todd Farhner at:
  2772 // http://style.verso.com/font_size_intervals/altintervals.html
  2773 //
  2774   static int32_t sStrictFontSizeTable[sFontSizeTableMax - sFontSizeTableMin + 1][8] =
  2776       { 9,    9,     9,     9,    11,    14,    18,    27},
  2777       { 9,    9,     9,    10,    12,    15,    20,    30},
  2778       { 9,    9,    10,    11,    13,    17,    22,    33},
  2779       { 9,    9,    10,    12,    14,    18,    24,    36},
  2780       { 9,   10,    12,    13,    16,    20,    26,    39},
  2781       { 9,   10,    12,    14,    17,    21,    28,    42},
  2782       { 9,   10,    13,    15,    18,    23,    30,    45},
  2783       { 9,   10,    13,    16,    18,    24,    32,    48}
  2784   };
  2785 // HTML       1      2      3      4      5      6      7
  2786 // CSS  xxs   xs     s      m      l     xl     xxl
  2787 //                          |
  2788 //                      user pref
  2789 //
  2790 //------------------------------------------------------------
  2791 //
  2792 // This table gives us compatibility with WinNav4 for the default fonts only.
  2793 // In WinNav4, the default fonts were:
  2794 //
  2795 //     Times/12pt ==   Times/16px at 96ppi
  2796 //   Courier/10pt == Courier/13px at 96ppi
  2797 //
  2798 // The 2 lines below marked "anchored" have the exact pixel sizes used by
  2799 // WinNav4 for Times/12pt and Courier/10pt at 96ppi. As you can see, the
  2800 // HTML size 3 (user pref) for those 2 anchored lines is 13px and 16px.
  2801 //
  2802 // All values other than the anchored values were filled in by hand, never
  2803 // going below 9px, and maintaining a "diagonal" relationship. See for
  2804 // example the 13s -- they follow a diagonal line through the table.
  2805 //
  2806   static int32_t sQuirksFontSizeTable[sFontSizeTableMax - sFontSizeTableMin + 1][8] =
  2808       { 9,    9,     9,     9,    11,    14,    18,    28 },
  2809       { 9,    9,     9,    10,    12,    15,    20,    31 },
  2810       { 9,    9,     9,    11,    13,    17,    22,    34 },
  2811       { 9,    9,    10,    12,    14,    18,    24,    37 },
  2812       { 9,    9,    10,    13,    16,    20,    26,    40 }, // anchored (13)
  2813       { 9,    9,    11,    14,    17,    21,    28,    42 },
  2814       { 9,   10,    12,    15,    17,    23,    30,    45 },
  2815       { 9,   10,    13,    16,    18,    24,    32,    48 }  // anchored (16)
  2816   };
  2817 // HTML       1      2      3      4      5      6      7
  2818 // CSS  xxs   xs     s      m      l     xl     xxl
  2819 //                          |
  2820 //                      user pref
  2822 #if 0
  2823 //
  2824 // These are the exact pixel values used by WinIE5 at 96ppi.
  2825 //
  2826       { ?,    8,    11,    12,    13,    16,    21,    32 }, // smallest
  2827       { ?,    9,    12,    13,    16,    21,    27,    40 }, // smaller
  2828       { ?,   10,    13,    16,    18,    24,    32,    48 }, // medium
  2829       { ?,   13,    16,    19,    21,    27,    37,    ?? }, // larger
  2830       { ?,   16,    19,    21,    24,    32,    43,    ?? }  // largest
  2831 //
  2832 // HTML       1      2      3      4      5      6      7
  2833 // CSS  ?     ?      ?      ?      ?      ?      ?      ?
  2834 //
  2835 // (CSS not tested yet.)
  2836 //
  2837 #endif
  2839   static int32_t sFontSizeFactors[8] = { 60,75,89,100,120,150,200,300 };
  2841   static int32_t sCSSColumns[7]  = {0, 1, 2, 3, 4, 5, 6}; // xxs...xxl
  2842   static int32_t sHTMLColumns[7] = {1, 2, 3, 4, 5, 6, 7}; // 1...7
  2844   double dFontSize;
  2846   if (aFontSizeType == eFontSize_HTML) {
  2847     aHTMLSize--;    // input as 1-7
  2850   if (aHTMLSize < 0)
  2851     aHTMLSize = 0;
  2852   else if (aHTMLSize > 6)
  2853     aHTMLSize = 6;
  2855   int32_t* column;
  2856   switch (aFontSizeType)
  2858     case eFontSize_HTML: column = sHTMLColumns; break;
  2859     case eFontSize_CSS:  column = sCSSColumns;  break;
  2862   // Make special call specifically for fonts (needed PrintPreview)
  2863   int32_t fontSize = nsPresContext::AppUnitsToIntCSSPixels(aBasePointSize);
  2865   if ((fontSize >= sFontSizeTableMin) && (fontSize <= sFontSizeTableMax))
  2867     int32_t row = fontSize - sFontSizeTableMin;
  2869     if (aPresContext->CompatibilityMode() == eCompatibility_NavQuirks) {
  2870       dFontSize = nsPresContext::CSSPixelsToAppUnits(sQuirksFontSizeTable[row][column[aHTMLSize]]);
  2871     } else {
  2872       dFontSize = nsPresContext::CSSPixelsToAppUnits(sStrictFontSizeTable[row][column[aHTMLSize]]);
  2875   else
  2877     int32_t factor = sFontSizeFactors[column[aHTMLSize]];
  2878     dFontSize = (factor * aBasePointSize) / 100;
  2882   if (1.0 < dFontSize) {
  2883     return (nscoord)dFontSize;
  2885   return (nscoord)1;
  2889 //------------------------------------------------------------------------------
  2890 //
  2891 //------------------------------------------------------------------------------
  2893 /* static */ nscoord
  2894 nsRuleNode::FindNextSmallerFontSize(nscoord aFontSize, int32_t aBasePointSize, 
  2895                                     nsPresContext* aPresContext,
  2896                                     nsFontSizeType aFontSizeType)
  2898   int32_t index;
  2899   int32_t indexMin;
  2900   int32_t indexMax;
  2901   float relativePosition;
  2902   nscoord smallerSize;
  2903   nscoord indexFontSize = aFontSize; // XXX initialize to quell a spurious gcc3.2 warning
  2904   nscoord smallestIndexFontSize;
  2905   nscoord largestIndexFontSize;
  2906   nscoord smallerIndexFontSize;
  2907   nscoord largerIndexFontSize;
  2909   nscoord onePx = nsPresContext::CSSPixelsToAppUnits(1);
  2911   if (aFontSizeType == eFontSize_HTML) {
  2912     indexMin = 1;
  2913     indexMax = 7;
  2914   } else {
  2915     indexMin = 0;
  2916     indexMax = 6;
  2919   smallestIndexFontSize = CalcFontPointSize(indexMin, aBasePointSize, aPresContext, aFontSizeType);
  2920   largestIndexFontSize = CalcFontPointSize(indexMax, aBasePointSize, aPresContext, aFontSizeType); 
  2921   if (aFontSize > smallestIndexFontSize) {
  2922     if (aFontSize < NSToCoordRound(float(largestIndexFontSize) * 1.5)) { // smaller will be in HTML table
  2923       // find largest index smaller than current
  2924       for (index = indexMax; index >= indexMin; index--) {
  2925         indexFontSize = CalcFontPointSize(index, aBasePointSize, aPresContext, aFontSizeType);
  2926         if (indexFontSize < aFontSize)
  2927           break;
  2929       // set up points beyond table for interpolation purposes
  2930       if (indexFontSize == smallestIndexFontSize) {
  2931         smallerIndexFontSize = indexFontSize - onePx;
  2932         largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
  2933       } else if (indexFontSize == largestIndexFontSize) {
  2934         smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
  2935         largerIndexFontSize = NSToCoordRound(float(largestIndexFontSize) * 1.5);
  2936       } else {
  2937         smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
  2938         largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
  2940       // compute the relative position of the parent size between the two closest indexed sizes
  2941       relativePosition = float(aFontSize - indexFontSize) / float(largerIndexFontSize - indexFontSize);            
  2942       // set the new size to have the same relative position between the next smallest two indexed sizes
  2943       smallerSize = smallerIndexFontSize + NSToCoordRound(relativePosition * (indexFontSize - smallerIndexFontSize));      
  2945     else {  // larger than HTML table, drop by 33%
  2946       smallerSize = NSToCoordRound(float(aFontSize) / 1.5);
  2949   else { // smaller than HTML table, drop by 1px
  2950     smallerSize = std::max(aFontSize - onePx, onePx);
  2952   return smallerSize;
  2955 //------------------------------------------------------------------------------
  2956 //
  2957 //------------------------------------------------------------------------------
  2959 /* static */ nscoord
  2960 nsRuleNode::FindNextLargerFontSize(nscoord aFontSize, int32_t aBasePointSize, 
  2961                                    nsPresContext* aPresContext,
  2962                                    nsFontSizeType aFontSizeType)
  2964   int32_t index;
  2965   int32_t indexMin;
  2966   int32_t indexMax;
  2967   float relativePosition;
  2968   nscoord adjustment;
  2969   nscoord largerSize;
  2970   nscoord indexFontSize = aFontSize; // XXX initialize to quell a spurious gcc3.2 warning
  2971   nscoord smallestIndexFontSize;
  2972   nscoord largestIndexFontSize;
  2973   nscoord smallerIndexFontSize;
  2974   nscoord largerIndexFontSize;
  2976   nscoord onePx = nsPresContext::CSSPixelsToAppUnits(1);
  2978   if (aFontSizeType == eFontSize_HTML) {
  2979     indexMin = 1;
  2980     indexMax = 7;
  2981   } else {
  2982     indexMin = 0;
  2983     indexMax = 6;
  2986   smallestIndexFontSize = CalcFontPointSize(indexMin, aBasePointSize, aPresContext, aFontSizeType);
  2987   largestIndexFontSize = CalcFontPointSize(indexMax, aBasePointSize, aPresContext, aFontSizeType); 
  2988   if (aFontSize > (smallestIndexFontSize - onePx)) {
  2989     if (aFontSize < largestIndexFontSize) { // larger will be in HTML table
  2990       // find smallest index larger than current
  2991       for (index = indexMin; index <= indexMax; index++) { 
  2992         indexFontSize = CalcFontPointSize(index, aBasePointSize, aPresContext, aFontSizeType);
  2993         if (indexFontSize > aFontSize)
  2994           break;
  2996       // set up points beyond table for interpolation purposes
  2997       if (indexFontSize == smallestIndexFontSize) {
  2998         smallerIndexFontSize = indexFontSize - onePx;
  2999         largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
  3000       } else if (indexFontSize == largestIndexFontSize) {
  3001         smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
  3002         largerIndexFontSize = NSCoordSaturatingMultiply(largestIndexFontSize, 1.5);
  3003       } else {
  3004         smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
  3005         largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
  3007       // compute the relative position of the parent size between the two closest indexed sizes
  3008       relativePosition = float(aFontSize - smallerIndexFontSize) / float(indexFontSize - smallerIndexFontSize);
  3009       // set the new size to have the same relative position between the next largest two indexed sizes
  3010       adjustment = NSCoordSaturatingNonnegativeMultiply(largerIndexFontSize - indexFontSize, relativePosition);
  3011       largerSize = NSCoordSaturatingAdd(indexFontSize, adjustment);
  3013     else {  // larger than HTML table, increase by 50%
  3014       largerSize = NSCoordSaturatingMultiply(aFontSize, 1.5);
  3017   else { // smaller than HTML table, increase by 1px
  3018     largerSize = NSCoordSaturatingAdd(aFontSize, onePx);
  3020   return largerSize;
  3023 struct SetFontSizeCalcOps : public css::BasicCoordCalcOps,
  3024                             public css::NumbersAlreadyNormalizedOps
  3026   // The parameters beyond aValue that we need for CalcLengthWith.
  3027   const nscoord mParentSize;
  3028   const nsStyleFont* const mParentFont;
  3029   nsPresContext* const mPresContext;
  3030   const bool mAtRoot;
  3031   bool& mCanStoreInRuleTree;
  3033   SetFontSizeCalcOps(nscoord aParentSize, const nsStyleFont* aParentFont,
  3034                      nsPresContext* aPresContext, bool aAtRoot,
  3035                      bool& aCanStoreInRuleTree)
  3036     : mParentSize(aParentSize),
  3037       mParentFont(aParentFont),
  3038       mPresContext(aPresContext),
  3039       mAtRoot(aAtRoot),
  3040       mCanStoreInRuleTree(aCanStoreInRuleTree)
  3044   result_type ComputeLeafValue(const nsCSSValue& aValue)
  3046     nscoord size;
  3047     if (aValue.IsLengthUnit()) {
  3048       // Note that font-based length units use the parent's size
  3049       // unadjusted for scriptlevel changes. A scriptlevel change
  3050       // between us and the parent is simply ignored.
  3051       size = CalcLengthWith(aValue, mParentSize,
  3052                             mParentFont,
  3053                             nullptr, mPresContext, mAtRoot,
  3054                             true, mCanStoreInRuleTree);
  3055       if (!aValue.IsRelativeLengthUnit() && mParentFont->mAllowZoom) {
  3056         size = nsStyleFont::ZoomText(mPresContext, size);
  3059     else if (eCSSUnit_Percent == aValue.GetUnit()) {
  3060       mCanStoreInRuleTree = false;
  3061       // Note that % units use the parent's size unadjusted for scriptlevel
  3062       // changes. A scriptlevel change between us and the parent is simply
  3063       // ignored.
  3064       // aValue.GetPercentValue() may be negative for, e.g., calc(-50%)
  3065       size = NSCoordSaturatingMultiply(mParentSize, aValue.GetPercentValue());
  3066     } else {
  3067       NS_ABORT_IF_FALSE(false, "unexpected value");
  3068       size = mParentSize;
  3071     return size;
  3073 };
  3075 /* static */ void
  3076 nsRuleNode::SetFontSize(nsPresContext* aPresContext,
  3077                         const nsRuleData* aRuleData,
  3078                         const nsStyleFont* aFont,
  3079                         const nsStyleFont* aParentFont,
  3080                         nscoord* aSize,
  3081                         const nsFont& aSystemFont,
  3082                         nscoord aParentSize,
  3083                         nscoord aScriptLevelAdjustedParentSize,
  3084                         bool aUsedStartStruct,
  3085                         bool aAtRoot,
  3086                         bool& aCanStoreInRuleTree)
  3088   // If false, means that *aSize has not been zoomed.  If true, means that
  3089   // *aSize has been zoomed iff aParentFont->mAllowZoom is true.
  3090   bool sizeIsZoomedAccordingToParent = false;
  3092   int32_t baseSize = (int32_t) aPresContext->
  3093     GetDefaultFont(aFont->mGenericID, aFont->mLanguage)->size;
  3094   const nsCSSValue* sizeValue = aRuleData->ValueForFontSize();
  3095   if (eCSSUnit_Enumerated == sizeValue->GetUnit()) {
  3096     int32_t value = sizeValue->GetIntValue();
  3098     if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) &&
  3099         (value <= NS_STYLE_FONT_SIZE_XXLARGE)) {
  3100       *aSize = CalcFontPointSize(value, baseSize,
  3101                        aPresContext, eFontSize_CSS);
  3103     else if (NS_STYLE_FONT_SIZE_XXXLARGE == value) {
  3104       // <font size="7"> is not specified in CSS, so we don't use eFontSize_CSS.
  3105       *aSize = CalcFontPointSize(value, baseSize, aPresContext);
  3107     else if (NS_STYLE_FONT_SIZE_LARGER  == value ||
  3108              NS_STYLE_FONT_SIZE_SMALLER == value) {
  3109       aCanStoreInRuleTree = false;
  3111       // Un-zoom so we use the tables correctly.  We'll then rezoom due
  3112       // to the |zoom = true| above.
  3113       // Note that relative units here use the parent's size unadjusted
  3114       // for scriptlevel changes. A scriptlevel change between us and the parent
  3115       // is simply ignored.
  3116       nscoord parentSize = aParentSize;
  3117       if (aParentFont->mAllowZoom) {
  3118         parentSize = nsStyleFont::UnZoomText(aPresContext, parentSize);
  3121       if (NS_STYLE_FONT_SIZE_LARGER == value) {
  3122         *aSize = FindNextLargerFontSize(parentSize,
  3123                          baseSize, aPresContext, eFontSize_CSS);
  3125         NS_ASSERTION(*aSize >= parentSize,
  3126                      "FindNextLargerFontSize failed");
  3128       else {
  3129         *aSize = FindNextSmallerFontSize(parentSize,
  3130                          baseSize, aPresContext, eFontSize_CSS);
  3131         NS_ASSERTION(*aSize < parentSize ||
  3132                      parentSize <= nsPresContext::CSSPixelsToAppUnits(1),
  3133                      "FindNextSmallerFontSize failed");
  3135     } else {
  3136       NS_NOTREACHED("unexpected value");
  3139   else if (sizeValue->IsLengthUnit() ||
  3140            sizeValue->GetUnit() == eCSSUnit_Percent ||
  3141            sizeValue->IsCalcUnit()) {
  3142     SetFontSizeCalcOps ops(aParentSize, aParentFont,
  3143                            aPresContext, aAtRoot,
  3144                            aCanStoreInRuleTree);
  3145     *aSize = css::ComputeCalc(*sizeValue, ops);
  3146     if (*aSize < 0) {
  3147       NS_ABORT_IF_FALSE(sizeValue->IsCalcUnit(),
  3148                         "negative lengths and percents should be rejected "
  3149                         "by parser");
  3150       *aSize = 0;
  3152     // The calc ops will always zoom its result according to the value
  3153     // of aParentFont->mAllowZoom.
  3154     sizeIsZoomedAccordingToParent = true;
  3156   else if (eCSSUnit_System_Font == sizeValue->GetUnit()) {
  3157     // this becomes our cascading size
  3158     *aSize = aSystemFont.size;
  3160   else if (eCSSUnit_Inherit == sizeValue->GetUnit() ||
  3161            eCSSUnit_Unset == sizeValue->GetUnit()) {
  3162     aCanStoreInRuleTree = false;
  3163     // We apply scriptlevel change for this case, because the default is
  3164     // to inherit and we don't want explicit "inherit" to differ from the
  3165     // default.
  3166     *aSize = aScriptLevelAdjustedParentSize;
  3167     sizeIsZoomedAccordingToParent = true;
  3169   else if (eCSSUnit_Initial == sizeValue->GetUnit()) {
  3170     // The initial value is 'medium', which has magical sizing based on
  3171     // the generic font family, so do that here too.
  3172     *aSize = baseSize;
  3173   } else {
  3174     NS_ASSERTION(eCSSUnit_Null == sizeValue->GetUnit(),
  3175                  "What kind of font-size value is this?");
  3176     // if aUsedStartStruct is true, then every single property in the
  3177     // font struct is being set all at once. This means scriptlevel is not
  3178     // going to have any influence on the font size; there is no need to
  3179     // do anything here.
  3180     if (!aUsedStartStruct && aParentSize != aScriptLevelAdjustedParentSize) {
  3181       // There was no rule affecting the size but the size has been
  3182       // affected by the parent's size via scriptlevel change. So we cannot
  3183       // store the data in the rule tree.
  3184       aCanStoreInRuleTree = false;
  3185       *aSize = aScriptLevelAdjustedParentSize;
  3186       sizeIsZoomedAccordingToParent = true;
  3187     } else {
  3188       return;
  3192   // We want to zoom the cascaded size so that em-based measurements,
  3193   // line-heights, etc., work.
  3194   bool currentlyZoomed = sizeIsZoomedAccordingToParent &&
  3195                          aParentFont->mAllowZoom;
  3196   if (!currentlyZoomed && aFont->mAllowZoom) {
  3197     *aSize = nsStyleFont::ZoomText(aPresContext, *aSize);
  3198   } else if (currentlyZoomed && !aFont->mAllowZoom) {
  3199     *aSize = nsStyleFont::UnZoomText(aPresContext, *aSize);
  3203 static int8_t ClampTo8Bit(int32_t aValue) {
  3204   if (aValue < -128)
  3205     return -128;
  3206   if (aValue > 127)
  3207     return 127;
  3208   return int8_t(aValue);
  3211 /* static */ void
  3212 nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
  3213                     uint8_t aGenericFontID, const nsRuleData* aRuleData,
  3214                     const nsStyleFont* aParentFont,
  3215                     nsStyleFont* aFont, bool aUsedStartStruct,
  3216                     bool& aCanStoreInRuleTree)
  3218   bool atRoot = !aContext->GetParent();
  3220   // -x-text-zoom: none, inherit, initial
  3221   bool allowZoom;
  3222   const nsCSSValue* textZoomValue = aRuleData->ValueForTextZoom();
  3223   if (eCSSUnit_Null != textZoomValue->GetUnit()) {
  3224     if (eCSSUnit_Inherit == textZoomValue->GetUnit()) {
  3225       allowZoom = aParentFont->mAllowZoom;
  3226     } else if (eCSSUnit_None == textZoomValue->GetUnit()) {
  3227       allowZoom = false;
  3228     } else {
  3229       MOZ_ASSERT(eCSSUnit_Initial == textZoomValue->GetUnit(),
  3230                  "unexpected unit");
  3231       allowZoom = true;
  3233     aFont->EnableZoom(aPresContext, allowZoom);
  3236   // mLanguage must be set before before any of the CalcLengthWith calls
  3237   // (direct calls or calls via SetFontSize) for the cases where |aParentFont|
  3238   // is the same as |aFont|.
  3239   //
  3240   // -x-lang: string, inherit
  3241   // This is not a real CSS property, it is an HTML attribute mapped to CSS.
  3242   const nsCSSValue* langValue = aRuleData->ValueForLang();
  3243   if (eCSSUnit_Ident == langValue->GetUnit()) {
  3244     nsAutoString lang;
  3245     langValue->GetStringValue(lang);
  3247     nsContentUtils::ASCIIToLower(lang);
  3248     aFont->mLanguage = do_GetAtom(lang);
  3249     aFont->mExplicitLanguage = true;
  3252   const nsFont* defaultVariableFont =
  3253     aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
  3254                                  aFont->mLanguage);
  3256   // XXX: Bleh. Disable these somehow?
  3257   // -moz-system-font: enum (never inherit!)
  3258   static_assert(
  3259     NS_STYLE_FONT_CAPTION        == LookAndFeel::eFont_Caption &&
  3260     NS_STYLE_FONT_ICON           == LookAndFeel::eFont_Icon &&
  3261     NS_STYLE_FONT_MENU           == LookAndFeel::eFont_Menu &&
  3262     NS_STYLE_FONT_MESSAGE_BOX    == LookAndFeel::eFont_MessageBox &&
  3263     NS_STYLE_FONT_SMALL_CAPTION  == LookAndFeel::eFont_SmallCaption &&
  3264     NS_STYLE_FONT_STATUS_BAR     == LookAndFeel::eFont_StatusBar &&
  3265     NS_STYLE_FONT_WINDOW         == LookAndFeel::eFont_Window &&
  3266     NS_STYLE_FONT_DOCUMENT       == LookAndFeel::eFont_Document &&
  3267     NS_STYLE_FONT_WORKSPACE      == LookAndFeel::eFont_Workspace &&
  3268     NS_STYLE_FONT_DESKTOP        == LookAndFeel::eFont_Desktop &&
  3269     NS_STYLE_FONT_INFO           == LookAndFeel::eFont_Info &&
  3270     NS_STYLE_FONT_DIALOG         == LookAndFeel::eFont_Dialog &&
  3271     NS_STYLE_FONT_BUTTON         == LookAndFeel::eFont_Button &&
  3272     NS_STYLE_FONT_PULL_DOWN_MENU == LookAndFeel::eFont_PullDownMenu &&
  3273     NS_STYLE_FONT_LIST           == LookAndFeel::eFont_List &&
  3274     NS_STYLE_FONT_FIELD          == LookAndFeel::eFont_Field,
  3275     "LookAndFeel.h system-font constants out of sync with nsStyleConsts.h");
  3277   // Fall back to defaultVariableFont.
  3278   nsFont systemFont = *defaultVariableFont;
  3279   const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
  3280   if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
  3281     gfxFontStyle fontStyle;
  3282     LookAndFeel::FontID fontID =
  3283       (LookAndFeel::FontID)systemFontValue->GetIntValue();
  3284     float devPerCSS =
  3285       (float)nsPresContext::AppUnitsPerCSSPixel() /
  3286       aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
  3287     if (LookAndFeel::GetFont(fontID, systemFont.name, fontStyle, devPerCSS)) {
  3288       systemFont.style = fontStyle.style;
  3289       systemFont.systemFont = fontStyle.systemFont;
  3290       systemFont.variant = NS_FONT_VARIANT_NORMAL;
  3291       systemFont.weight = fontStyle.weight;
  3292       systemFont.stretch = fontStyle.stretch;
  3293       systemFont.decorations = NS_FONT_DECORATION_NONE;
  3294       systemFont.size = NSFloatPixelsToAppUnits(fontStyle.size,
  3295                                                 aPresContext->DeviceContext()->
  3296                                                 UnscaledAppUnitsPerDevPixel());
  3297       //systemFont.langGroup = fontStyle.langGroup;
  3298       systemFont.sizeAdjust = fontStyle.sizeAdjust;
  3300 #ifdef XP_WIN
  3301       // XXXldb This platform-specific stuff should be in the
  3302       // LookAndFeel implementation, not here.
  3303       // XXXzw Should we even still *have* this code?  It looks to be making
  3304       // old, probably obsolete assumptions.
  3306       if (fontID == LookAndFeel::eFont_Field ||
  3307           fontID == LookAndFeel::eFont_Button ||
  3308           fontID == LookAndFeel::eFont_List) {
  3309         // As far as I can tell the system default fonts and sizes
  3310         // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
  3311         // all pre-determined and cannot be changed by either the control panel
  3312         // or programmatically.
  3313         // Fields (text fields)
  3314         // Button and Selects (listboxes/comboboxes)
  3315         //    We use whatever font is defined by the system. Which it appears
  3316         //    (and the assumption is) it is always a proportional font. Then we
  3317         //    always use 2 points smaller than what the browser has defined as
  3318         //    the default proportional font.
  3319         // Assumption: system defined font is proportional
  3320         systemFont.size =
  3321           std::max(defaultVariableFont->size -
  3322                  nsPresContext::CSSPointsToAppUnits(2), 0);
  3324 #endif
  3328   // font-family: string list, enum, inherit
  3329   const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
  3330   NS_ASSERTION(eCSSUnit_Enumerated != familyValue->GetUnit(),
  3331                "system fonts should not be in mFamily anymore");
  3332   if (eCSSUnit_Families == familyValue->GetUnit()) {
  3333     // set the correct font if we are using DocumentFonts OR we are overriding for XUL
  3334     // MJA: bug 31816
  3335     if (aGenericFontID == kGenericFont_NONE) {
  3336       // only bother appending fallback fonts if this isn't a fallback generic font itself
  3337       if (!aFont->mFont.name.IsEmpty())
  3338         aFont->mFont.name.Append((char16_t)',');
  3339       // defaultVariableFont.name should always be "serif" or "sans-serif".
  3340       aFont->mFont.name.Append(defaultVariableFont->name);
  3342     aFont->mFont.systemFont = false;
  3343     // Technically this is redundant with the code below, but it's good
  3344     // to have since we'll still want it once we get rid of
  3345     // SetGenericFont (bug 380915).
  3346     aFont->mGenericID = aGenericFontID;
  3348   else if (eCSSUnit_System_Font == familyValue->GetUnit()) {
  3349     aFont->mFont.name = systemFont.name;
  3350     aFont->mFont.systemFont = true;
  3351     aFont->mGenericID = kGenericFont_NONE;
  3353   else if (eCSSUnit_Inherit == familyValue->GetUnit() ||
  3354            eCSSUnit_Unset == familyValue->GetUnit()) {
  3355     aCanStoreInRuleTree = false;
  3356     aFont->mFont.name = aParentFont->mFont.name;
  3357     aFont->mFont.systemFont = aParentFont->mFont.systemFont;
  3358     aFont->mGenericID = aParentFont->mGenericID;
  3360   else if (eCSSUnit_Initial == familyValue->GetUnit()) {
  3361     aFont->mFont.name = defaultVariableFont->name;
  3362     aFont->mFont.systemFont = defaultVariableFont->systemFont;
  3363     aFont->mGenericID = kGenericFont_NONE;
  3366   // When we're in the loop in SetGenericFont, we must ensure that we
  3367   // always keep aFont->mFlags set to the correct generic.  But we have
  3368   // to be careful not to touch it when we're called directly from
  3369   // ComputeFontData, because we could have a start struct.
  3370   if (aGenericFontID != kGenericFont_NONE) {
  3371     aFont->mGenericID = aGenericFontID;
  3374   // -moz-math-variant: enum, inherit, initial
  3375   SetDiscrete(*aRuleData->ValueForMathVariant(), aFont->mMathVariant,
  3376               aCanStoreInRuleTree,
  3377               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  3378               aParentFont->mMathVariant, NS_MATHML_MATHVARIANT_NONE,
  3379               0, 0, 0, 0);
  3381   // -moz-math-display: enum, inherit, initial
  3382   SetDiscrete(*aRuleData->ValueForMathDisplay(), aFont->mMathDisplay,
  3383               aCanStoreInRuleTree,
  3384               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  3385               aParentFont->mMathDisplay, NS_MATHML_DISPLAYSTYLE_INLINE,
  3386               0, 0, 0, 0);
  3388   // font-smoothing: enum, inherit, initial
  3389   SetDiscrete(*aRuleData->ValueForOSXFontSmoothing(),
  3390               aFont->mFont.smoothing, aCanStoreInRuleTree,
  3391               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  3392               aParentFont->mFont.smoothing,
  3393               defaultVariableFont->smoothing,
  3394               0, 0, 0, 0);
  3396   // font-style: enum, inherit, initial, -moz-system-font
  3397   if (aFont->mMathVariant != NS_MATHML_MATHVARIANT_NONE) {
  3398     // -moz-math-variant overrides font-style
  3399     aFont->mFont.style = NS_FONT_STYLE_NORMAL;
  3400   } else {
  3401     SetDiscrete(*aRuleData->ValueForFontStyle(),
  3402                 aFont->mFont.style, aCanStoreInRuleTree,
  3403                 SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
  3404                 aParentFont->mFont.style,
  3405                 defaultVariableFont->style,
  3406                 0, 0, 0, systemFont.style);
  3409   // font-variant: enum, inherit, initial, -moz-system-font
  3410   SetDiscrete(*aRuleData->ValueForFontVariant(),
  3411               aFont->mFont.variant, aCanStoreInRuleTree,
  3412               SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
  3413               aParentFont->mFont.variant,
  3414               defaultVariableFont->variant,
  3415               0, 0, 0, systemFont.variant);
  3417   // font-weight: int, enum, inherit, initial, -moz-system-font
  3418   // special handling for enum
  3419   const nsCSSValue* weightValue = aRuleData->ValueForFontWeight();
  3420   if (aFont->mMathVariant != NS_MATHML_MATHVARIANT_NONE) {
  3421     // -moz-math-variant overrides font-weight
  3422     aFont->mFont.weight = NS_FONT_WEIGHT_NORMAL;
  3423   } else if (eCSSUnit_Enumerated == weightValue->GetUnit()) {
  3424     int32_t value = weightValue->GetIntValue();
  3425     switch (value) {
  3426       case NS_STYLE_FONT_WEIGHT_NORMAL:
  3427       case NS_STYLE_FONT_WEIGHT_BOLD:
  3428         aFont->mFont.weight = value;
  3429         break;
  3430       case NS_STYLE_FONT_WEIGHT_BOLDER: {
  3431         aCanStoreInRuleTree = false;
  3432         int32_t inheritedValue = aParentFont->mFont.weight;
  3433         if (inheritedValue <= 300) {
  3434           aFont->mFont.weight = 400;
  3435         } else if (inheritedValue <= 500) {
  3436           aFont->mFont.weight = 700;
  3437         } else {
  3438           aFont->mFont.weight = 900;
  3440         break;
  3442       case NS_STYLE_FONT_WEIGHT_LIGHTER: {
  3443         aCanStoreInRuleTree = false;
  3444         int32_t inheritedValue = aParentFont->mFont.weight;
  3445         if (inheritedValue < 600) {
  3446           aFont->mFont.weight = 100;
  3447         } else if (inheritedValue < 800) {
  3448           aFont->mFont.weight = 400;
  3449         } else {
  3450           aFont->mFont.weight = 700;
  3452         break;
  3455   } else
  3456     SetDiscrete(*weightValue, aFont->mFont.weight, aCanStoreInRuleTree,
  3457                 SETDSC_INTEGER | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
  3458                 aParentFont->mFont.weight,
  3459                 defaultVariableFont->weight,
  3460                 0, 0, 0, systemFont.weight);
  3462   // font-stretch: enum, inherit, initial, -moz-system-font
  3463   SetDiscrete(*aRuleData->ValueForFontStretch(),
  3464               aFont->mFont.stretch, aCanStoreInRuleTree,
  3465               SETDSC_SYSTEM_FONT | SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  3466               aParentFont->mFont.stretch,
  3467               defaultVariableFont->stretch,
  3468               0, 0, 0, systemFont.stretch);
  3470   // Compute scriptlevel, scriptminsize and scriptsizemultiplier now so
  3471   // they're available for font-size computation.
  3473   // -moz-script-min-size: length
  3474   const nsCSSValue* scriptMinSizeValue = aRuleData->ValueForScriptMinSize();
  3475   if (scriptMinSizeValue->IsLengthUnit()) {
  3476     // scriptminsize in font units (em, ex) has to be interpreted relative
  3477     // to the parent font, or the size definitions are circular and we
  3478     //
  3479     aFont->mScriptMinSize =
  3480       CalcLengthWith(*scriptMinSizeValue, aParentFont->mSize,
  3481                      aParentFont,
  3482                      nullptr, aPresContext, atRoot, true,
  3483                      aCanStoreInRuleTree);
  3486   // -moz-script-size-multiplier: factor, inherit, initial
  3487   SetFactor(*aRuleData->ValueForScriptSizeMultiplier(),
  3488             aFont->mScriptSizeMultiplier,
  3489             aCanStoreInRuleTree, aParentFont->mScriptSizeMultiplier,
  3490             NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER,
  3491             SETFCT_POSITIVE | SETFCT_UNSET_INHERIT);
  3493   // -moz-script-level: integer, number, inherit
  3494   const nsCSSValue* scriptLevelValue = aRuleData->ValueForScriptLevel();
  3495   if (eCSSUnit_Integer == scriptLevelValue->GetUnit()) {
  3496     // "relative"
  3497     aCanStoreInRuleTree = false;
  3498     aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel + scriptLevelValue->GetIntValue());
  3500   else if (eCSSUnit_Number == scriptLevelValue->GetUnit()) {
  3501     // "absolute"
  3502     aFont->mScriptLevel = ClampTo8Bit(int32_t(scriptLevelValue->GetFloatValue()));
  3504   else if (eCSSUnit_Auto == scriptLevelValue->GetUnit()) {
  3505     // auto
  3506     aCanStoreInRuleTree = false;
  3507     aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel +
  3508                                       (aParentFont->mMathDisplay ==
  3509                                        NS_MATHML_DISPLAYSTYLE_INLINE ? 1 : 0));
  3511   else if (eCSSUnit_Inherit == scriptLevelValue->GetUnit() ||
  3512            eCSSUnit_Unset == scriptLevelValue->GetUnit()) {
  3513     aCanStoreInRuleTree = false;
  3514     aFont->mScriptLevel = aParentFont->mScriptLevel;
  3516   else if (eCSSUnit_Initial == scriptLevelValue->GetUnit()) {
  3517     aFont->mScriptLevel = 0;
  3520   // font-kerning: none, enum, inherit, initial, -moz-system-font
  3521   SetDiscrete(*aRuleData->ValueForFontKerning(),
  3522               aFont->mFont.kerning, aCanStoreInRuleTree,
  3523               SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
  3524               aParentFont->mFont.kerning,
  3525               defaultVariableFont->kerning,
  3526               0, 0, 0, systemFont.kerning);
  3528   // font-synthesis: none, enum (bit field), inherit, initial, -moz-system-font
  3529   SetDiscrete(*aRuleData->ValueForFontSynthesis(),
  3530               aFont->mFont.synthesis, aCanStoreInRuleTree,
  3531               SETDSC_NONE | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  3532                 SETDSC_UNSET_INHERIT,
  3533               aParentFont->mFont.synthesis,
  3534               defaultVariableFont->synthesis,
  3535               0, 0, 0, systemFont.synthesis);
  3537   // font-variant-alternates: normal, enum (bit field) + functions, inherit,
  3538   //                          initial, -moz-system-font
  3539   const nsCSSValue* variantAlternatesValue =
  3540     aRuleData->ValueForFontVariantAlternates();
  3541   int32_t variantAlternates = 0;
  3543   switch (variantAlternatesValue->GetUnit()) {
  3544   case eCSSUnit_Inherit:
  3545   case eCSSUnit_Unset:
  3546     aFont->mFont.CopyAlternates(aParentFont->mFont);
  3547     aCanStoreInRuleTree = false;
  3548     break;
  3550   case eCSSUnit_Initial:
  3551   case eCSSUnit_Normal:
  3552     aFont->mFont.variantAlternates = 0;
  3553     aFont->mFont.alternateValues.Clear();
  3554     aFont->mFont.featureValueLookup = nullptr;
  3555     break;
  3557   case eCSSUnit_Pair:
  3558     NS_ASSERTION(variantAlternatesValue->GetPairValue().mXValue.GetUnit() ==
  3559                    eCSSUnit_Enumerated, "strange unit for variantAlternates");
  3560     variantAlternates =
  3561       variantAlternatesValue->GetPairValue().mXValue.GetIntValue();
  3562     aFont->mFont.variantAlternates = variantAlternates;
  3564     if (variantAlternates & NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK) {
  3565       // fetch the feature lookup object from the styleset
  3566       aFont->mFont.featureValueLookup =
  3567         aPresContext->StyleSet()->GetFontFeatureValuesLookup();
  3569       NS_ASSERTION(variantAlternatesValue->GetPairValue().mYValue.GetUnit() ==
  3570                    eCSSUnit_List, "function list not a list value");
  3571       nsStyleUtil::ComputeFunctionalAlternates(
  3572         variantAlternatesValue->GetPairValue().mYValue.GetListValue(),
  3573         aFont->mFont.alternateValues);
  3575     break;
  3577   default:
  3578     break;
  3581   // font-variant-caps: normal, enum, inherit, initial, -moz-system-font
  3582   SetDiscrete(*aRuleData->ValueForFontVariantCaps(),
  3583               aFont->mFont.variantCaps, aCanStoreInRuleTree,
  3584               SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  3585                 SETDSC_UNSET_INHERIT,
  3586               aParentFont->mFont.variantCaps,
  3587               defaultVariableFont->variantCaps,
  3588               0, 0, 0, systemFont.variantCaps);
  3590   // font-variant-east-asian: normal, enum (bit field), inherit, initial,
  3591   //                          -moz-system-font
  3592   SetDiscrete(*aRuleData->ValueForFontVariantEastAsian(),
  3593               aFont->mFont.variantEastAsian, aCanStoreInRuleTree,
  3594               SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  3595                 SETDSC_UNSET_INHERIT,
  3596               aParentFont->mFont.variantEastAsian,
  3597               defaultVariableFont->variantEastAsian,
  3598               0, 0, 0, systemFont.variantEastAsian);
  3600   // font-variant-ligatures: normal, enum (bit field), inherit, initial,
  3601   //                         -moz-system-font
  3602   SetDiscrete(*aRuleData->ValueForFontVariantLigatures(),
  3603               aFont->mFont.variantLigatures, aCanStoreInRuleTree,
  3604               SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  3605                 SETDSC_UNSET_INHERIT,
  3606               aParentFont->mFont.variantLigatures,
  3607               defaultVariableFont->variantLigatures,
  3608               0, 0, 0, systemFont.variantLigatures);
  3610   // font-variant-numeric: normal, enum (bit field), inherit, initial,
  3611   //                       -moz-system-font
  3612   SetDiscrete(*aRuleData->ValueForFontVariantNumeric(),
  3613               aFont->mFont.variantNumeric, aCanStoreInRuleTree,
  3614               SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  3615                 SETDSC_UNSET_INHERIT,
  3616               aParentFont->mFont.variantNumeric,
  3617               defaultVariableFont->variantNumeric,
  3618               0, 0, 0, systemFont.variantNumeric);
  3620   // font-variant-position: normal, enum, inherit, initial,
  3621   //                        -moz-system-font
  3622   SetDiscrete(*aRuleData->ValueForFontVariantPosition(),
  3623               aFont->mFont.variantPosition, aCanStoreInRuleTree,
  3624               SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  3625                 SETDSC_UNSET_INHERIT,
  3626               aParentFont->mFont.variantPosition,
  3627               defaultVariableFont->variantPosition,
  3628               0, 0, 0, systemFont.variantPosition);
  3630   // font-feature-settings
  3631   const nsCSSValue* featureSettingsValue =
  3632     aRuleData->ValueForFontFeatureSettings();
  3634   switch (featureSettingsValue->GetUnit()) {
  3635   case eCSSUnit_Null:
  3636     break;
  3638   case eCSSUnit_Normal:
  3639   case eCSSUnit_Initial:
  3640     aFont->mFont.fontFeatureSettings.Clear();
  3641     break;
  3643   case eCSSUnit_Inherit:
  3644   case eCSSUnit_Unset:
  3645     aCanStoreInRuleTree = false;
  3646     aFont->mFont.fontFeatureSettings = aParentFont->mFont.fontFeatureSettings;
  3647     break;
  3649   case eCSSUnit_System_Font:
  3650     aFont->mFont.fontFeatureSettings = systemFont.fontFeatureSettings;
  3651     break;
  3653   case eCSSUnit_PairList:
  3654   case eCSSUnit_PairListDep:
  3655     ComputeFontFeatures(featureSettingsValue->GetPairListValue(),
  3656                         aFont->mFont.fontFeatureSettings);
  3657     break;
  3659   default:
  3660     NS_ABORT_IF_FALSE(false, "unexpected value unit");
  3661     break;
  3664   // font-language-override
  3665   const nsCSSValue* languageOverrideValue =
  3666     aRuleData->ValueForFontLanguageOverride();
  3667   if (eCSSUnit_Inherit == languageOverrideValue->GetUnit() ||
  3668       eCSSUnit_Unset == languageOverrideValue->GetUnit()) {
  3669     aCanStoreInRuleTree = false;
  3670     aFont->mFont.languageOverride = aParentFont->mFont.languageOverride;
  3671   } else if (eCSSUnit_Normal == languageOverrideValue->GetUnit() ||
  3672              eCSSUnit_Initial == languageOverrideValue->GetUnit()) {
  3673     aFont->mFont.languageOverride.Truncate();
  3674   } else if (eCSSUnit_System_Font == languageOverrideValue->GetUnit()) {
  3675     aFont->mFont.languageOverride = systemFont.languageOverride;
  3676   } else if (eCSSUnit_String == languageOverrideValue->GetUnit()) {
  3677     languageOverrideValue->GetStringValue(aFont->mFont.languageOverride);
  3680   // font-size: enum, length, percent, inherit
  3681   nscoord scriptLevelAdjustedParentSize = aParentFont->mSize;
  3682   nscoord scriptLevelAdjustedUnconstrainedParentSize;
  3683   scriptLevelAdjustedParentSize =
  3684     ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
  3685                            &scriptLevelAdjustedUnconstrainedParentSize);
  3686   NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
  3687                "If we have a start struct, we should have reset everything coming in here");
  3688   SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
  3689               &aFont->mSize,
  3690               systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
  3691               aUsedStartStruct, atRoot, aCanStoreInRuleTree);
  3692   if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize &&
  3693       scriptLevelAdjustedParentSize == scriptLevelAdjustedUnconstrainedParentSize) {
  3694     // Fast path: we have not been affected by scriptminsize so we don't
  3695     // need to call SetFontSize again to compute the
  3696     // scriptminsize-unconstrained size. This is OK even if we have a
  3697     // start struct, because if we have a start struct then 'font-size'
  3698     // was specified and so scriptminsize has no effect.
  3699     aFont->mScriptUnconstrainedSize = aFont->mSize;
  3700   } else {
  3701     SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
  3702                 &aFont->mScriptUnconstrainedSize,
  3703                 systemFont, aParentFont->mScriptUnconstrainedSize,
  3704                 scriptLevelAdjustedUnconstrainedParentSize,
  3705                 aUsedStartStruct, atRoot, aCanStoreInRuleTree);
  3707   NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
  3708                "scriptminsize should never be making things bigger");
  3710   nscoord fontSize = aFont->mSize;
  3712   // enforce the user' specified minimum font-size on the value that we expose
  3713   // (but don't change font-size:0, since that would unhide hidden text)
  3714   if (fontSize > 0) {
  3715     nscoord minFontSize = aPresContext->MinFontSize(aFont->mLanguage);
  3716     if (minFontSize < 0) {
  3717       minFontSize = 0;
  3719     if (fontSize < minFontSize && !aPresContext->IsChrome()) {
  3720       // override the minimum font-size constraint
  3721       fontSize = minFontSize;
  3724   aFont->mFont.size = fontSize;
  3726   // font-size-adjust: number, none, inherit, initial, -moz-system-font
  3727   const nsCSSValue* sizeAdjustValue = aRuleData->ValueForFontSizeAdjust();
  3728   if (eCSSUnit_System_Font == sizeAdjustValue->GetUnit()) {
  3729     aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
  3730   } else
  3731     SetFactor(*sizeAdjustValue, aFont->mFont.sizeAdjust,
  3732               aCanStoreInRuleTree, aParentFont->mFont.sizeAdjust, 0.0f,
  3733               SETFCT_NONE | SETFCT_UNSET_INHERIT);
  3736 /* static */ void
  3737 nsRuleNode::ComputeFontFeatures(const nsCSSValuePairList *aFeaturesList,
  3738                                 nsTArray<gfxFontFeature>& aFeatureSettings)
  3740   aFeatureSettings.Clear();
  3741   for (const nsCSSValuePairList* p = aFeaturesList; p; p = p->mNext) {
  3742     gfxFontFeature feat = {0, 0};
  3744     NS_ABORT_IF_FALSE(aFeaturesList->mXValue.GetUnit() == eCSSUnit_String,
  3745                       "unexpected value unit");
  3747     // tag is a 4-byte ASCII sequence
  3748     nsAutoString tag;
  3749     p->mXValue.GetStringValue(tag);
  3750     if (tag.Length() != 4) {
  3751       continue;
  3753     // parsing validates that these are ASCII chars
  3754     // tags are always big-endian
  3755     feat.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8)  | tag[3];
  3757     // value
  3758     NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Integer,
  3759                  "should have found an integer unit");
  3760     feat.mValue = p->mYValue.GetIntValue();
  3762     aFeatureSettings.AppendElement(feat);
  3766 // This should die (bug 380915).
  3767 //
  3768 // SetGenericFont:
  3769 //  - backtrack to an ancestor with the same generic font name (possibly
  3770 //    up to the root where default values come from the presentation context)
  3771 //  - re-apply cascading rules from there without caching intermediate values
  3772 /* static */ void
  3773 nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
  3774                            nsStyleContext* aContext,
  3775                            uint8_t aGenericFontID,
  3776                            nsStyleFont* aFont)
  3778   // walk up the contexts until a context with the desired generic font
  3779   nsAutoTArray<nsStyleContext*, 8> contextPath;
  3780   contextPath.AppendElement(aContext);
  3781   nsStyleContext* higherContext = aContext->GetParent();
  3782   while (higherContext) {
  3783     if (higherContext->StyleFont()->mGenericID == aGenericFontID) {
  3784       // done walking up the higher contexts
  3785       break;
  3787     contextPath.AppendElement(higherContext);
  3788     higherContext = higherContext->GetParent();
  3791   // re-apply the cascading rules, starting from the higher context
  3793   // If we stopped earlier because we reached the root of the style tree,
  3794   // we will start with the default generic font from the presentation
  3795   // context. Otherwise we start with the higher context.
  3796   const nsFont* defaultFont =
  3797     aPresContext->GetDefaultFont(aGenericFontID, aFont->mLanguage);
  3798   nsStyleFont parentFont(*defaultFont, aPresContext);
  3799   if (higherContext) {
  3800     const nsStyleFont* tmpFont = higherContext->StyleFont();
  3801     parentFont = *tmpFont;
  3803   *aFont = parentFont;
  3805   bool dummy;
  3806   uint32_t fontBit = nsCachedStyleData::GetBitForSID(eStyleStruct_Font);
  3808   // use placement new[] on the result of alloca() to allocate a
  3809   // variable-sized stack array, including execution of constructors,
  3810   // and use an RAII class to run the destructors too.
  3811   size_t nprops = nsCSSProps::PropertyCountInStruct(eStyleStruct_Font);
  3812   void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
  3814   for (int32_t i = contextPath.Length() - 1; i >= 0; --i) {
  3815     nsStyleContext* context = contextPath[i];
  3816     AutoCSSValueArray dataArray(dataStorage, nprops);
  3818     nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), dataArray.get(),
  3819                         aPresContext, context);
  3820     ruleData.mValueOffsets[eStyleStruct_Font] = 0;
  3822     // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
  3823     // Note that we *do* need to do this for our own data, since what is
  3824     // in |fontData| in ComputeFontData is only for the rules below
  3825     // aStartStruct.
  3826     for (nsRuleNode* ruleNode = context->RuleNode(); ruleNode;
  3827          ruleNode = ruleNode->GetParent()) {
  3828       if (ruleNode->mNoneBits & fontBit)
  3829         // no more font rules on this branch, get out
  3830         break;
  3832       nsIStyleRule *rule = ruleNode->GetRule();
  3833       if (rule) {
  3834         ruleData.mLevel = ruleNode->GetLevel();
  3835         ruleData.mIsImportantRule = ruleNode->IsImportantRule();
  3836         rule->MapRuleInfoInto(&ruleData);
  3840     // Compute the delta from the information that the rules specified
  3842     // Avoid unnecessary operations in SetFont().  But we care if it's
  3843     // the final value that we're computing.
  3844     if (i != 0)
  3845       ruleData.ValueForFontFamily()->Reset();
  3847     ResolveVariableReferences(eStyleStruct_Font, &ruleData, aContext);
  3849     nsRuleNode::SetFont(aPresContext, context,
  3850                         aGenericFontID, &ruleData, &parentFont, aFont,
  3851                         false, dummy);
  3853     parentFont = *aFont;
  3857 static bool ExtractGeneric(const nsString& aFamily, bool aGeneric,
  3858                              void *aData)
  3860   nsAutoString *data = static_cast<nsAutoString*>(aData);
  3862   if (aGeneric) {
  3863     *data = aFamily;
  3864     return false; // stop enumeration
  3866   return true;
  3869 struct smugglerStruct {
  3870   nsStyleFont *font;
  3871   gfxUserFontSet *userFonts;
  3872 };
  3874 /* This function forces the use of the first @font-face font we find */
  3875 static bool ForceFirstWebFont(const nsString& aFamily, bool aGeneric,
  3876                               void *smuggled)
  3878   smugglerStruct *sm = static_cast<smugglerStruct*>(smuggled);
  3880   if (aGeneric) {
  3881     return true;
  3884   if (sm->userFonts->HasFamily(aFamily)) {
  3885     // Force use of this exact @font-face font since we have it.
  3886     sm->font->mFont.name = aFamily;
  3888     return false; // Stop enumeration. 
  3891   return true;
  3894 const void*
  3895 nsRuleNode::ComputeFontData(void* aStartStruct,
  3896                             const nsRuleData* aRuleData,
  3897                             nsStyleContext* aContext,
  3898                             nsRuleNode* aHighestNode,
  3899                             const RuleDetail aRuleDetail,
  3900                             const bool aCanStoreInRuleTree)
  3902   COMPUTE_START_INHERITED(Font, (mPresContext), font, parentFont)
  3904   // NOTE:  The |aRuleDetail| passed in is a little bit conservative due
  3905   // to the -moz-system-font property.  We really don't need to consider
  3906   // it here in determining whether to cache in the rule tree.  However,
  3907   // we do need to consider it in WalkRuleTree when deciding whether to
  3908   // walk further up the tree.  So this means that when the font struct
  3909   // is fully specified using *longhand* properties (excluding
  3910   // -moz-system-font), we won't cache in the rule tree even though we
  3911   // could.  However, it's pretty unlikely authors will do that
  3912   // (although there is a pretty good chance they'll fully specify it
  3913   // using the 'font' shorthand).
  3915   bool useDocumentFonts =
  3916     mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
  3917   bool isXUL = PR_FALSE;
  3918   bool forcedWebFont = false;
  3920   // See if we are in the chrome
  3921   // We only need to know this to determine if we have to use the
  3922   // document fonts (overriding the useDocumentFonts flag).
  3923   if (mPresContext->IsChrome()) {
  3924     // if we are not using document fonts, but this is a XUL document,
  3925     // then we use the document fonts anyway
  3926     isXUL = true;
  3929   // Figure out if we are a generic font
  3930   uint8_t generic = kGenericFont_NONE;
  3931   // XXXldb What if we would have had a string if we hadn't been doing
  3932   // the optimization with a non-null aStartStruct?
  3933   const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
  3934   if (eCSSUnit_Families == familyValue->GetUnit()) {
  3935     familyValue->GetStringValue(font->mFont.name);
  3936     // XXXldb Do we want to extract the generic for this if it's not only a
  3937     // generic?
  3938     nsFont::GetGenericID(font->mFont.name, &generic);
  3940     if (!isXUL) {
  3941       gfxUserFontSet *userFonts = mPresContext->GetUserFontSet();
  3942       if (userFonts) {
  3943         smugglerStruct sm;
  3944         sm.userFonts = userFonts;
  3945         sm.font = font;
  3947         if (!sm.font->mFont.EnumerateFamilies(ForceFirstWebFont, &sm)) {
  3948           isXUL = true; // Always allow WebFont use.
  3949           forcedWebFont = true;
  3954     if (!forcedWebFont && generic == kGenericFont_NONE)
  3955       mPresContext->AddFontAttempt(font->mFont);
  3957     // If we aren't allowed to use document fonts, then we are only entitled
  3958     // to use the user's default variable-width font and fixed-width font
  3959     if (!isXUL && (!useDocumentFonts ||
  3960                     mPresContext->FontAttemptCountReached(font->mFont) ||
  3961                     mPresContext->FontUseCountReached(font->mFont))) {
  3962       // Extract the generic from the specified font family...
  3963       nsAutoString genericName;
  3964       if (!font->mFont.EnumerateFamilies(ExtractGeneric, &genericName)) {
  3965         // The specified font had a generic family.
  3966         font->mFont.name = genericName;
  3967         nsFont::GetGenericID(genericName, &generic);
  3969         // ... and only use it if it's -moz-fixed or monospace
  3970         if (generic != kGenericFont_moz_fixed &&
  3971             generic != kGenericFont_monospace) {
  3972           font->mFont.name.Truncate();
  3973           generic = kGenericFont_NONE;
  3975       } else {
  3976         // The specified font did not have a generic family.
  3977         font->mFont.name.Truncate();
  3978         generic = kGenericFont_NONE;
  3983   // Now compute our font struct
  3984   if (generic == kGenericFont_NONE) {
  3985     // continue the normal processing
  3986     nsRuleNode::SetFont(mPresContext, aContext, generic,
  3987                         aRuleData, parentFont, font,
  3988                         aStartStruct != nullptr, canStoreInRuleTree);
  3990   else {
  3991     // re-calculate the font as a generic font
  3992     canStoreInRuleTree = false;
  3993     nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
  3994                                font);
  3997   if (!forcedWebFont && font->mGenericID == kGenericFont_NONE)
  3998     mPresContext->AddFontUse(font->mFont);
  3999   COMPUTE_END_INHERITED(Font, font)
  4002 template <typename T>
  4003 inline uint32_t ListLength(const T* aList)
  4005   uint32_t len = 0;
  4006   while (aList) {
  4007     len++;
  4008     aList = aList->mNext;
  4010   return len;
  4015 already_AddRefed<nsCSSShadowArray>
  4016 nsRuleNode::GetShadowData(const nsCSSValueList* aList,
  4017                           nsStyleContext* aContext,
  4018                           bool aIsBoxShadow,
  4019                           bool& aCanStoreInRuleTree)
  4021   uint32_t arrayLength = ListLength(aList);
  4023   NS_ABORT_IF_FALSE(arrayLength > 0,
  4024                     "Non-null text-shadow list, yet we counted 0 items.");
  4025   nsRefPtr<nsCSSShadowArray> shadowList =
  4026     new(arrayLength) nsCSSShadowArray(arrayLength);
  4028   if (!shadowList)
  4029     return nullptr;
  4031   nsStyleCoord tempCoord;
  4032   DebugOnly<bool> unitOK;
  4033   for (nsCSSShadowItem* item = shadowList->ShadowAt(0);
  4034        aList;
  4035        aList = aList->mNext, ++item) {
  4036     NS_ABORT_IF_FALSE(aList->mValue.GetUnit() == eCSSUnit_Array,
  4037                       "expecting a plain array value");
  4038     nsCSSValue::Array *arr = aList->mValue.GetArrayValue();
  4039     // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
  4040     unitOK = SetCoord(arr->Item(0), tempCoord, nsStyleCoord(),
  4041                       SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
  4042                       aContext, mPresContext, aCanStoreInRuleTree);
  4043     NS_ASSERTION(unitOK, "unexpected unit");
  4044     item->mXOffset = tempCoord.GetCoordValue();
  4046     unitOK = SetCoord(arr->Item(1), tempCoord, nsStyleCoord(),
  4047                       SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
  4048                       aContext, mPresContext, aCanStoreInRuleTree);
  4049     NS_ASSERTION(unitOK, "unexpected unit");
  4050     item->mYOffset = tempCoord.GetCoordValue();
  4052     // Blur radius is optional in the current box-shadow spec
  4053     if (arr->Item(2).GetUnit() != eCSSUnit_Null) {
  4054       unitOK = SetCoord(arr->Item(2), tempCoord, nsStyleCoord(),
  4055                         SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY |
  4056                           SETCOORD_CALC_CLAMP_NONNEGATIVE,
  4057                         aContext, mPresContext, aCanStoreInRuleTree);
  4058       NS_ASSERTION(unitOK, "unexpected unit");
  4059       item->mRadius = tempCoord.GetCoordValue();
  4060     } else {
  4061       item->mRadius = 0;
  4064     // Find the spread radius
  4065     if (aIsBoxShadow && arr->Item(3).GetUnit() != eCSSUnit_Null) {
  4066       unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(),
  4067                         SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
  4068                         aContext, mPresContext, aCanStoreInRuleTree);
  4069       NS_ASSERTION(unitOK, "unexpected unit");
  4070       item->mSpread = tempCoord.GetCoordValue();
  4071     } else {
  4072       item->mSpread = 0;
  4075     if (arr->Item(4).GetUnit() != eCSSUnit_Null) {
  4076       item->mHasColor = true;
  4077       // 2nd argument can be bogus since inherit is not a valid color
  4078       unitOK = SetColor(arr->Item(4), 0, mPresContext, aContext, item->mColor,
  4079                         aCanStoreInRuleTree);
  4080       NS_ASSERTION(unitOK, "unexpected unit");
  4083     if (aIsBoxShadow && arr->Item(5).GetUnit() == eCSSUnit_Enumerated) {
  4084       NS_ASSERTION(arr->Item(5).GetIntValue() == NS_STYLE_BOX_SHADOW_INSET,
  4085                    "invalid keyword type for box shadow");
  4086       item->mInset = true;
  4087     } else {
  4088       item->mInset = false;
  4092   return shadowList.forget();
  4095 const void*
  4096 nsRuleNode::ComputeTextData(void* aStartStruct,
  4097                             const nsRuleData* aRuleData,
  4098                             nsStyleContext* aContext,
  4099                             nsRuleNode* aHighestNode,
  4100                             const RuleDetail aRuleDetail,
  4101                             const bool aCanStoreInRuleTree)
  4103   COMPUTE_START_INHERITED(Text, (), text, parentText)
  4105   // tab-size: integer, inherit
  4106   SetDiscrete(*aRuleData->ValueForTabSize(),
  4107               text->mTabSize, canStoreInRuleTree,
  4108               SETDSC_INTEGER | SETDSC_UNSET_INHERIT, parentText->mTabSize,
  4109               NS_STYLE_TABSIZE_INITIAL, 0, 0, 0, 0);
  4111   // letter-spacing: normal, length, inherit
  4112   SetCoord(*aRuleData->ValueForLetterSpacing(),
  4113            text->mLetterSpacing, parentText->mLetterSpacing,
  4114            SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
  4115              SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INHERIT,
  4116            aContext, mPresContext, canStoreInRuleTree);
  4118   // text-shadow: none, list, inherit, initial
  4119   const nsCSSValue* textShadowValue = aRuleData->ValueForTextShadow();
  4120   if (textShadowValue->GetUnit() != eCSSUnit_Null) {
  4121     text->mTextShadow = nullptr;
  4123     // Don't need to handle none/initial explicitly: The above assignment
  4124     // takes care of that
  4125     if (textShadowValue->GetUnit() == eCSSUnit_Inherit ||
  4126         textShadowValue->GetUnit() == eCSSUnit_Unset) {
  4127       canStoreInRuleTree = false;
  4128       text->mTextShadow = parentText->mTextShadow;
  4129     } else if (textShadowValue->GetUnit() == eCSSUnit_List ||
  4130                textShadowValue->GetUnit() == eCSSUnit_ListDep) {
  4131       // List of arrays
  4132       text->mTextShadow = GetShadowData(textShadowValue->GetListValue(),
  4133                                         aContext, false, canStoreInRuleTree);
  4137   // line-height: normal, number, length, percent, inherit
  4138   const nsCSSValue* lineHeightValue = aRuleData->ValueForLineHeight();
  4139   if (eCSSUnit_Percent == lineHeightValue->GetUnit()) {
  4140     canStoreInRuleTree = false;
  4141     // Use |mFont.size| to pick up minimum font size.
  4142     text->mLineHeight.SetCoordValue(
  4143         NSToCoordRound(float(aContext->StyleFont()->mFont.size) *
  4144                        lineHeightValue->GetPercentValue()));
  4146   else if (eCSSUnit_Initial == lineHeightValue->GetUnit() ||
  4147            eCSSUnit_System_Font == lineHeightValue->GetUnit()) {
  4148     text->mLineHeight.SetNormalValue();
  4150   else {
  4151     SetCoord(*lineHeightValue, text->mLineHeight, parentText->mLineHeight,
  4152              SETCOORD_LEH | SETCOORD_FACTOR | SETCOORD_NORMAL |
  4153                SETCOORD_UNSET_INHERIT,
  4154              aContext, mPresContext, canStoreInRuleTree);
  4155     if (lineHeightValue->IsLengthUnit() &&
  4156         !lineHeightValue->IsRelativeLengthUnit()) {
  4157       nscoord lh = nsStyleFont::ZoomText(mPresContext,
  4158                                          text->mLineHeight.GetCoordValue());
  4160       canStoreInRuleTree = false;
  4161       const nsStyleFont *font = aContext->StyleFont();
  4162       nscoord minimumFontSize = mPresContext->MinFontSize(font->mLanguage);
  4164       if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
  4165         if (font->mSize != 0) {
  4166           lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
  4167         } else {
  4168           lh = minimumFontSize;
  4171       text->mLineHeight.SetCoordValue(lh);
  4176   // text-align: enum, string, pair(enum|string), inherit, initial
  4177   // NOTE: string is not implemented yet.
  4178   const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
  4179   text->mTextAlignTrue = false;
  4180   if (eCSSUnit_String == textAlignValue->GetUnit()) {
  4181     NS_NOTYETIMPLEMENTED("align string");
  4182   } else if (eCSSUnit_Enumerated == textAlignValue->GetUnit() &&
  4183              NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT ==
  4184                textAlignValue->GetIntValue()) {
  4185     canStoreInRuleTree = false;
  4186     uint8_t parentAlign = parentText->mTextAlign;
  4187     text->mTextAlign = (NS_STYLE_TEXT_ALIGN_DEFAULT == parentAlign) ?
  4188       NS_STYLE_TEXT_ALIGN_CENTER : parentAlign;
  4189   } else {
  4190     if (eCSSUnit_Pair == textAlignValue->GetUnit()) {
  4191       // Two values were specified, one must be 'true'.
  4192       text->mTextAlignTrue = true;
  4193       const nsCSSValuePair& textAlignValuePair = textAlignValue->GetPairValue();
  4194       textAlignValue = &textAlignValuePair.mXValue;
  4195       if (eCSSUnit_Enumerated == textAlignValue->GetUnit()) {
  4196         if (textAlignValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
  4197           textAlignValue = &textAlignValuePair.mYValue;
  4199       } else if (eCSSUnit_String == textAlignValue->GetUnit()) {
  4200         NS_NOTYETIMPLEMENTED("align string");
  4202     } else if (eCSSUnit_Inherit == textAlignValue->GetUnit() ||
  4203                eCSSUnit_Unset == textAlignValue->GetUnit()) {
  4204       text->mTextAlignTrue = parentText->mTextAlignTrue;
  4206     SetDiscrete(*textAlignValue, text->mTextAlign, canStoreInRuleTree,
  4207                 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4208                 parentText->mTextAlign,
  4209                 NS_STYLE_TEXT_ALIGN_DEFAULT, 0, 0, 0, 0);
  4212   // text-align-last: enum, pair(enum), inherit, initial
  4213   const nsCSSValue* textAlignLastValue = aRuleData->ValueForTextAlignLast();
  4214   text->mTextAlignLastTrue = false;
  4215   if (eCSSUnit_Pair == textAlignLastValue->GetUnit()) {
  4216     // Two values were specified, one must be 'true'.
  4217     text->mTextAlignLastTrue = true;
  4218     const nsCSSValuePair& textAlignLastValuePair = textAlignLastValue->GetPairValue();
  4219     textAlignLastValue = &textAlignLastValuePair.mXValue;
  4220     if (eCSSUnit_Enumerated == textAlignLastValue->GetUnit()) {
  4221       if (textAlignLastValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
  4222         textAlignLastValue = &textAlignLastValuePair.mYValue;
  4225   } else if (eCSSUnit_Inherit == textAlignLastValue->GetUnit() ||
  4226              eCSSUnit_Unset == textAlignLastValue->GetUnit()) {
  4227     text->mTextAlignLastTrue = parentText->mTextAlignLastTrue;
  4229   SetDiscrete(*textAlignLastValue, text->mTextAlignLast,
  4230               canStoreInRuleTree,
  4231               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4232               parentText->mTextAlignLast,
  4233               NS_STYLE_TEXT_ALIGN_AUTO, 0, 0, 0, 0);
  4235   // text-indent: length, percent, calc, inherit, initial
  4236   SetCoord(*aRuleData->ValueForTextIndent(), text->mTextIndent, parentText->mTextIndent,
  4237            SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  4238              SETCOORD_UNSET_INHERIT,
  4239            aContext, mPresContext, canStoreInRuleTree);
  4241   // text-transform: enum, inherit, initial
  4242   SetDiscrete(*aRuleData->ValueForTextTransform(), text->mTextTransform, canStoreInRuleTree,
  4243               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4244               parentText->mTextTransform,
  4245               NS_STYLE_TEXT_TRANSFORM_NONE, 0, 0, 0, 0);
  4247   // white-space: enum, inherit, initial
  4248   SetDiscrete(*aRuleData->ValueForWhiteSpace(), text->mWhiteSpace, canStoreInRuleTree,
  4249               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4250               parentText->mWhiteSpace,
  4251               NS_STYLE_WHITESPACE_NORMAL, 0, 0, 0, 0);
  4253   // word-break: enum, inherit, initial
  4254   SetDiscrete(*aRuleData->ValueForWordBreak(), text->mWordBreak, canStoreInRuleTree,
  4255               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4256               parentText->mWordBreak,
  4257               NS_STYLE_WORDBREAK_NORMAL, 0, 0, 0, 0);
  4259   // word-spacing: normal, length, inherit
  4260   nsStyleCoord tempCoord;
  4261   const nsCSSValue* wordSpacingValue = aRuleData->ValueForWordSpacing();
  4262   if (SetCoord(*wordSpacingValue, tempCoord,
  4263                nsStyleCoord(parentText->mWordSpacing,
  4264                             nsStyleCoord::CoordConstructor),
  4265                SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
  4266                  SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INHERIT,
  4267                aContext, mPresContext, canStoreInRuleTree)) {
  4268     if (tempCoord.GetUnit() == eStyleUnit_Coord) {
  4269       text->mWordSpacing = tempCoord.GetCoordValue();
  4270     } else if (tempCoord.GetUnit() == eStyleUnit_Normal) {
  4271       text->mWordSpacing = 0;
  4272     } else {
  4273       NS_NOTREACHED("unexpected unit");
  4275   } else {
  4276     NS_ASSERTION(wordSpacingValue->GetUnit() == eCSSUnit_Null,
  4277                  "unexpected unit");
  4280   // word-wrap: enum, inherit, initial
  4281   SetDiscrete(*aRuleData->ValueForWordWrap(), text->mWordWrap, canStoreInRuleTree,
  4282               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4283               parentText->mWordWrap,
  4284               NS_STYLE_WORDWRAP_NORMAL, 0, 0, 0, 0);
  4286   // hyphens: enum, inherit, initial
  4287   SetDiscrete(*aRuleData->ValueForHyphens(), text->mHyphens, canStoreInRuleTree,
  4288               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4289               parentText->mHyphens,
  4290               NS_STYLE_HYPHENS_MANUAL, 0, 0, 0, 0);
  4292   // text-size-adjust: none, auto, inherit, initial
  4293   SetDiscrete(*aRuleData->ValueForTextSizeAdjust(), text->mTextSizeAdjust,
  4294               canStoreInRuleTree,
  4295               SETDSC_NONE | SETDSC_AUTO | SETDSC_UNSET_INHERIT,
  4296               parentText->mTextSizeAdjust,
  4297               NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // initial value
  4298               NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // auto value
  4299               NS_STYLE_TEXT_SIZE_ADJUST_NONE, // none value
  4300               0, 0);
  4302   // -moz-text-discard: enum, inherit, initial
  4303   SetDiscrete(*aRuleData->ValueForControlCharacterVisibility(),
  4304               text->mControlCharacterVisibility,
  4305               canStoreInRuleTree,
  4306               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4307               parentText->mControlCharacterVisibility,
  4308               NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN, 0, 0, 0, 0);
  4310   // text-orientation: enum, inherit, initial
  4311   SetDiscrete(*aRuleData->ValueForTextOrientation(), text->mTextOrientation,
  4312               canStoreInRuleTree,
  4313               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4314               parentText->mTextOrientation,
  4315               NS_STYLE_TEXT_ORIENTATION_AUTO, 0, 0, 0, 0);
  4317   // text-combine-upright: enum, inherit, initial
  4318   SetDiscrete(*aRuleData->ValueForTextCombineUpright(),
  4319               text->mTextCombineUpright,
  4320               canStoreInRuleTree,
  4321               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4322               parentText->mTextCombineUpright,
  4323               NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE, 0, 0, 0, 0);
  4325   COMPUTE_END_INHERITED(Text, text)
  4328 const void*
  4329 nsRuleNode::ComputeTextResetData(void* aStartStruct,
  4330                                  const nsRuleData* aRuleData,
  4331                                  nsStyleContext* aContext,
  4332                                  nsRuleNode* aHighestNode,
  4333                                  const RuleDetail aRuleDetail,
  4334                                  const bool aCanStoreInRuleTree)
  4336   COMPUTE_START_RESET(TextReset, (), text, parentText)
  4338   // vertical-align: enum, length, percent, calc, inherit
  4339   const nsCSSValue* verticalAlignValue = aRuleData->ValueForVerticalAlign();
  4340   if (!SetCoord(*verticalAlignValue, text->mVerticalAlign,
  4341                 parentText->mVerticalAlign,
  4342                 SETCOORD_LPH | SETCOORD_ENUMERATED | SETCOORD_STORE_CALC,
  4343                 aContext, mPresContext, canStoreInRuleTree)) {
  4344     if (eCSSUnit_Initial == verticalAlignValue->GetUnit() ||
  4345         eCSSUnit_Unset == verticalAlignValue->GetUnit()) {
  4346       text->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE,
  4347                                        eStyleUnit_Enumerated);
  4351   // text-decoration-line: enum (bit field), inherit, initial
  4352   const nsCSSValue* decorationLineValue =
  4353     aRuleData->ValueForTextDecorationLine();
  4354   if (eCSSUnit_Enumerated == decorationLineValue->GetUnit()) {
  4355     int32_t td = decorationLineValue->GetIntValue();
  4356     text->mTextDecorationLine = td;
  4357     if (td & NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS) {
  4358       bool underlineLinks =
  4359         mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
  4360       if (underlineLinks) {
  4361         text->mTextDecorationLine |= NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
  4363       else {
  4364         text->mTextDecorationLine &= ~NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
  4367   } else if (eCSSUnit_Inherit == decorationLineValue->GetUnit()) {
  4368     canStoreInRuleTree = false;
  4369     text->mTextDecorationLine = parentText->mTextDecorationLine;
  4370   } else if (eCSSUnit_Initial == decorationLineValue->GetUnit() ||
  4371              eCSSUnit_Unset == decorationLineValue->GetUnit()) {
  4372     text->mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
  4375   // text-decoration-color: color, string, enum, inherit, initial
  4376   const nsCSSValue* decorationColorValue =
  4377     aRuleData->ValueForTextDecorationColor();
  4378   nscolor decorationColor;
  4379   if (eCSSUnit_Inherit == decorationColorValue->GetUnit()) {
  4380     canStoreInRuleTree = false;
  4381     if (parentContext) {
  4382       bool isForeground;
  4383       parentText->GetDecorationColor(decorationColor, isForeground);
  4384       if (isForeground) {
  4385         text->SetDecorationColor(parentContext->StyleColor()->mColor);
  4386       } else {
  4387         text->SetDecorationColor(decorationColor);
  4389     } else {
  4390       text->SetDecorationColorToForeground();
  4393   else if (eCSSUnit_EnumColor == decorationColorValue->GetUnit() &&
  4394            decorationColorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
  4395     text->SetDecorationColorToForeground();
  4397   else if (SetColor(*decorationColorValue, 0, mPresContext, aContext,
  4398                     decorationColor, canStoreInRuleTree)) {
  4399     text->SetDecorationColor(decorationColor);
  4401   else if (eCSSUnit_Initial == decorationColorValue->GetUnit() ||
  4402            eCSSUnit_Unset == decorationColorValue->GetUnit() ||
  4403            eCSSUnit_Enumerated == decorationColorValue->GetUnit()) {
  4404     NS_ABORT_IF_FALSE(eCSSUnit_Enumerated != decorationColorValue->GetUnit() ||
  4405                       decorationColorValue->GetIntValue() ==
  4406                         NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,
  4407                       "unexpected enumerated value");
  4408     text->SetDecorationColorToForeground();
  4411   // text-decoration-style: enum, inherit, initial
  4412   const nsCSSValue* decorationStyleValue =
  4413     aRuleData->ValueForTextDecorationStyle();
  4414   if (eCSSUnit_Enumerated == decorationStyleValue->GetUnit()) {
  4415     text->SetDecorationStyle(decorationStyleValue->GetIntValue());
  4416   } else if (eCSSUnit_Inherit == decorationStyleValue->GetUnit()) {
  4417     text->SetDecorationStyle(parentText->GetDecorationStyle());
  4418     canStoreInRuleTree = false;
  4419   } else if (eCSSUnit_Initial == decorationStyleValue->GetUnit() ||
  4420              eCSSUnit_Unset == decorationStyleValue->GetUnit()) {
  4421     text->SetDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID);
  4424   // text-overflow: enum, string, pair(enum|string), inherit, initial
  4425   const nsCSSValue* textOverflowValue =
  4426     aRuleData->ValueForTextOverflow();
  4427   if (eCSSUnit_Initial == textOverflowValue->GetUnit() ||
  4428       eCSSUnit_Unset == textOverflowValue->GetUnit()) {
  4429     text->mTextOverflow = nsStyleTextOverflow();
  4430   } else if (eCSSUnit_Inherit == textOverflowValue->GetUnit()) {
  4431     canStoreInRuleTree = false;
  4432     text->mTextOverflow = parentText->mTextOverflow;
  4433   } else if (eCSSUnit_Enumerated == textOverflowValue->GetUnit()) {
  4434     // A single enumerated value.
  4435     SetDiscrete(*textOverflowValue, text->mTextOverflow.mRight.mType,
  4436                 canStoreInRuleTree,
  4437                 SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
  4438                 NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
  4439     text->mTextOverflow.mRight.mString.Truncate();
  4440     text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
  4441     text->mTextOverflow.mLeft.mString.Truncate();
  4442     text->mTextOverflow.mLogicalDirections = true;
  4443   } else if (eCSSUnit_String == textOverflowValue->GetUnit()) {
  4444     // A single string value.
  4445     text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
  4446     textOverflowValue->GetStringValue(text->mTextOverflow.mRight.mString);
  4447     text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
  4448     text->mTextOverflow.mLeft.mString.Truncate();
  4449     text->mTextOverflow.mLogicalDirections = true;
  4450   } else if (eCSSUnit_Pair == textOverflowValue->GetUnit()) {
  4451     // Two values were specified.
  4452     text->mTextOverflow.mLogicalDirections = false;
  4453     const nsCSSValuePair& textOverflowValuePair =
  4454       textOverflowValue->GetPairValue();
  4456     const nsCSSValue *textOverflowLeftValue = &textOverflowValuePair.mXValue;
  4457     if (eCSSUnit_Enumerated == textOverflowLeftValue->GetUnit()) {
  4458       SetDiscrete(*textOverflowLeftValue, text->mTextOverflow.mLeft.mType,
  4459                   canStoreInRuleTree,
  4460                   SETDSC_ENUMERATED, parentText->mTextOverflow.mLeft.mType,
  4461                   NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
  4462       text->mTextOverflow.mLeft.mString.Truncate();
  4463     } else if (eCSSUnit_String == textOverflowLeftValue->GetUnit()) {
  4464       textOverflowLeftValue->GetStringValue(text->mTextOverflow.mLeft.mString);
  4465       text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
  4468     const nsCSSValue *textOverflowRightValue = &textOverflowValuePair.mYValue;
  4469     if (eCSSUnit_Enumerated == textOverflowRightValue->GetUnit()) {
  4470       SetDiscrete(*textOverflowRightValue, text->mTextOverflow.mRight.mType,
  4471                   canStoreInRuleTree,
  4472                   SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
  4473                   NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
  4474       text->mTextOverflow.mRight.mString.Truncate();
  4475     } else if (eCSSUnit_String == textOverflowRightValue->GetUnit()) {
  4476       textOverflowRightValue->GetStringValue(text->mTextOverflow.mRight.mString);
  4477       text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
  4481   // unicode-bidi: enum, inherit, initial
  4482   SetDiscrete(*aRuleData->ValueForUnicodeBidi(), text->mUnicodeBidi, canStoreInRuleTree,
  4483               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  4484               parentText->mUnicodeBidi,
  4485               NS_STYLE_UNICODE_BIDI_NORMAL, 0, 0, 0, 0);
  4487   COMPUTE_END_RESET(TextReset, text)
  4490 const void*
  4491 nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
  4492                                      const nsRuleData* aRuleData,
  4493                                      nsStyleContext* aContext,
  4494                                      nsRuleNode* aHighestNode,
  4495                                      const RuleDetail aRuleDetail,
  4496                                      const bool aCanStoreInRuleTree)
  4498   COMPUTE_START_INHERITED(UserInterface, (), ui, parentUI)
  4500   // cursor: enum, url, inherit
  4501   const nsCSSValue* cursorValue = aRuleData->ValueForCursor();
  4502   nsCSSUnit cursorUnit = cursorValue->GetUnit();
  4503   if (cursorUnit != eCSSUnit_Null) {
  4504     delete [] ui->mCursorArray;
  4505     ui->mCursorArray = nullptr;
  4506     ui->mCursorArrayLength = 0;
  4508     if (cursorUnit == eCSSUnit_Inherit ||
  4509         cursorUnit == eCSSUnit_Unset) {
  4510       canStoreInRuleTree = false;
  4511       ui->mCursor = parentUI->mCursor;
  4512       ui->CopyCursorArrayFrom(*parentUI);
  4514     else if (cursorUnit == eCSSUnit_Initial) {
  4515       ui->mCursor = NS_STYLE_CURSOR_AUTO;
  4517     else {
  4518       // The parser will never create a list that is *all* URL values --
  4519       // that's invalid.
  4520       NS_ABORT_IF_FALSE(cursorUnit == eCSSUnit_List ||
  4521                         cursorUnit == eCSSUnit_ListDep,
  4522                         nsPrintfCString("unrecognized cursor unit %d",
  4523                                         cursorUnit).get());
  4524       const nsCSSValueList* list = cursorValue->GetListValue();
  4525       const nsCSSValueList* list2 = list;
  4526       nsIDocument* doc = aContext->PresContext()->Document();
  4527       uint32_t arrayLength = 0;
  4528       for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext)
  4529         if (list->mValue.GetArrayValue()->Item(0).GetImageValue(doc))
  4530           ++arrayLength;
  4532       if (arrayLength != 0) {
  4533         ui->mCursorArray = new nsCursorImage[arrayLength];
  4534         if (ui->mCursorArray) {
  4535           ui->mCursorArrayLength = arrayLength;
  4537           for (nsCursorImage *item = ui->mCursorArray;
  4538                list2->mValue.GetUnit() == eCSSUnit_Array;
  4539                list2 = list2->mNext) {
  4540             nsCSSValue::Array *arr = list2->mValue.GetArrayValue();
  4541             imgIRequest *req = arr->Item(0).GetImageValue(doc);
  4542             if (req) {
  4543               item->SetImage(req);
  4544               if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
  4545                 item->mHaveHotspot = true;
  4546                 item->mHotspotX = arr->Item(1).GetFloatValue(),
  4547                 item->mHotspotY = arr->Item(2).GetFloatValue();
  4549               ++item;
  4555       NS_ASSERTION(list, "Must have non-array value at the end");
  4556       NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated,
  4557                    "Unexpected fallback value at end of cursor list");
  4558       ui->mCursor = list->mValue.GetIntValue();
  4562   // user-input: enum, inherit, initial
  4563   SetDiscrete(*aRuleData->ValueForUserInput(),
  4564               ui->mUserInput, canStoreInRuleTree,
  4565               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4566               parentUI->mUserInput,
  4567               NS_STYLE_USER_INPUT_AUTO, 0, 0, 0, 0);
  4569   // user-modify: enum, inherit, initial
  4570   SetDiscrete(*aRuleData->ValueForUserModify(),
  4571               ui->mUserModify, canStoreInRuleTree,
  4572               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4573               parentUI->mUserModify,
  4574               NS_STYLE_USER_MODIFY_READ_ONLY,
  4575               0, 0, 0, 0);
  4577   // user-focus: enum, inherit, initial
  4578   SetDiscrete(*aRuleData->ValueForUserFocus(),
  4579               ui->mUserFocus, canStoreInRuleTree,
  4580               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  4581               parentUI->mUserFocus,
  4582               NS_STYLE_USER_FOCUS_NONE, 0, 0, 0, 0);
  4584   COMPUTE_END_INHERITED(UserInterface, ui)
  4587 const void*
  4588 nsRuleNode::ComputeUIResetData(void* aStartStruct,
  4589                                const nsRuleData* aRuleData,
  4590                                nsStyleContext* aContext,
  4591                                nsRuleNode* aHighestNode,
  4592                                const RuleDetail aRuleDetail,
  4593                                const bool aCanStoreInRuleTree)
  4595   COMPUTE_START_RESET(UIReset, (), ui, parentUI)
  4597   // user-select: enum, inherit, initial
  4598   SetDiscrete(*aRuleData->ValueForUserSelect(),
  4599               ui->mUserSelect, canStoreInRuleTree,
  4600               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  4601               parentUI->mUserSelect,
  4602               NS_STYLE_USER_SELECT_AUTO, 0, 0, 0, 0);
  4604   // ime-mode: enum, inherit, initial
  4605   SetDiscrete(*aRuleData->ValueForImeMode(),
  4606               ui->mIMEMode, canStoreInRuleTree,
  4607               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  4608               parentUI->mIMEMode,
  4609               NS_STYLE_IME_MODE_AUTO, 0, 0, 0, 0);
  4611   // force-broken-image-icons: integer, inherit, initial
  4612   SetDiscrete(*aRuleData->ValueForForceBrokenImageIcon(),
  4613               ui->mForceBrokenImageIcon,
  4614               canStoreInRuleTree,
  4615               SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
  4616               parentUI->mForceBrokenImageIcon,
  4617               0, 0, 0, 0, 0);
  4619   // -moz-window-shadow: enum, inherit, initial
  4620   SetDiscrete(*aRuleData->ValueForWindowShadow(),
  4621               ui->mWindowShadow, canStoreInRuleTree,
  4622               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  4623               parentUI->mWindowShadow,
  4624               NS_STYLE_WINDOW_SHADOW_DEFAULT, 0, 0, 0, 0);
  4626   COMPUTE_END_RESET(UIReset, ui)
  4629 // Information about each transition or animation property that is
  4630 // constant.
  4631 struct TransitionPropInfo {
  4632   nsCSSProperty property;
  4633   // Location of the count of the property's computed value.
  4634   uint32_t nsStyleDisplay::* sdCount;
  4635 };
  4637 // Each property's index in this array must match its index in the
  4638 // mutable array |transitionPropData| below.
  4639 static const TransitionPropInfo transitionPropInfo[4] = {
  4640   { eCSSProperty_transition_delay,
  4641     &nsStyleDisplay::mTransitionDelayCount },
  4642   { eCSSProperty_transition_duration,
  4643     &nsStyleDisplay::mTransitionDurationCount },
  4644   { eCSSProperty_transition_property,
  4645     &nsStyleDisplay::mTransitionPropertyCount },
  4646   { eCSSProperty_transition_timing_function,
  4647     &nsStyleDisplay::mTransitionTimingFunctionCount },
  4648 };
  4650 // Each property's index in this array must match its index in the
  4651 // mutable array |animationPropData| below.
  4652 static const TransitionPropInfo animationPropInfo[8] = {
  4653   { eCSSProperty_animation_delay,
  4654     &nsStyleDisplay::mAnimationDelayCount },
  4655   { eCSSProperty_animation_duration,
  4656     &nsStyleDisplay::mAnimationDurationCount },
  4657   { eCSSProperty_animation_name,
  4658     &nsStyleDisplay::mAnimationNameCount },
  4659   { eCSSProperty_animation_timing_function,
  4660     &nsStyleDisplay::mAnimationTimingFunctionCount },
  4661   { eCSSProperty_animation_direction,
  4662     &nsStyleDisplay::mAnimationDirectionCount },
  4663   { eCSSProperty_animation_fill_mode,
  4664     &nsStyleDisplay::mAnimationFillModeCount },
  4665   { eCSSProperty_animation_play_state,
  4666     &nsStyleDisplay::mAnimationPlayStateCount },
  4667   { eCSSProperty_animation_iteration_count,
  4668     &nsStyleDisplay::mAnimationIterationCountCount },
  4669 };
  4671 // Information about each transition or animation property that changes
  4672 // during ComputeDisplayData.
  4673 struct TransitionPropData {
  4674   const nsCSSValueList *list;
  4675   nsCSSUnit unit;
  4676   uint32_t num;
  4677 };
  4679 static uint32_t
  4680 CountTransitionProps(const TransitionPropInfo* aInfo,
  4681                      TransitionPropData* aData,
  4682                      size_t aLength,
  4683                      nsStyleDisplay* aDisplay,
  4684                      const nsStyleDisplay* aParentDisplay,
  4685                      const nsRuleData* aRuleData,
  4686                      bool& aCanStoreInRuleTree)
  4688   // The four transition properties or eight animation properties are
  4689   // stored in nsCSSDisplay in a single array for all properties.  The
  4690   // number of transitions is equal to the number of items in the
  4691   // longest property's value.  Properties that have fewer values than
  4692   // the longest are filled in by repeating the list.  However, this
  4693   // repetition does not extend the computed value of that particular
  4694   // property (for purposes of inheritance, or, in our code, for when
  4695   // other properties are overridden by a more specific rule).
  4697   // But actually, since the spec isn't clear yet, we'll fully compute
  4698   // all of them (so we can switch easily later), but only care about
  4699   // the ones up to the number of items for 'transition-property', per
  4700   // http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html .
  4702   // Transitions are difficult to handle correctly because of this.  For
  4703   // example, we need to handle scenarios such as:
  4704   //  * a more general rule specifies transition-property: a, b, c;
  4705   //  * a more specific rule overrides as transition-property: d;
  4706   //
  4707   // If only the general rule applied, we would fill in the extra
  4708   // properties (duration, delay, etc) with initial values to create 3
  4709   // fully-specified transitions.  But when the more specific rule
  4710   // applies, we should only create a single transition.  In order to do
  4711   // this we need to remember which properties were explicitly specified
  4712   // and which ones were just filled in with initial values to get a
  4713   // fully-specified transition, which we do by remembering the number
  4714   // of values for each property.
  4716   uint32_t numTransitions = 0;
  4717   for (size_t i = 0; i < aLength; ++i) {
  4718     const TransitionPropInfo& info = aInfo[i];
  4719     TransitionPropData& data = aData[i];
  4721     // cache whether any of the properties are specified as 'inherit' so
  4722     // we can use it below
  4724     const nsCSSValue& value = *aRuleData->ValueFor(info.property);
  4725     data.unit = value.GetUnit();
  4726     data.list = (value.GetUnit() == eCSSUnit_List ||
  4727                  value.GetUnit() == eCSSUnit_ListDep)
  4728                   ? value.GetListValue() : nullptr;
  4730     // General algorithm to determine how many total transitions we need
  4731     // to build.  For each property:
  4732     //  - if there is no value specified in for the property in
  4733     //    displayData, use the values from the start struct, but only if
  4734     //    they were explicitly specified
  4735     //  - if there is a value specified for the property in displayData:
  4736     //    - if the value is 'inherit', count the number of values for
  4737     //      that property are specified by the parent, but only those
  4738     //      that were explicitly specified
  4739     //    - otherwise, count the number of values specified in displayData
  4742     // calculate number of elements
  4743     if (data.unit == eCSSUnit_Inherit) {
  4744       data.num = aParentDisplay->*(info.sdCount);
  4745       aCanStoreInRuleTree = false;
  4746     } else if (data.list) {
  4747       data.num = ListLength(data.list);
  4748     } else {
  4749       data.num = aDisplay->*(info.sdCount);
  4751     if (data.num > numTransitions)
  4752       numTransitions = data.num;
  4755   return numTransitions;
  4758 static void
  4759 ComputeTimingFunction(const nsCSSValue& aValue, nsTimingFunction& aResult)
  4761   switch (aValue.GetUnit()) {
  4762     case eCSSUnit_Enumerated:
  4763       aResult = nsTimingFunction(aValue.GetIntValue());
  4764       break;
  4765     case eCSSUnit_Cubic_Bezier:
  4767         nsCSSValue::Array* array = aValue.GetArrayValue();
  4768         NS_ASSERTION(array && array->Count() == 4,
  4769                      "Need 4 control points");
  4770         aResult = nsTimingFunction(array->Item(0).GetFloatValue(),
  4771                                    array->Item(1).GetFloatValue(),
  4772                                    array->Item(2).GetFloatValue(),
  4773                                    array->Item(3).GetFloatValue());
  4775       break;
  4776     case eCSSUnit_Steps:
  4778         nsCSSValue::Array* array = aValue.GetArrayValue();
  4779         NS_ASSERTION(array && array->Count() == 2,
  4780                      "Need 2 items");
  4781         NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
  4782                      "unexpected first value");
  4783         NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
  4784                      (array->Item(1).GetIntValue() ==
  4785                        NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START ||
  4786                       array->Item(1).GetIntValue() ==
  4787                        NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END),
  4788                      "unexpected second value");
  4789         nsTimingFunction::Type type =
  4790           (array->Item(1).GetIntValue() ==
  4791             NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END)
  4792             ? nsTimingFunction::StepEnd : nsTimingFunction::StepStart;
  4793         aResult = nsTimingFunction(type, array->Item(0).GetIntValue());
  4795       break;
  4796     default:
  4797       NS_NOTREACHED("Invalid transition property unit");
  4801 const void*
  4802 nsRuleNode::ComputeDisplayData(void* aStartStruct,
  4803                                const nsRuleData* aRuleData,
  4804                                nsStyleContext* aContext,
  4805                                nsRuleNode* aHighestNode,
  4806                                const RuleDetail aRuleDetail,
  4807                                const bool aCanStoreInRuleTree)
  4809   COMPUTE_START_RESET(Display, (), display, parentDisplay)
  4811   // We may have ended up with aStartStruct's values of mDisplay and
  4812   // mFloats, but those may not be correct if our style data overrides
  4813   // its position or float properties.  Reset to mOriginalDisplay and
  4814   // mOriginalFloats; it if turns out we still need the display/floats
  4815   // adjustments we'll do them below.
  4816   display->mDisplay = display->mOriginalDisplay;
  4817   display->mFloats = display->mOriginalFloats;
  4819   // Each property's index in this array must match its index in the
  4820   // const array |transitionPropInfo| above.
  4821   TransitionPropData transitionPropData[4];
  4822   TransitionPropData& delay = transitionPropData[0];
  4823   TransitionPropData& duration = transitionPropData[1];
  4824   TransitionPropData& property = transitionPropData[2];
  4825   TransitionPropData& timingFunction = transitionPropData[3];
  4827 #define FOR_ALL_TRANSITION_PROPS(var_) \
  4828                                       for (uint32_t var_ = 0; var_ < 4; ++var_)
  4830   // CSS Transitions
  4831   uint32_t numTransitions =
  4832     CountTransitionProps(transitionPropInfo, transitionPropData,
  4833                          ArrayLength(transitionPropData),
  4834                          display, parentDisplay, aRuleData,
  4835                          canStoreInRuleTree);
  4837   display->mTransitions.SetLength(numTransitions);
  4839   FOR_ALL_TRANSITION_PROPS(p) {
  4840     const TransitionPropInfo& i = transitionPropInfo[p];
  4841     TransitionPropData& d = transitionPropData[p];
  4843     display->*(i.sdCount) = d.num;
  4846   // Fill in the transitions we just allocated with the appropriate values.
  4847   for (uint32_t i = 0; i < numTransitions; ++i) {
  4848     nsTransition *transition = &display->mTransitions[i];
  4850     if (i >= delay.num) {
  4851       transition->SetDelay(display->mTransitions[i % delay.num].GetDelay());
  4852     } else if (delay.unit == eCSSUnit_Inherit) {
  4853       // FIXME (Bug 522599) (for all transition properties): write a test that
  4854       // detects when this was wrong for i >= delay.num if parent had
  4855       // count for this property not equal to length
  4856       NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionDelayCount,
  4857                         "delay.num computed incorrectly");
  4858       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  4859                         "should have made canStoreInRuleTree false above");
  4860       transition->SetDelay(parentDisplay->mTransitions[i].GetDelay());
  4861     } else if (delay.unit == eCSSUnit_Initial ||
  4862                delay.unit == eCSSUnit_Unset) {
  4863       transition->SetDelay(0.0);
  4864     } else if (delay.list) {
  4865       switch (delay.list->mValue.GetUnit()) {
  4866         case eCSSUnit_Seconds:
  4867           transition->SetDelay(PR_MSEC_PER_SEC *
  4868                                delay.list->mValue.GetFloatValue());
  4869           break;
  4870         case eCSSUnit_Milliseconds:
  4871           transition->SetDelay(delay.list->mValue.GetFloatValue());
  4872           break;
  4873         default:
  4874           NS_NOTREACHED("Invalid delay unit");
  4878     if (i >= duration.num) {
  4879       transition->SetDuration(
  4880         display->mTransitions[i % duration.num].GetDuration());
  4881     } else if (duration.unit == eCSSUnit_Inherit) {
  4882       NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionDurationCount,
  4883                         "duration.num computed incorrectly");
  4884       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  4885                         "should have made canStoreInRuleTree false above");
  4886       transition->SetDuration(parentDisplay->mTransitions[i].GetDuration());
  4887     } else if (duration.unit == eCSSUnit_Initial ||
  4888                duration.unit == eCSSUnit_Unset) {
  4889       transition->SetDuration(0.0);
  4890     } else if (duration.list) {
  4891       switch (duration.list->mValue.GetUnit()) {
  4892         case eCSSUnit_Seconds:
  4893           transition->SetDuration(PR_MSEC_PER_SEC *
  4894                                   duration.list->mValue.GetFloatValue());
  4895           break;
  4896         case eCSSUnit_Milliseconds:
  4897           transition->SetDuration(duration.list->mValue.GetFloatValue());
  4898           break;
  4899         default:
  4900           NS_NOTREACHED("Invalid duration unit");
  4904     if (i >= property.num) {
  4905       transition->CopyPropertyFrom(display->mTransitions[i % property.num]);
  4906     } else if (property.unit == eCSSUnit_Inherit) {
  4907       NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionPropertyCount,
  4908                         "property.num computed incorrectly");
  4909       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  4910                         "should have made canStoreInRuleTree false above");
  4911       transition->CopyPropertyFrom(parentDisplay->mTransitions[i]);
  4912     } else if (property.unit == eCSSUnit_Initial ||
  4913                property.unit == eCSSUnit_Unset) {
  4914       transition->SetProperty(eCSSPropertyExtra_all_properties);
  4915     } else if (property.unit == eCSSUnit_None) {
  4916       transition->SetProperty(eCSSPropertyExtra_no_properties);
  4917     } else if (property.list) {
  4918       const nsCSSValue &val = property.list->mValue;
  4920       if (val.GetUnit() == eCSSUnit_Ident) {
  4921         nsDependentString
  4922           propertyStr(property.list->mValue.GetStringBufferValue());
  4923         nsCSSProperty prop =
  4924           nsCSSProps::LookupProperty(propertyStr,
  4925                                      nsCSSProps::eEnabledForAllContent);
  4926         if (prop == eCSSProperty_UNKNOWN) {
  4927           transition->SetUnknownProperty(propertyStr);
  4928         } else {
  4929           transition->SetProperty(prop);
  4931       } else {
  4932         NS_ABORT_IF_FALSE(val.GetUnit() == eCSSUnit_All,
  4933                           nsPrintfCString("Invalid transition property unit %d",
  4934                                           val.GetUnit()).get());
  4935         transition->SetProperty(eCSSPropertyExtra_all_properties);
  4939     if (i >= timingFunction.num) {
  4940       transition->SetTimingFunction(
  4941         display->mTransitions[i % timingFunction.num].GetTimingFunction());
  4942     } else if (timingFunction.unit == eCSSUnit_Inherit) {
  4943       NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionTimingFunctionCount,
  4944                         "timingFunction.num computed incorrectly");
  4945       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  4946                         "should have made canStoreInRuleTree false above");
  4947       transition->SetTimingFunction(
  4948         parentDisplay->mTransitions[i].GetTimingFunction());
  4949     } else if (timingFunction.unit == eCSSUnit_Initial ||
  4950                timingFunction.unit == eCSSUnit_Unset) {
  4951       transition->SetTimingFunction(
  4952         nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
  4953     } else if (timingFunction.list) {
  4954       ComputeTimingFunction(timingFunction.list->mValue,
  4955                             transition->TimingFunctionSlot());
  4958     FOR_ALL_TRANSITION_PROPS(p) {
  4959       const TransitionPropInfo& info = transitionPropInfo[p];
  4960       TransitionPropData& d = transitionPropData[p];
  4962       // if we're at the end of the list, start at the beginning and repeat
  4963       // until we're out of transitions to populate
  4964       if (d.list) {
  4965         d.list = d.list->mNext ? d.list->mNext :
  4966           aRuleData->ValueFor(info.property)->GetListValue();
  4971   // Each property's index in this array must match its index in the
  4972   // const array |animationPropInfo| above.
  4973   TransitionPropData animationPropData[8];
  4974   TransitionPropData& animDelay = animationPropData[0];
  4975   TransitionPropData& animDuration = animationPropData[1];
  4976   TransitionPropData& animName = animationPropData[2];
  4977   TransitionPropData& animTimingFunction = animationPropData[3];
  4978   TransitionPropData& animDirection = animationPropData[4];
  4979   TransitionPropData& animFillMode = animationPropData[5];
  4980   TransitionPropData& animPlayState = animationPropData[6];
  4981   TransitionPropData& animIterationCount = animationPropData[7];
  4983 #define FOR_ALL_ANIMATION_PROPS(var_) \
  4984     for (uint32_t var_ = 0; var_ < 8; ++var_)
  4986   // CSS Animations.
  4988   uint32_t numAnimations =
  4989     CountTransitionProps(animationPropInfo, animationPropData,
  4990                          ArrayLength(animationPropData),
  4991                          display, parentDisplay, aRuleData,
  4992                          canStoreInRuleTree);
  4994   display->mAnimations.SetLength(numAnimations);
  4996   FOR_ALL_ANIMATION_PROPS(p) {
  4997     const TransitionPropInfo& i = animationPropInfo[p];
  4998     TransitionPropData& d = animationPropData[p];
  5000     display->*(i.sdCount) = d.num;
  5003   // Fill in the animations we just allocated with the appropriate values.
  5004   for (uint32_t i = 0; i < numAnimations; ++i) {
  5005     nsAnimation *animation = &display->mAnimations[i];
  5007     if (i >= animDelay.num) {
  5008       animation->SetDelay(display->mAnimations[i % animDelay.num].GetDelay());
  5009     } else if (animDelay.unit == eCSSUnit_Inherit) {
  5010       // FIXME (Bug 522599) (for all animation properties): write a test that
  5011       // detects when this was wrong for i >= animDelay.num if parent had
  5012       // count for this property not equal to length
  5013       NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDelayCount,
  5014                         "animDelay.num computed incorrectly");
  5015       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  5016                         "should have made canStoreInRuleTree false above");
  5017       animation->SetDelay(parentDisplay->mAnimations[i].GetDelay());
  5018     } else if (animDelay.unit == eCSSUnit_Initial ||
  5019                animDelay.unit == eCSSUnit_Unset) {
  5020       animation->SetDelay(0.0);
  5021     } else if (animDelay.list) {
  5022       switch (animDelay.list->mValue.GetUnit()) {
  5023         case eCSSUnit_Seconds:
  5024           animation->SetDelay(PR_MSEC_PER_SEC *
  5025                               animDelay.list->mValue.GetFloatValue());
  5026           break;
  5027         case eCSSUnit_Milliseconds:
  5028           animation->SetDelay(animDelay.list->mValue.GetFloatValue());
  5029           break;
  5030         default:
  5031           NS_NOTREACHED("Invalid delay unit");
  5035     if (i >= animDuration.num) {
  5036       animation->SetDuration(
  5037         display->mAnimations[i % animDuration.num].GetDuration());
  5038     } else if (animDuration.unit == eCSSUnit_Inherit) {
  5039       NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDurationCount,
  5040                         "animDuration.num computed incorrectly");
  5041       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  5042                         "should have made canStoreInRuleTree false above");
  5043       animation->SetDuration(parentDisplay->mAnimations[i].GetDuration());
  5044     } else if (animDuration.unit == eCSSUnit_Initial ||
  5045                animDuration.unit == eCSSUnit_Unset) {
  5046       animation->SetDuration(0.0);
  5047     } else if (animDuration.list) {
  5048       switch (animDuration.list->mValue.GetUnit()) {
  5049         case eCSSUnit_Seconds:
  5050           animation->SetDuration(PR_MSEC_PER_SEC *
  5051                                  animDuration.list->mValue.GetFloatValue());
  5052           break;
  5053         case eCSSUnit_Milliseconds:
  5054           animation->SetDuration(animDuration.list->mValue.GetFloatValue());
  5055           break;
  5056         default:
  5057           NS_NOTREACHED("Invalid duration unit");
  5061     if (i >= animName.num) {
  5062       animation->SetName(display->mAnimations[i % animName.num].GetName());
  5063     } else if (animName.unit == eCSSUnit_Inherit) {
  5064       NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationNameCount,
  5065                         "animName.num computed incorrectly");
  5066       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  5067                         "should have made canStoreInRuleTree false above");
  5068       animation->SetName(parentDisplay->mAnimations[i].GetName());
  5069     } else if (animName.unit == eCSSUnit_Initial ||
  5070                animName.unit == eCSSUnit_Unset) {
  5071       animation->SetName(EmptyString());
  5072     } else if (animName.list) {
  5073       switch (animName.list->mValue.GetUnit()) {
  5074         case eCSSUnit_Ident: {
  5075           nsDependentString
  5076             nameStr(animName.list->mValue.GetStringBufferValue());
  5077           animation->SetName(nameStr);
  5078           break;
  5080         case eCSSUnit_None: {
  5081           animation->SetName(EmptyString());
  5082           break;
  5084         default:
  5085           NS_ABORT_IF_FALSE(false,
  5086             nsPrintfCString("Invalid animation-name unit %d",
  5087                                 animName.list->mValue.GetUnit()).get());
  5091     if (i >= animTimingFunction.num) {
  5092       animation->SetTimingFunction(
  5093         display->mAnimations[i % animTimingFunction.num].GetTimingFunction());
  5094     } else if (animTimingFunction.unit == eCSSUnit_Inherit) {
  5095       NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationTimingFunctionCount,
  5096                         "animTimingFunction.num computed incorrectly");
  5097       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  5098                         "should have made canStoreInRuleTree false above");
  5099       animation->SetTimingFunction(
  5100         parentDisplay->mAnimations[i].GetTimingFunction());
  5101     } else if (animTimingFunction.unit == eCSSUnit_Initial ||
  5102                animTimingFunction.unit == eCSSUnit_Unset) {
  5103       animation->SetTimingFunction(
  5104         nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
  5105     } else if (animTimingFunction.list) {
  5106       ComputeTimingFunction(animTimingFunction.list->mValue,
  5107                             animation->TimingFunctionSlot());
  5110     if (i >= animDirection.num) {
  5111       animation->SetDirection(display->mAnimations[i % animDirection.num].GetDirection());
  5112     } else if (animDirection.unit == eCSSUnit_Inherit) {
  5113       NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDirectionCount,
  5114                         "animDirection.num computed incorrectly");
  5115       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  5116                         "should have made canStoreInRuleTree false above");
  5117       animation->SetDirection(parentDisplay->mAnimations[i].GetDirection());
  5118     } else if (animDirection.unit == eCSSUnit_Initial ||
  5119                animDirection.unit == eCSSUnit_Unset) {
  5120       animation->SetDirection(NS_STYLE_ANIMATION_DIRECTION_NORMAL);
  5121     } else if (animDirection.list) {
  5122       NS_ABORT_IF_FALSE(animDirection.list->mValue.GetUnit() == eCSSUnit_Enumerated,
  5123                         nsPrintfCString("Invalid animation-direction unit %d",
  5124                                         animDirection.list->mValue.GetUnit()).get());
  5126       animation->SetDirection(animDirection.list->mValue.GetIntValue());
  5129     if (i >= animFillMode.num) {
  5130       animation->SetFillMode(display->mAnimations[i % animFillMode.num].GetFillMode());
  5131     } else if (animFillMode.unit == eCSSUnit_Inherit) {
  5132       NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationFillModeCount,
  5133                         "animFillMode.num computed incorrectly");
  5134       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  5135                         "should have made canStoreInRuleTree false above");
  5136       animation->SetFillMode(parentDisplay->mAnimations[i].GetFillMode());
  5137     } else if (animFillMode.unit == eCSSUnit_Initial ||
  5138                animFillMode.unit == eCSSUnit_Unset) {
  5139       animation->SetFillMode(NS_STYLE_ANIMATION_FILL_MODE_NONE);
  5140     } else if (animFillMode.list) {
  5141       NS_ABORT_IF_FALSE(animFillMode.list->mValue.GetUnit() == eCSSUnit_Enumerated,
  5142                         nsPrintfCString("Invalid animation-fill-mode unit %d",
  5143                                         animFillMode.list->mValue.GetUnit()).get());
  5145       animation->SetFillMode(animFillMode.list->mValue.GetIntValue());
  5148     if (i >= animPlayState.num) {
  5149       animation->SetPlayState(display->mAnimations[i % animPlayState.num].GetPlayState());
  5150     } else if (animPlayState.unit == eCSSUnit_Inherit) {
  5151       NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationPlayStateCount,
  5152                         "animPlayState.num computed incorrectly");
  5153       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  5154                         "should have made canStoreInRuleTree false above");
  5155       animation->SetPlayState(parentDisplay->mAnimations[i].GetPlayState());
  5156     } else if (animPlayState.unit == eCSSUnit_Initial ||
  5157                animPlayState.unit == eCSSUnit_Unset) {
  5158       animation->SetPlayState(NS_STYLE_ANIMATION_PLAY_STATE_RUNNING);
  5159     } else if (animPlayState.list) {
  5160       NS_ABORT_IF_FALSE(animPlayState.list->mValue.GetUnit() == eCSSUnit_Enumerated,
  5161                         nsPrintfCString("Invalid animation-play-state unit %d",
  5162                                         animPlayState.list->mValue.GetUnit()).get());
  5164       animation->SetPlayState(animPlayState.list->mValue.GetIntValue());
  5167     if (i >= animIterationCount.num) {
  5168       animation->SetIterationCount(display->mAnimations[i % animIterationCount.num].GetIterationCount());
  5169     } else if (animIterationCount.unit == eCSSUnit_Inherit) {
  5170       NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationIterationCountCount,
  5171                         "animIterationCount.num computed incorrectly");
  5172       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  5173                         "should have made canStoreInRuleTree false above");
  5174       animation->SetIterationCount(parentDisplay->mAnimations[i].GetIterationCount());
  5175     } else if (animIterationCount.unit == eCSSUnit_Initial ||
  5176                animIterationCount.unit == eCSSUnit_Unset) {
  5177       animation->SetIterationCount(1.0f);
  5178     } else if (animIterationCount.list) {
  5179       switch (animIterationCount.list->mValue.GetUnit()) {
  5180         case eCSSUnit_Enumerated:
  5181           NS_ABORT_IF_FALSE(animIterationCount.list->mValue.GetIntValue() ==
  5182                               NS_STYLE_ANIMATION_ITERATION_COUNT_INFINITE,
  5183                             "unexpected value");
  5184           animation->SetIterationCount(NS_IEEEPositiveInfinity());
  5185           break;
  5186         case eCSSUnit_Number:
  5187           animation->SetIterationCount(
  5188             animIterationCount.list->mValue.GetFloatValue());
  5189           break;
  5190         default:
  5191           NS_ABORT_IF_FALSE(false,
  5192                             "unexpected animation-iteration-count unit");
  5196     FOR_ALL_ANIMATION_PROPS(p) {
  5197       const TransitionPropInfo& info = animationPropInfo[p];
  5198       TransitionPropData& d = animationPropData[p];
  5200       // if we're at the end of the list, start at the beginning and repeat
  5201       // until we're out of animations to populate
  5202       if (d.list) {
  5203         d.list = d.list->mNext ? d.list->mNext :
  5204           aRuleData->ValueFor(info.property)->GetListValue();
  5209   // opacity: factor, inherit, initial
  5210   SetFactor(*aRuleData->ValueForOpacity(), display->mOpacity, canStoreInRuleTree,
  5211             parentDisplay->mOpacity, 1.0f,
  5212             SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
  5214   // display: enum, inherit, initial
  5215   SetDiscrete(*aRuleData->ValueForDisplay(), display->mDisplay, canStoreInRuleTree,
  5216               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5217               parentDisplay->mDisplay,
  5218               NS_STYLE_DISPLAY_INLINE, 0, 0, 0, 0);
  5220   // mix-blend-mode: enum, inherit, initial
  5221   SetDiscrete(*aRuleData->ValueForMixBlendMode(), display->mMixBlendMode,
  5222               canStoreInRuleTree,
  5223               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5224               parentDisplay->mMixBlendMode, NS_STYLE_BLEND_NORMAL,
  5225               0, 0, 0, 0);
  5227   // Backup original display value for calculation of a hypothetical
  5228   // box (CSS2 10.6.4/10.6.5), in addition to getting our style data right later.
  5229   // See nsHTMLReflowState::CalculateHypotheticalBox
  5230   display->mOriginalDisplay = display->mDisplay;
  5232   // appearance: enum, inherit, initial
  5233   SetDiscrete(*aRuleData->ValueForAppearance(),
  5234               display->mAppearance, canStoreInRuleTree,
  5235               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5236               parentDisplay->mAppearance,
  5237               NS_THEME_NONE, 0, 0, 0, 0);
  5239   // binding: url, none, inherit
  5240   const nsCSSValue* bindingValue = aRuleData->ValueForBinding();
  5241   if (eCSSUnit_URL == bindingValue->GetUnit()) {
  5242     mozilla::css::URLValue* url = bindingValue->GetURLStructValue();
  5243     NS_ASSERTION(url, "What's going on here?");
  5245     if (MOZ_LIKELY(url->GetURI())) {
  5246       display->mBinding = url;
  5247     } else {
  5248       display->mBinding = nullptr;
  5251   else if (eCSSUnit_None == bindingValue->GetUnit() ||
  5252            eCSSUnit_Initial == bindingValue->GetUnit() ||
  5253            eCSSUnit_Unset == bindingValue->GetUnit()) {
  5254     display->mBinding = nullptr;
  5256   else if (eCSSUnit_Inherit == bindingValue->GetUnit()) {
  5257     canStoreInRuleTree = false;
  5258     display->mBinding = parentDisplay->mBinding;
  5261   // position: enum, inherit, initial
  5262   SetDiscrete(*aRuleData->ValueForPosition(), display->mPosition, canStoreInRuleTree,
  5263               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5264               parentDisplay->mPosition,
  5265               NS_STYLE_POSITION_STATIC, 0, 0, 0, 0);
  5267   // clear: enum, inherit, initial
  5268   SetDiscrete(*aRuleData->ValueForClear(), display->mBreakType, canStoreInRuleTree,
  5269               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5270               parentDisplay->mBreakType,
  5271               NS_STYLE_CLEAR_NONE, 0, 0, 0, 0);
  5273   // temp fix for bug 24000
  5274   // Map 'auto' and 'avoid' to false, and 'always', 'left', and
  5275   // 'right' to true.
  5276   // "A conforming user agent may interpret the values 'left' and
  5277   // 'right' as 'always'." - CSS2.1, section 13.3.1
  5278   const nsCSSValue* breakBeforeValue = aRuleData->ValueForPageBreakBefore();
  5279   if (eCSSUnit_Enumerated == breakBeforeValue->GetUnit()) {
  5280     display->mBreakBefore =
  5281       (NS_STYLE_PAGE_BREAK_AVOID != breakBeforeValue->GetIntValue() &&
  5282        NS_STYLE_PAGE_BREAK_AUTO  != breakBeforeValue->GetIntValue());
  5284   else if (eCSSUnit_Initial == breakBeforeValue->GetUnit() ||
  5285            eCSSUnit_Unset == breakBeforeValue->GetUnit()) {
  5286     display->mBreakBefore = false;
  5288   else if (eCSSUnit_Inherit == breakBeforeValue->GetUnit()) {
  5289     canStoreInRuleTree = false;
  5290     display->mBreakBefore = parentDisplay->mBreakBefore;
  5293   const nsCSSValue* breakAfterValue = aRuleData->ValueForPageBreakAfter();
  5294   if (eCSSUnit_Enumerated == breakAfterValue->GetUnit()) {
  5295     display->mBreakAfter =
  5296       (NS_STYLE_PAGE_BREAK_AVOID != breakAfterValue->GetIntValue() &&
  5297        NS_STYLE_PAGE_BREAK_AUTO  != breakAfterValue->GetIntValue());
  5299   else if (eCSSUnit_Initial == breakAfterValue->GetUnit() ||
  5300            eCSSUnit_Unset == breakAfterValue->GetUnit()) {
  5301     display->mBreakAfter = false;
  5303   else if (eCSSUnit_Inherit == breakAfterValue->GetUnit()) {
  5304     canStoreInRuleTree = false;
  5305     display->mBreakAfter = parentDisplay->mBreakAfter;
  5307   // end temp fix
  5309   // page-break-inside: enum, inherit, initial
  5310   SetDiscrete(*aRuleData->ValueForPageBreakInside(),
  5311               display->mBreakInside, canStoreInRuleTree,
  5312               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5313               parentDisplay->mBreakInside,
  5314               NS_STYLE_PAGE_BREAK_AUTO, 0, 0, 0, 0);
  5316   // touch-action: none, auto, enum, inherit, initial
  5317   SetDiscrete(*aRuleData->ValueForTouchAction(), display->mTouchAction,
  5318               canStoreInRuleTree,
  5319               SETDSC_ENUMERATED | SETDSC_AUTO | SETDSC_NONE |
  5320                 SETDSC_UNSET_INITIAL,
  5321               parentDisplay->mTouchAction,
  5322               NS_STYLE_TOUCH_ACTION_AUTO,
  5323               NS_STYLE_TOUCH_ACTION_AUTO,
  5324               NS_STYLE_TOUCH_ACTION_NONE, 0, 0);
  5326   // float: enum, inherit, initial
  5327   SetDiscrete(*aRuleData->ValueForFloat(),
  5328               display->mFloats, canStoreInRuleTree,
  5329               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5330               parentDisplay->mFloats,
  5331               NS_STYLE_FLOAT_NONE, 0, 0, 0, 0);
  5332   // Save mFloats in mOriginalFloats in case we need it later
  5333   display->mOriginalFloats = display->mFloats;
  5335   // overflow-x: enum, inherit, initial
  5336   SetDiscrete(*aRuleData->ValueForOverflowX(),
  5337               display->mOverflowX, canStoreInRuleTree,
  5338               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5339               parentDisplay->mOverflowX,
  5340               NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
  5342   // overflow-y: enum, inherit, initial
  5343   SetDiscrete(*aRuleData->ValueForOverflowY(),
  5344               display->mOverflowY, canStoreInRuleTree,
  5345               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5346               parentDisplay->mOverflowY,
  5347               NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
  5349   // CSS3 overflow-x and overflow-y require some fixup as well in some
  5350   // cases.  NS_STYLE_OVERFLOW_VISIBLE and NS_STYLE_OVERFLOW_CLIP are
  5351   // meaningful only when used in both dimensions.
  5352   if (display->mOverflowX != display->mOverflowY &&
  5353       (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE ||
  5354        display->mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
  5355        display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE ||
  5356        display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)) {
  5357     // We can't store in the rule tree since a more specific rule might
  5358     // change these conditions.
  5359     canStoreInRuleTree = false;
  5361     // NS_STYLE_OVERFLOW_CLIP is a deprecated value, so if it's specified
  5362     // in only one dimension, convert it to NS_STYLE_OVERFLOW_HIDDEN.
  5363     if (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
  5364       display->mOverflowX = NS_STYLE_OVERFLOW_HIDDEN;
  5365     if (display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)
  5366       display->mOverflowY = NS_STYLE_OVERFLOW_HIDDEN;
  5368     // If 'visible' is specified but doesn't match the other dimension, it
  5369     // turns into 'auto'.
  5370     if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
  5371       display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
  5372     if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
  5373       display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
  5376   SetDiscrete(*aRuleData->ValueForOverflowClipBox(), display->mOverflowClipBox,
  5377               canStoreInRuleTree,
  5378               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5379               parentDisplay->mOverflowClipBox,
  5380               NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX, 0, 0, 0, 0);
  5382   SetDiscrete(*aRuleData->ValueForResize(), display->mResize, canStoreInRuleTree,
  5383               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5384               parentDisplay->mResize,
  5385               NS_STYLE_RESIZE_NONE, 0, 0, 0, 0);
  5387   // clip property: length, auto, inherit
  5388   const nsCSSValue* clipValue = aRuleData->ValueForClip();
  5389   switch (clipValue->GetUnit()) {
  5390   case eCSSUnit_Inherit:
  5391     canStoreInRuleTree = false;
  5392     display->mClipFlags = parentDisplay->mClipFlags;
  5393     display->mClip = parentDisplay->mClip;
  5394     break;
  5396   case eCSSUnit_Initial:
  5397   case eCSSUnit_Unset:
  5398   case eCSSUnit_Auto:
  5399     display->mClipFlags = NS_STYLE_CLIP_AUTO;
  5400     display->mClip.SetRect(0,0,0,0);
  5401     break;
  5403   case eCSSUnit_Null:
  5404     break;
  5406   case eCSSUnit_Rect: {
  5407     const nsCSSRect& clipRect = clipValue->GetRectValue();
  5409     display->mClipFlags = NS_STYLE_CLIP_RECT;
  5411     if (clipRect.mTop.GetUnit() == eCSSUnit_Auto) {
  5412       display->mClip.y = 0;
  5413       display->mClipFlags |= NS_STYLE_CLIP_TOP_AUTO;
  5415     else if (clipRect.mTop.IsLengthUnit()) {
  5416       display->mClip.y = CalcLength(clipRect.mTop, aContext,
  5417                                     mPresContext, canStoreInRuleTree);
  5420     if (clipRect.mBottom.GetUnit() == eCSSUnit_Auto) {
  5421       // Setting to NS_MAXSIZE for the 'auto' case ensures that
  5422       // the clip rect is nonempty. It is important that mClip be
  5423       // nonempty if the actual clip rect could be nonempty.
  5424       display->mClip.height = NS_MAXSIZE;
  5425       display->mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO;
  5427     else if (clipRect.mBottom.IsLengthUnit()) {
  5428       display->mClip.height = CalcLength(clipRect.mBottom, aContext,
  5429                                          mPresContext, canStoreInRuleTree) -
  5430                               display->mClip.y;
  5433     if (clipRect.mLeft.GetUnit() == eCSSUnit_Auto) {
  5434       display->mClip.x = 0;
  5435       display->mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO;
  5437     else if (clipRect.mLeft.IsLengthUnit()) {
  5438       display->mClip.x = CalcLength(clipRect.mLeft, aContext,
  5439                                     mPresContext, canStoreInRuleTree);
  5442     if (clipRect.mRight.GetUnit() == eCSSUnit_Auto) {
  5443       // Setting to NS_MAXSIZE for the 'auto' case ensures that
  5444       // the clip rect is nonempty. It is important that mClip be
  5445       // nonempty if the actual clip rect could be nonempty.
  5446       display->mClip.width = NS_MAXSIZE;
  5447       display->mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO;
  5449     else if (clipRect.mRight.IsLengthUnit()) {
  5450       display->mClip.width = CalcLength(clipRect.mRight, aContext,
  5451                                         mPresContext, canStoreInRuleTree) -
  5452                              display->mClip.x;
  5454     break;
  5457   default:
  5458     NS_ABORT_IF_FALSE(false, "unrecognized clip unit");
  5461   if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
  5462     // CSS2 9.7 specifies display type corrections dealing with 'float'
  5463     // and 'position'.  Since generated content can't be floated or
  5464     // positioned, we can deal with it here.
  5466     if (nsCSSPseudoElements::firstLetter == aContext->GetPseudo()) {
  5467       // a non-floating first-letter must be inline
  5468       // XXX this fix can go away once bug 103189 is fixed correctly
  5469       // Note that we reset mOriginalDisplay to enforce the invariant that it equals mDisplay if we're not positioned or floating.
  5470       display->mOriginalDisplay = display->mDisplay = NS_STYLE_DISPLAY_INLINE;
  5472       // We can't cache the data in the rule tree since if a more specific
  5473       // rule has 'float: left' we'll end up with the wrong 'display'
  5474       // property.
  5475       canStoreInRuleTree = false;
  5478     if (display->IsAbsolutelyPositionedStyle()) {
  5479       // 1) if position is 'absolute' or 'fixed' then display must be
  5480       // block-level and float must be 'none'
  5481       EnsureBlockDisplay(display->mDisplay);
  5482       display->mFloats = NS_STYLE_FLOAT_NONE;
  5484       // Note that it's OK to cache this struct in the ruletree
  5485       // because it's fine as-is for any style context that points to
  5486       // it directly, and any use of it as aStartStruct (e.g. if a
  5487       // more specific rule sets "position: static") will use
  5488       // mOriginalDisplay and mOriginalFloats, which we have carefully
  5489       // not changed.
  5490     } else if (display->mFloats != NS_STYLE_FLOAT_NONE) {
  5491       // 2) if float is not none, and display is not none, then we must
  5492       // set a block-level 'display' type per CSS2.1 section 9.7.
  5493       EnsureBlockDisplay(display->mDisplay);
  5495       // Note that it's OK to cache this struct in the ruletree
  5496       // because it's fine as-is for any style context that points to
  5497       // it directly, and any use of it as aStartStruct (e.g. if a
  5498       // more specific rule sets "float: none") will use
  5499       // mOriginalDisplay, which we have carefully not changed.
  5504   /* Convert the nsCSSValueList into an nsTArray<nsTransformFunction *>. */
  5505   const nsCSSValue* transformValue = aRuleData->ValueForTransform();
  5506   switch (transformValue->GetUnit()) {
  5507   case eCSSUnit_Null:
  5508     break;
  5510   case eCSSUnit_Initial:
  5511   case eCSSUnit_Unset:
  5512   case eCSSUnit_None:
  5513     display->mSpecifiedTransform = nullptr;
  5514     break;
  5516   case eCSSUnit_Inherit:
  5517     display->mSpecifiedTransform = parentDisplay->mSpecifiedTransform;
  5518     canStoreInRuleTree = false;
  5519     break;
  5521   case eCSSUnit_SharedList: {
  5522     nsCSSValueSharedList* list = transformValue->GetSharedListValue();
  5523     nsCSSValueList* head = list->mHead;
  5524     MOZ_ASSERT(head, "transform list must have at least one item");
  5525     // can get a _None in here from transform animation
  5526     if (head->mValue.GetUnit() == eCSSUnit_None) {
  5527       NS_ABORT_IF_FALSE(head->mNext == nullptr, "none must be alone");
  5528       display->mSpecifiedTransform = nullptr;
  5529     } else {
  5530       display->mSpecifiedTransform = list;
  5532     break;
  5535   default:
  5536     NS_ABORT_IF_FALSE(false, "unrecognized transform unit");
  5539   /* Convert the nsCSSValueList into a will-change bitfield for fast lookup */
  5540   const nsCSSValue* willChangeValue = aRuleData->ValueForWillChange();
  5541   switch (willChangeValue->GetUnit()) {
  5542   case eCSSUnit_Null:
  5543     break;
  5545   case eCSSUnit_List:
  5546   case eCSSUnit_ListDep: {
  5547     display->mWillChange.Clear();
  5548     display->mWillChangeBitField = 0;
  5549     for (const nsCSSValueList* item = willChangeValue->GetListValue();
  5550          item; item = item->mNext)
  5552       if (item->mValue.UnitHasStringValue()) {
  5553         nsAutoString buffer;
  5554         item->mValue.GetStringValue(buffer);
  5555         display->mWillChange.AppendElement(buffer);
  5557         if (buffer.EqualsLiteral("transform")) {
  5558           display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_TRANSFORM;
  5560         if (buffer.EqualsLiteral("opacity")) {
  5561           display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_OPACITY;
  5563         if (buffer.EqualsLiteral("scroll-position")) {
  5564           display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_SCROLL;
  5567         nsCSSProperty prop =
  5568           nsCSSProps::LookupProperty(buffer,
  5569                                      nsCSSProps::eEnabledForAllContent);
  5570         if (prop != eCSSProperty_UNKNOWN &&
  5571             nsCSSProps::PropHasFlags(prop,
  5572                                      CSS_PROPERTY_CREATES_STACKING_CONTEXT))
  5574           display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_STACKING_CONTEXT;
  5578     break;
  5581   case eCSSUnit_Inherit:
  5582     display->mWillChange = parentDisplay->mWillChange;
  5583     display->mWillChangeBitField = parentDisplay->mWillChangeBitField;
  5584     canStoreInRuleTree = false;
  5585     break;
  5587   case eCSSUnit_Initial:
  5588   case eCSSUnit_Unset:
  5589   case eCSSUnit_Auto:
  5590     display->mWillChange.Clear();
  5591     display->mWillChangeBitField = 0;
  5592     break;
  5594   default:
  5595     MOZ_ASSERT(false, "unrecognized will-change unit");
  5598   /* Convert -moz-transform-origin. */
  5599   const nsCSSValue* transformOriginValue =
  5600     aRuleData->ValueForTransformOrigin();
  5601   if (transformOriginValue->GetUnit() != eCSSUnit_Null) {
  5602     const nsCSSValue& valX =
  5603       transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
  5604         transformOriginValue->GetTripletValue().mXValue : *transformOriginValue;
  5605     const nsCSSValue& valY =
  5606       transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
  5607         transformOriginValue->GetTripletValue().mYValue : *transformOriginValue;
  5608     const nsCSSValue& valZ =
  5609       transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
  5610         transformOriginValue->GetTripletValue().mZValue : *transformOriginValue;
  5612     mozilla::DebugOnly<bool> cX =
  5613        SetCoord(valX, display->mTransformOrigin[0],
  5614                 parentDisplay->mTransformOrigin[0],
  5615                 SETCOORD_LPH | SETCOORD_INITIAL_HALF |
  5616                   SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
  5617                   SETCOORD_UNSET_INITIAL,
  5618                 aContext, mPresContext, canStoreInRuleTree);
  5620      mozilla::DebugOnly<bool> cY =
  5621        SetCoord(valY, display->mTransformOrigin[1],
  5622                 parentDisplay->mTransformOrigin[1],
  5623                 SETCOORD_LPH | SETCOORD_INITIAL_HALF |
  5624                   SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
  5625                   SETCOORD_UNSET_INITIAL,
  5626                 aContext, mPresContext, canStoreInRuleTree);
  5628      if (valZ.GetUnit() == eCSSUnit_Null) {
  5629        // Null for the z component means a 0 translation, not
  5630        // unspecified, as we have already checked the triplet
  5631        // value for Null.
  5632        display->mTransformOrigin[2].SetCoordValue(0);
  5633      } else {
  5634        mozilla::DebugOnly<bool> cZ =
  5635          SetCoord(valZ, display->mTransformOrigin[2],
  5636                   parentDisplay->mTransformOrigin[2],
  5637                   SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  5638                     SETCOORD_UNSET_INITIAL,
  5639                   aContext, mPresContext, canStoreInRuleTree);
  5640        NS_ABORT_IF_FALSE(cY == cZ, "changed one but not the other");
  5642      NS_ABORT_IF_FALSE(cX == cY, "changed one but not the other");
  5643      NS_ASSERTION(cX, "Malformed -moz-transform-origin parse!");
  5646   const nsCSSValue* perspectiveOriginValue =
  5647     aRuleData->ValueForPerspectiveOrigin();
  5648   if (perspectiveOriginValue->GetUnit() != eCSSUnit_Null) {
  5649     mozilla::DebugOnly<bool> result =
  5650       SetPairCoords(*perspectiveOriginValue,
  5651                     display->mPerspectiveOrigin[0],
  5652                     display->mPerspectiveOrigin[1],
  5653                     parentDisplay->mPerspectiveOrigin[0],
  5654                     parentDisplay->mPerspectiveOrigin[1],
  5655                     SETCOORD_LPH | SETCOORD_INITIAL_HALF |
  5656                       SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
  5657                       SETCOORD_UNSET_INITIAL,
  5658                     aContext, mPresContext, canStoreInRuleTree);
  5659     NS_ASSERTION(result, "Malformed -moz-perspective-origin parse!");
  5662   SetCoord(*aRuleData->ValueForPerspective(), 
  5663            display->mChildPerspective, parentDisplay->mChildPerspective,
  5664            SETCOORD_LAH | SETCOORD_INITIAL_NONE | SETCOORD_NONE |
  5665              SETCOORD_UNSET_INITIAL,
  5666            aContext, mPresContext, canStoreInRuleTree);
  5668   SetDiscrete(*aRuleData->ValueForBackfaceVisibility(),
  5669               display->mBackfaceVisibility, canStoreInRuleTree,
  5670               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5671               parentDisplay->mBackfaceVisibility,
  5672               NS_STYLE_BACKFACE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
  5674   // transform-style: enum, inherit, initial
  5675   SetDiscrete(*aRuleData->ValueForTransformStyle(),
  5676               display->mTransformStyle, canStoreInRuleTree,
  5677               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5678               parentDisplay->mTransformStyle,
  5679               NS_STYLE_TRANSFORM_STYLE_FLAT, 0, 0, 0, 0);
  5681   // orient: enum, inherit, initial
  5682   SetDiscrete(*aRuleData->ValueForOrient(),
  5683               display->mOrient, canStoreInRuleTree,
  5684               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  5685               parentDisplay->mOrient,
  5686               NS_STYLE_ORIENT_AUTO, 0, 0, 0, 0);
  5688   COMPUTE_END_RESET(Display, display)
  5691 const void*
  5692 nsRuleNode::ComputeVisibilityData(void* aStartStruct,
  5693                                   const nsRuleData* aRuleData,
  5694                                   nsStyleContext* aContext,
  5695                                   nsRuleNode* aHighestNode,
  5696                                   const RuleDetail aRuleDetail,
  5697                                   const bool aCanStoreInRuleTree)
  5699   COMPUTE_START_INHERITED(Visibility, (mPresContext),
  5700                           visibility, parentVisibility)
  5702   // IMPORTANT: No properties in this struct have lengths in them.  We
  5703   // depend on this since CalcLengthWith can call StyleVisibility()
  5704   // to get the language for resolving fonts!
  5706   // direction: enum, inherit, initial
  5707   SetDiscrete(*aRuleData->ValueForDirection(), visibility->mDirection,
  5708               canStoreInRuleTree,
  5709               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  5710               parentVisibility->mDirection,
  5711               (GET_BIDI_OPTION_DIRECTION(mPresContext->GetBidi())
  5712                == IBMBIDI_TEXTDIRECTION_RTL)
  5713               ? NS_STYLE_DIRECTION_RTL : NS_STYLE_DIRECTION_LTR,
  5714               0, 0, 0, 0);
  5716   // visibility: enum, inherit, initial
  5717   SetDiscrete(*aRuleData->ValueForVisibility(), visibility->mVisible,
  5718               canStoreInRuleTree,
  5719               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  5720               parentVisibility->mVisible,
  5721               NS_STYLE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
  5723   // pointer-events: enum, inherit, initial
  5724   SetDiscrete(*aRuleData->ValueForPointerEvents(), visibility->mPointerEvents,
  5725               canStoreInRuleTree,
  5726               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  5727               parentVisibility->mPointerEvents,
  5728               NS_STYLE_POINTER_EVENTS_AUTO, 0, 0, 0, 0);
  5730   // writing-mode: enum, inherit, initial
  5731   SetDiscrete(*aRuleData->ValueForWritingMode(), visibility->mWritingMode,
  5732               canStoreInRuleTree,
  5733               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  5734               parentVisibility->mWritingMode,
  5735               NS_STYLE_WRITING_MODE_HORIZONTAL_TB, 0, 0, 0, 0);
  5737   // image-orientation: enum, inherit, initial
  5738   const nsCSSValue* orientation = aRuleData->ValueForImageOrientation();
  5739   if (orientation->GetUnit() == eCSSUnit_Inherit ||
  5740       orientation->GetUnit() == eCSSUnit_Unset) {
  5741     canStoreInRuleTree = false;
  5742     visibility->mImageOrientation = parentVisibility->mImageOrientation;
  5743   } else if (orientation->GetUnit() == eCSSUnit_Initial) {
  5744     visibility->mImageOrientation = nsStyleImageOrientation();
  5745   } else if (orientation->IsAngularUnit()) {
  5746     double angle = orientation->GetAngleValueInRadians();
  5747     visibility->mImageOrientation =
  5748       nsStyleImageOrientation::CreateAsAngleAndFlip(angle, false);
  5749   } else if (orientation->GetUnit() == eCSSUnit_Array) {
  5750     const nsCSSValue::Array* array = orientation->GetArrayValue();
  5751     MOZ_ASSERT(array->Item(0).IsAngularUnit(),
  5752                "First image-orientation value is not an angle");
  5753     MOZ_ASSERT(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
  5754                array->Item(1).GetIntValue() == NS_STYLE_IMAGE_ORIENTATION_FLIP,
  5755                "Second image-orientation value is not 'flip'");
  5756     double angle = array->Item(0).GetAngleValueInRadians();
  5757     visibility->mImageOrientation =
  5758       nsStyleImageOrientation::CreateAsAngleAndFlip(angle, true);
  5760   } else if (orientation->GetUnit() == eCSSUnit_Enumerated) {
  5761     switch (orientation->GetIntValue()) {
  5762       case NS_STYLE_IMAGE_ORIENTATION_FLIP:
  5763         visibility->mImageOrientation = nsStyleImageOrientation::CreateAsFlip();
  5764         break;
  5765       case NS_STYLE_IMAGE_ORIENTATION_FROM_IMAGE:
  5766         visibility->mImageOrientation = nsStyleImageOrientation::CreateAsFromImage();
  5767         break;
  5768       default:
  5769         NS_NOTREACHED("Invalid image-orientation enumerated value");
  5771   } else {
  5772     MOZ_ASSERT(orientation->GetUnit() == eCSSUnit_Null, "Should be null unit");
  5775   COMPUTE_END_INHERITED(Visibility, visibility)
  5778 const void*
  5779 nsRuleNode::ComputeColorData(void* aStartStruct,
  5780                              const nsRuleData* aRuleData,
  5781                              nsStyleContext* aContext,
  5782                              nsRuleNode* aHighestNode,
  5783                              const RuleDetail aRuleDetail,
  5784                              const bool aCanStoreInRuleTree)
  5786   COMPUTE_START_INHERITED(Color, (mPresContext), color, parentColor)
  5788   // color: color, string, inherit
  5789   // Special case for currentColor.  According to CSS3, setting color to 'currentColor'
  5790   // should behave as if it is inherited
  5791   const nsCSSValue* colorValue = aRuleData->ValueForColor();
  5792   if ((colorValue->GetUnit() == eCSSUnit_EnumColor &&
  5793        colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) ||
  5794       colorValue->GetUnit() == eCSSUnit_Unset) {
  5795     color->mColor = parentColor->mColor;
  5796     canStoreInRuleTree = false;
  5798   else if (colorValue->GetUnit() == eCSSUnit_Initial) {
  5799     color->mColor = mPresContext->DefaultColor();
  5801   else {
  5802     SetColor(*colorValue, parentColor->mColor, mPresContext, aContext,
  5803              color->mColor, canStoreInRuleTree);
  5806   COMPUTE_END_INHERITED(Color, color)
  5809 // information about how to compute values for background-* properties
  5810 template <class SpecifiedValueItem, class ComputedValueItem>
  5811 struct BackgroundItemComputer {
  5812 };
  5814 template <>
  5815 struct BackgroundItemComputer<nsCSSValueList, uint8_t>
  5817   static void ComputeValue(nsStyleContext* aStyleContext,
  5818                            const nsCSSValueList* aSpecifiedValue,
  5819                            uint8_t& aComputedValue,
  5820                            bool& aCanStoreInRuleTree)
  5822     SetDiscrete(aSpecifiedValue->mValue, aComputedValue, aCanStoreInRuleTree,
  5823                 SETDSC_ENUMERATED, uint8_t(0), 0, 0, 0, 0, 0);
  5825 };
  5827 template <>
  5828 struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Repeat>
  5830   static void ComputeValue(nsStyleContext* aStyleContext,
  5831                            const nsCSSValuePairList* aSpecifiedValue,
  5832                            nsStyleBackground::Repeat& aComputedValue,
  5833                            bool& aCanStoreInRuleTree)
  5835     NS_ASSERTION(aSpecifiedValue->mXValue.GetUnit() == eCSSUnit_Enumerated &&
  5836                  (aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Enumerated ||
  5837                   aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null),
  5838                  "Invalid unit");
  5840     bool hasContraction = true;
  5841     uint8_t value = aSpecifiedValue->mXValue.GetIntValue();
  5842     switch (value) {
  5843     case NS_STYLE_BG_REPEAT_REPEAT_X:
  5844       aComputedValue.mXRepeat = NS_STYLE_BG_REPEAT_REPEAT;
  5845       aComputedValue.mYRepeat = NS_STYLE_BG_REPEAT_NO_REPEAT;
  5846       break;
  5847     case NS_STYLE_BG_REPEAT_REPEAT_Y:
  5848       aComputedValue.mXRepeat = NS_STYLE_BG_REPEAT_NO_REPEAT;
  5849       aComputedValue.mYRepeat = NS_STYLE_BG_REPEAT_REPEAT;
  5850       break;
  5851     default:
  5852       aComputedValue.mXRepeat = value;
  5853       hasContraction = false;
  5854       break;
  5857     if (hasContraction) {
  5858       NS_ASSERTION(aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null,
  5859                    "Invalid unit.");
  5860       return;
  5863     switch (aSpecifiedValue->mYValue.GetUnit()) {
  5864     case eCSSUnit_Null:
  5865       aComputedValue.mYRepeat = aComputedValue.mXRepeat;
  5866       break;
  5867     case eCSSUnit_Enumerated:
  5868       value = aSpecifiedValue->mYValue.GetIntValue();
  5869       NS_ASSERTION(value == NS_STYLE_BG_REPEAT_NO_REPEAT ||
  5870                    value == NS_STYLE_BG_REPEAT_REPEAT, "Unexpected value");
  5871       aComputedValue.mYRepeat = value;
  5872       break;
  5873     default:
  5874       NS_NOTREACHED("Unexpected CSS value");
  5875       break;
  5878 };
  5880 template <>
  5881 struct BackgroundItemComputer<nsCSSValueList, nsStyleImage>
  5883   static void ComputeValue(nsStyleContext* aStyleContext,
  5884                            const nsCSSValueList* aSpecifiedValue,
  5885                            nsStyleImage& aComputedValue,
  5886                            bool& aCanStoreInRuleTree)
  5888     SetStyleImage(aStyleContext, aSpecifiedValue->mValue, aComputedValue,
  5889                   aCanStoreInRuleTree);
  5891 };
  5893 /* Helper function for
  5894  * BackgroundItemComputer<nsCSSValue, nsStyleBackground::Position>
  5895  * It computes a single PositionCoord from an nsCSSValue object
  5896  * (contained in a list).
  5897  */
  5898 typedef nsStyleBackground::Position::PositionCoord PositionCoord;
  5899 static void
  5900 ComputeBackgroundPositionCoord(nsStyleContext* aStyleContext,
  5901                                const nsCSSValue& aEdge,
  5902                                const nsCSSValue& aOffset,
  5903                                PositionCoord* aResult,
  5904                                bool& aCanStoreInRuleTree)
  5906   if (eCSSUnit_Percent == aOffset.GetUnit()) {
  5907     aResult->mLength = 0;
  5908     aResult->mPercent = aOffset.GetPercentValue();
  5909     aResult->mHasPercent = true;
  5910   } else if (aOffset.IsLengthUnit()) {
  5911     aResult->mLength = CalcLength(aOffset, aStyleContext,
  5912                                   aStyleContext->PresContext(),
  5913                                   aCanStoreInRuleTree);
  5914     aResult->mPercent = 0.0f;
  5915     aResult->mHasPercent = false;
  5916   } else if (aOffset.IsCalcUnit()) {
  5917     LengthPercentPairCalcOps ops(aStyleContext,
  5918                                  aStyleContext->PresContext(),
  5919                                  aCanStoreInRuleTree);
  5920     nsRuleNode::ComputedCalc vals = ComputeCalc(aOffset, ops);
  5921     aResult->mLength = vals.mLength;
  5922     aResult->mPercent = vals.mPercent;
  5923     aResult->mHasPercent = ops.mHasPercent;
  5924   } else {
  5925     aResult->mLength = 0;
  5926     aResult->mPercent = 0.0f;
  5927     aResult->mHasPercent = false;
  5928     NS_ASSERTION(aOffset.GetUnit() == eCSSUnit_Null, "unexpected unit");
  5931   if (eCSSUnit_Enumerated == aEdge.GetUnit()) {
  5932     int sign;
  5933     if (aEdge.GetIntValue() & (NS_STYLE_BG_POSITION_BOTTOM |
  5934                                NS_STYLE_BG_POSITION_RIGHT)) {
  5935       sign = -1;
  5936     } else {
  5937       sign = 1;
  5939     aResult->mPercent = GetFloatFromBoxPosition(aEdge.GetIntValue()) +
  5940                         sign * aResult->mPercent;
  5941     aResult->mLength = sign * aResult->mLength;
  5942     aResult->mHasPercent = true;
  5943   } else {
  5944     NS_ASSERTION(eCSSUnit_Null == aEdge.GetUnit(), "unexpected unit");
  5948 template <>
  5949 struct BackgroundItemComputer<nsCSSValueList, nsStyleBackground::Position>
  5951   static void ComputeValue(nsStyleContext* aStyleContext,
  5952                            const nsCSSValueList* aSpecifiedValue,
  5953                            nsStyleBackground::Position& aComputedValue,
  5954                            bool& aCanStoreInRuleTree)
  5956     NS_ASSERTION(aSpecifiedValue->mValue.GetUnit() == eCSSUnit_Array, "bg-position not an array");
  5958     nsRefPtr<nsCSSValue::Array> bgPositionArray =
  5959                                   aSpecifiedValue->mValue.GetArrayValue();
  5960     const nsCSSValue &xEdge   = bgPositionArray->Item(0);
  5961     const nsCSSValue &xOffset = bgPositionArray->Item(1);
  5962     const nsCSSValue &yEdge   = bgPositionArray->Item(2);
  5963     const nsCSSValue &yOffset = bgPositionArray->Item(3);
  5965     NS_ASSERTION((eCSSUnit_Enumerated == xEdge.GetUnit()  ||
  5966                   eCSSUnit_Null       == xEdge.GetUnit()) &&
  5967                  (eCSSUnit_Enumerated == yEdge.GetUnit()  ||
  5968                   eCSSUnit_Null       == yEdge.GetUnit()) &&
  5969                   eCSSUnit_Enumerated != xOffset.GetUnit()  &&
  5970                   eCSSUnit_Enumerated != yOffset.GetUnit(),
  5971                   "Invalid background position");
  5973     ComputeBackgroundPositionCoord(aStyleContext, xEdge, xOffset,
  5974                                    &aComputedValue.mXPosition,
  5975                                    aCanStoreInRuleTree);
  5977     ComputeBackgroundPositionCoord(aStyleContext, yEdge, yOffset,
  5978                                    &aComputedValue.mYPosition,
  5979                                    aCanStoreInRuleTree);
  5981 };
  5984 struct BackgroundSizeAxis {
  5985   nsCSSValue nsCSSValuePairList::* specified;
  5986   nsStyleBackground::Size::Dimension nsStyleBackground::Size::* result;
  5987   uint8_t nsStyleBackground::Size::* type;
  5988 };
  5990 static const BackgroundSizeAxis gBGSizeAxes[] = {
  5991   { &nsCSSValuePairList::mXValue,
  5992     &nsStyleBackground::Size::mWidth,
  5993     &nsStyleBackground::Size::mWidthType },
  5994   { &nsCSSValuePairList::mYValue,
  5995     &nsStyleBackground::Size::mHeight,
  5996     &nsStyleBackground::Size::mHeightType }
  5997 };
  5999 template <>
  6000 struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Size>
  6002   static void ComputeValue(nsStyleContext* aStyleContext,
  6003                            const nsCSSValuePairList* aSpecifiedValue,
  6004                            nsStyleBackground::Size& aComputedValue,
  6005                            bool& aCanStoreInRuleTree)
  6007     nsStyleBackground::Size &size = aComputedValue;
  6008     for (const BackgroundSizeAxis *axis = gBGSizeAxes,
  6009                         *axis_end = ArrayEnd(gBGSizeAxes);
  6010          axis < axis_end; ++axis) {
  6011       const nsCSSValue &specified = aSpecifiedValue->*(axis->specified);
  6012       if (eCSSUnit_Auto == specified.GetUnit()) {
  6013         size.*(axis->type) = nsStyleBackground::Size::eAuto;
  6015       else if (eCSSUnit_Enumerated == specified.GetUnit()) {
  6016         static_assert(nsStyleBackground::Size::eContain ==
  6017                       NS_STYLE_BG_SIZE_CONTAIN &&
  6018                       nsStyleBackground::Size::eCover ==
  6019                       NS_STYLE_BG_SIZE_COVER,
  6020                       "background size constants out of sync");
  6021         NS_ABORT_IF_FALSE(specified.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
  6022                           specified.GetIntValue() == NS_STYLE_BG_SIZE_COVER,
  6023                           "invalid enumerated value for size coordinate");
  6024         size.*(axis->type) = specified.GetIntValue();
  6026       else if (eCSSUnit_Null == specified.GetUnit()) {
  6027         NS_ABORT_IF_FALSE(axis == gBGSizeAxes + 1,
  6028                           "null allowed only as height value, and only "
  6029                           "for contain/cover/initial/inherit");
  6030 #ifdef DEBUG
  6032           const nsCSSValue &widthValue = aSpecifiedValue->mXValue;
  6033           NS_ABORT_IF_FALSE(widthValue.GetUnit() != eCSSUnit_Inherit &&
  6034                             widthValue.GetUnit() != eCSSUnit_Initial &&
  6035                             widthValue.GetUnit() != eCSSUnit_Unset,
  6036                             "initial/inherit/unset should already have been handled");
  6037           NS_ABORT_IF_FALSE(widthValue.GetUnit() == eCSSUnit_Enumerated &&
  6038                             (widthValue.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
  6039                              widthValue.GetIntValue() == NS_STYLE_BG_SIZE_COVER),
  6040                             "null height value not corresponding to allowable "
  6041                             "non-null width value");
  6043 #endif
  6044         size.*(axis->type) = size.mWidthType;
  6046       else if (eCSSUnit_Percent == specified.GetUnit()) {
  6047         (size.*(axis->result)).mLength = 0;
  6048         (size.*(axis->result)).mPercent = specified.GetPercentValue();
  6049         (size.*(axis->result)).mHasPercent = true;
  6050         size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
  6052       else if (specified.IsLengthUnit()) {
  6053         (size.*(axis->result)).mLength =
  6054           CalcLength(specified, aStyleContext, aStyleContext->PresContext(),
  6055                      aCanStoreInRuleTree);
  6056         (size.*(axis->result)).mPercent = 0.0f;
  6057         (size.*(axis->result)).mHasPercent = false;
  6058         size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
  6059       } else {
  6060         NS_ABORT_IF_FALSE(specified.IsCalcUnit(), "unexpected unit");
  6061         LengthPercentPairCalcOps ops(aStyleContext,
  6062                                      aStyleContext->PresContext(),
  6063                                      aCanStoreInRuleTree);
  6064         nsRuleNode::ComputedCalc vals = ComputeCalc(specified, ops);
  6065         (size.*(axis->result)).mLength = vals.mLength;
  6066         (size.*(axis->result)).mPercent = vals.mPercent;
  6067         (size.*(axis->result)).mHasPercent = ops.mHasPercent;
  6068         size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
  6072     NS_ABORT_IF_FALSE(size.mWidthType < nsStyleBackground::Size::eDimensionType_COUNT,
  6073                       "bad width type");
  6074     NS_ABORT_IF_FALSE(size.mHeightType < nsStyleBackground::Size::eDimensionType_COUNT,
  6075                       "bad height type");
  6076     NS_ABORT_IF_FALSE((size.mWidthType != nsStyleBackground::Size::eContain &&
  6077                        size.mWidthType != nsStyleBackground::Size::eCover) ||
  6078                       size.mWidthType == size.mHeightType,
  6079                       "contain/cover apply to both dimensions or to neither");
  6081 };
  6083 template <class ComputedValueItem>
  6084 static void
  6085 SetBackgroundList(nsStyleContext* aStyleContext,
  6086                   const nsCSSValue& aValue,
  6087                   nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
  6088                   const nsAutoTArray<nsStyleBackground::Layer, 1> &aParentLayers,
  6089                   ComputedValueItem nsStyleBackground::Layer::* aResultLocation,
  6090                   ComputedValueItem aInitialValue,
  6091                   uint32_t aParentItemCount,
  6092                   uint32_t& aItemCount,
  6093                   uint32_t& aMaxItemCount,
  6094                   bool& aRebuild,
  6095                   bool& aCanStoreInRuleTree)
  6097   switch (aValue.GetUnit()) {
  6098   case eCSSUnit_Null:
  6099     break;
  6101   case eCSSUnit_Inherit:
  6102     aRebuild = true;
  6103     aCanStoreInRuleTree = false;
  6104     aLayers.EnsureLengthAtLeast(aParentItemCount);
  6105     aItemCount = aParentItemCount;
  6106     for (uint32_t i = 0; i < aParentItemCount; ++i) {
  6107       aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
  6109     break;
  6111   case eCSSUnit_Initial:
  6112   case eCSSUnit_Unset:
  6113     aRebuild = true;
  6114     aItemCount = 1;
  6115     aLayers[0].*aResultLocation = aInitialValue;
  6116     break;
  6118   case eCSSUnit_List:
  6119   case eCSSUnit_ListDep: {
  6120     aRebuild = true;
  6121     aItemCount = 0;
  6122     const nsCSSValueList* item = aValue.GetListValue();
  6123     do {
  6124       NS_ASSERTION(item->mValue.GetUnit() != eCSSUnit_Null &&
  6125                    item->mValue.GetUnit() != eCSSUnit_Inherit &&
  6126                    item->mValue.GetUnit() != eCSSUnit_Initial &&
  6127                    item->mValue.GetUnit() != eCSSUnit_Unset,
  6128                    "unexpected unit");
  6129       ++aItemCount;
  6130       aLayers.EnsureLengthAtLeast(aItemCount);
  6131       BackgroundItemComputer<nsCSSValueList, ComputedValueItem>
  6132         ::ComputeValue(aStyleContext, item,
  6133                        aLayers[aItemCount-1].*aResultLocation,
  6134                        aCanStoreInRuleTree);
  6135       item = item->mNext;
  6136     } while (item);
  6137     break;
  6140   default:
  6141     NS_ABORT_IF_FALSE(false,
  6142                       nsPrintfCString("unexpected unit %d",
  6143                                       aValue.GetUnit()).get());
  6146   if (aItemCount > aMaxItemCount)
  6147     aMaxItemCount = aItemCount;
  6150 template <class ComputedValueItem>
  6151 static void
  6152 SetBackgroundPairList(nsStyleContext* aStyleContext,
  6153                       const nsCSSValue& aValue,
  6154                       nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
  6155                       const nsAutoTArray<nsStyleBackground::Layer, 1>
  6156                                                                  &aParentLayers,
  6157                       ComputedValueItem nsStyleBackground::Layer::*
  6158                                                                 aResultLocation,
  6159                       ComputedValueItem aInitialValue,
  6160                       uint32_t aParentItemCount,
  6161                       uint32_t& aItemCount,
  6162                       uint32_t& aMaxItemCount,
  6163                       bool& aRebuild,
  6164                       bool& aCanStoreInRuleTree)
  6166   switch (aValue.GetUnit()) {
  6167   case eCSSUnit_Null:
  6168     break;
  6170   case eCSSUnit_Inherit:
  6171     aRebuild = true;
  6172     aCanStoreInRuleTree = false;
  6173     aLayers.EnsureLengthAtLeast(aParentItemCount);
  6174     aItemCount = aParentItemCount;
  6175     for (uint32_t i = 0; i < aParentItemCount; ++i) {
  6176       aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
  6178     break;
  6180   case eCSSUnit_Initial:
  6181   case eCSSUnit_Unset:
  6182     aRebuild = true;
  6183     aItemCount = 1;
  6184     aLayers[0].*aResultLocation = aInitialValue;
  6185     break;
  6187   case eCSSUnit_PairList:
  6188   case eCSSUnit_PairListDep: {
  6189     aRebuild = true;
  6190     aItemCount = 0;
  6191     const nsCSSValuePairList* item = aValue.GetPairListValue();
  6192     do {
  6193       NS_ASSERTION(item->mXValue.GetUnit() != eCSSUnit_Inherit &&
  6194                    item->mXValue.GetUnit() != eCSSUnit_Initial &&
  6195                    item->mXValue.GetUnit() != eCSSUnit_Unset &&
  6196                    item->mYValue.GetUnit() != eCSSUnit_Inherit &&
  6197                    item->mYValue.GetUnit() != eCSSUnit_Initial &&
  6198                    item->mYValue.GetUnit() != eCSSUnit_Unset,
  6199                    "unexpected unit");
  6200       ++aItemCount;
  6201       aLayers.EnsureLengthAtLeast(aItemCount);
  6202       BackgroundItemComputer<nsCSSValuePairList, ComputedValueItem>
  6203         ::ComputeValue(aStyleContext, item,
  6204                        aLayers[aItemCount-1].*aResultLocation,
  6205                        aCanStoreInRuleTree);
  6206       item = item->mNext;
  6207     } while (item);
  6208     break;
  6211   default:
  6212     NS_ABORT_IF_FALSE(false,
  6213                       nsPrintfCString("unexpected unit %d",
  6214                                       aValue.GetUnit()).get());
  6217   if (aItemCount > aMaxItemCount)
  6218     aMaxItemCount = aItemCount;
  6221 template <class ComputedValueItem>
  6222 static void
  6223 FillBackgroundList(nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
  6224     ComputedValueItem nsStyleBackground::Layer::* aResultLocation,
  6225     uint32_t aItemCount, uint32_t aFillCount)
  6227   NS_PRECONDITION(aFillCount <= aLayers.Length(), "unexpected array length");
  6228   for (uint32_t sourceLayer = 0, destLayer = aItemCount;
  6229        destLayer < aFillCount;
  6230        ++sourceLayer, ++destLayer) {
  6231     aLayers[destLayer].*aResultLocation =
  6232       aLayers[sourceLayer].*aResultLocation;
  6236 const void*
  6237 nsRuleNode::ComputeBackgroundData(void* aStartStruct,
  6238                                   const nsRuleData* aRuleData,
  6239                                   nsStyleContext* aContext,
  6240                                   nsRuleNode* aHighestNode,
  6241                                   const RuleDetail aRuleDetail,
  6242                                   const bool aCanStoreInRuleTree)
  6244   COMPUTE_START_RESET(Background, (), bg, parentBG)
  6246   // background-color: color, string, inherit
  6247   const nsCSSValue* backColorValue = aRuleData->ValueForBackgroundColor();
  6248   if (eCSSUnit_Initial == backColorValue->GetUnit() ||
  6249       eCSSUnit_Unset == backColorValue->GetUnit()) {
  6250     bg->mBackgroundColor = NS_RGBA(0, 0, 0, 0);
  6251   } else if (!SetColor(*backColorValue, parentBG->mBackgroundColor,
  6252                        mPresContext, aContext, bg->mBackgroundColor,
  6253                        canStoreInRuleTree)) {
  6254     NS_ASSERTION(eCSSUnit_Null == backColorValue->GetUnit(),
  6255                  "unexpected color unit");
  6258   uint32_t maxItemCount = 1;
  6259   bool rebuild = false;
  6261   // background-image: url (stored as image), none, inherit [list]
  6262   nsStyleImage initialImage;
  6263   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundImage(),
  6264                     bg->mLayers,
  6265                     parentBG->mLayers, &nsStyleBackground::Layer::mImage,
  6266                     initialImage, parentBG->mImageCount, bg->mImageCount,
  6267                     maxItemCount, rebuild, canStoreInRuleTree);
  6269   // background-repeat: enum, inherit, initial [pair list]
  6270   nsStyleBackground::Repeat initialRepeat;
  6271   initialRepeat.SetInitialValues();
  6272   SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundRepeat(),
  6273                         bg->mLayers,
  6274                         parentBG->mLayers, &nsStyleBackground::Layer::mRepeat,
  6275                         initialRepeat, parentBG->mRepeatCount,
  6276                         bg->mRepeatCount, maxItemCount, rebuild, 
  6277                         canStoreInRuleTree);
  6279   // background-attachment: enum, inherit, initial [list]
  6280   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundAttachment(),
  6281                     bg->mLayers, parentBG->mLayers,
  6282                     &nsStyleBackground::Layer::mAttachment,
  6283                     uint8_t(NS_STYLE_BG_ATTACHMENT_SCROLL),
  6284                     parentBG->mAttachmentCount,
  6285                     bg->mAttachmentCount, maxItemCount, rebuild,
  6286                     canStoreInRuleTree);
  6288   // background-clip: enum, inherit, initial [list]
  6289   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundClip(),
  6290                     bg->mLayers,
  6291                     parentBG->mLayers, &nsStyleBackground::Layer::mClip,
  6292                     uint8_t(NS_STYLE_BG_CLIP_BORDER), parentBG->mClipCount,
  6293                     bg->mClipCount, maxItemCount, rebuild, canStoreInRuleTree);
  6295   // background-inline-policy: enum, inherit, initial
  6296   SetDiscrete(*aRuleData->ValueForBackgroundInlinePolicy(),
  6297               bg->mBackgroundInlinePolicy,
  6298               canStoreInRuleTree,
  6299               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  6300               parentBG->mBackgroundInlinePolicy,
  6301               NS_STYLE_BG_INLINE_POLICY_CONTINUOUS, 0, 0, 0, 0);
  6303   // background-blend-mode: enum, inherit, initial [list]
  6304   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundBlendMode(),
  6305                     bg->mLayers,
  6306                     parentBG->mLayers, &nsStyleBackground::Layer::mBlendMode,
  6307                     uint8_t(NS_STYLE_BLEND_NORMAL), parentBG->mBlendModeCount,
  6308                     bg->mBlendModeCount, maxItemCount, rebuild,
  6309                     canStoreInRuleTree);
  6311   // background-origin: enum, inherit, initial [list]
  6312   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundOrigin(),
  6313                     bg->mLayers,
  6314                     parentBG->mLayers, &nsStyleBackground::Layer::mOrigin,
  6315                     uint8_t(NS_STYLE_BG_ORIGIN_PADDING), parentBG->mOriginCount,
  6316                     bg->mOriginCount, maxItemCount, rebuild,
  6317                     canStoreInRuleTree);
  6319   // background-position: enum, length, percent (flags), inherit [pair list]
  6320   nsStyleBackground::Position initialPosition;
  6321   initialPosition.SetInitialValues();
  6322   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundPosition(),
  6323                     bg->mLayers,
  6324                     parentBG->mLayers, &nsStyleBackground::Layer::mPosition,
  6325                     initialPosition, parentBG->mPositionCount,
  6326                     bg->mPositionCount, maxItemCount, rebuild,
  6327                     canStoreInRuleTree);
  6329   // background-size: enum, length, auto, inherit, initial [pair list]
  6330   nsStyleBackground::Size initialSize;
  6331   initialSize.SetInitialValues();
  6332   SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundSize(),
  6333                         bg->mLayers,
  6334                         parentBG->mLayers, &nsStyleBackground::Layer::mSize,
  6335                         initialSize, parentBG->mSizeCount,
  6336                         bg->mSizeCount, maxItemCount, rebuild,
  6337                         canStoreInRuleTree);
  6339   if (rebuild) {
  6340     // Delete any extra items.  We need to keep layers in which any
  6341     // property was specified.
  6342     bg->mLayers.TruncateLength(maxItemCount);
  6344     uint32_t fillCount = bg->mImageCount;
  6345     FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mImage,
  6346                        bg->mImageCount, fillCount);
  6347     FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mRepeat,
  6348                        bg->mRepeatCount, fillCount);
  6349     FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mAttachment,
  6350                        bg->mAttachmentCount, fillCount);
  6351     FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mClip,
  6352                        bg->mClipCount, fillCount);
  6353     FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mBlendMode,
  6354                        bg->mBlendModeCount, fillCount);
  6355     FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mOrigin,
  6356                        bg->mOriginCount, fillCount);
  6357     FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mPosition,
  6358                        bg->mPositionCount, fillCount);
  6359     FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mSize,
  6360                        bg->mSizeCount, fillCount);
  6363   // Now that the dust has settled, register the images with the document
  6364   for (uint32_t i = 0; i < bg->mImageCount; ++i)
  6365     bg->mLayers[i].TrackImages(aContext->PresContext());
  6367   COMPUTE_END_RESET(Background, bg)
  6370 const void*
  6371 nsRuleNode::ComputeMarginData(void* aStartStruct,
  6372                               const nsRuleData* aRuleData,
  6373                               nsStyleContext* aContext,
  6374                               nsRuleNode* aHighestNode,
  6375                               const RuleDetail aRuleDetail,
  6376                               const bool aCanStoreInRuleTree)
  6378   COMPUTE_START_RESET(Margin, (), margin, parentMargin)
  6380   // margin: length, percent, auto, inherit
  6381   nsStyleCoord  coord;
  6382   nsCSSRect ourMargin;
  6383   ourMargin.mTop = *aRuleData->ValueForMarginTop();
  6384   ourMargin.mRight = *aRuleData->ValueForMarginRightValue();
  6385   ourMargin.mBottom = *aRuleData->ValueForMarginBottom();
  6386   ourMargin.mLeft = *aRuleData->ValueForMarginLeftValue();
  6387   AdjustLogicalBoxProp(aContext,
  6388                        *aRuleData->ValueForMarginLeftLTRSource(),
  6389                        *aRuleData->ValueForMarginLeftRTLSource(),
  6390                        *aRuleData->ValueForMarginStartValue(),
  6391                        *aRuleData->ValueForMarginEndValue(),
  6392                        NS_SIDE_LEFT, ourMargin, canStoreInRuleTree);
  6393   AdjustLogicalBoxProp(aContext,
  6394                        *aRuleData->ValueForMarginRightLTRSource(),
  6395                        *aRuleData->ValueForMarginRightRTLSource(),
  6396                        *aRuleData->ValueForMarginEndValue(),
  6397                        *aRuleData->ValueForMarginStartValue(),
  6398                        NS_SIDE_RIGHT, ourMargin, canStoreInRuleTree);
  6399   NS_FOR_CSS_SIDES(side) {
  6400     nsStyleCoord parentCoord = parentMargin->mMargin.Get(side);
  6401     if (SetCoord(ourMargin.*(nsCSSRect::sides[side]),
  6402                  coord, parentCoord,
  6403                  SETCOORD_LPAH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  6404                    SETCOORD_UNSET_INITIAL,
  6405                  aContext, mPresContext, canStoreInRuleTree)) {
  6406       margin->mMargin.Set(side, coord);
  6410   margin->RecalcData();
  6411   COMPUTE_END_RESET(Margin, margin)
  6414 static void
  6415 SetBorderImageRect(const nsCSSValue& aValue,
  6416                    /** outparam */ nsCSSRect& aRect)
  6418   switch (aValue.GetUnit()) {
  6419   case eCSSUnit_Null:
  6420     aRect.Reset();
  6421     break;
  6422   case eCSSUnit_Rect:
  6423     aRect = aValue.GetRectValue();
  6424     break;
  6425   case eCSSUnit_Inherit:
  6426   case eCSSUnit_Initial:
  6427   case eCSSUnit_Unset:
  6428     aRect.SetAllSidesTo(aValue);
  6429     break;
  6430   default:
  6431     NS_ASSERTION(false, "Unexpected border image value for rect.");
  6435 static void
  6436 SetBorderImagePair(const nsCSSValue& aValue,
  6437                    /** outparam */ nsCSSValuePair& aPair)
  6439   switch (aValue.GetUnit()) {
  6440   case eCSSUnit_Null:
  6441     aPair.Reset();
  6442     break;
  6443   case eCSSUnit_Pair:
  6444     aPair = aValue.GetPairValue();
  6445     break;
  6446   case eCSSUnit_Inherit:
  6447   case eCSSUnit_Initial:
  6448   case eCSSUnit_Unset:
  6449     aPair.SetBothValuesTo(aValue);
  6450     break;
  6451   default:
  6452     NS_ASSERTION(false, "Unexpected border image value for pair.");
  6456 static void
  6457 SetBorderImageSlice(const nsCSSValue& aValue,
  6458                     /** outparam */ nsCSSValue& aSlice,
  6459                     /** outparam */ nsCSSValue& aFill)
  6461   const nsCSSValueList* valueList;
  6462   switch (aValue.GetUnit()) {
  6463   case eCSSUnit_Null:
  6464     aSlice.Reset();
  6465     aFill.Reset();
  6466     break;
  6467   case eCSSUnit_List:
  6468     // Get slice dimensions.
  6469     valueList = aValue.GetListValue();
  6470     aSlice = valueList->mValue;
  6472     // Get "fill" keyword.
  6473     valueList = valueList->mNext;
  6474     if (valueList) {
  6475       aFill = valueList->mValue;
  6476     } else {
  6477       aFill.SetInitialValue();
  6479     break;
  6480   case eCSSUnit_Inherit:
  6481   case eCSSUnit_Initial:
  6482   case eCSSUnit_Unset:
  6483     aSlice = aValue;
  6484     aFill = aValue;
  6485     break;
  6486   default:
  6487     NS_ASSERTION(false, "Unexpected border image value for pair.");
  6491 const void*
  6492 nsRuleNode::ComputeBorderData(void* aStartStruct,
  6493                               const nsRuleData* aRuleData,
  6494                               nsStyleContext* aContext,
  6495                               nsRuleNode* aHighestNode,
  6496                               const RuleDetail aRuleDetail,
  6497                               const bool aCanStoreInRuleTree)
  6499   COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder)
  6501   // box-shadow: none, list, inherit, initial
  6502   const nsCSSValue* boxShadowValue = aRuleData->ValueForBoxShadow();
  6503   switch (boxShadowValue->GetUnit()) {
  6504   case eCSSUnit_Null:
  6505     break;
  6507   case eCSSUnit_Initial:
  6508   case eCSSUnit_Unset:
  6509   case eCSSUnit_None:
  6510     border->mBoxShadow = nullptr;
  6511     break;
  6513   case eCSSUnit_Inherit:
  6514     border->mBoxShadow = parentBorder->mBoxShadow;
  6515     canStoreInRuleTree = false;
  6516     break;
  6518   case eCSSUnit_List:
  6519   case eCSSUnit_ListDep:
  6520     border->mBoxShadow = GetShadowData(boxShadowValue->GetListValue(),
  6521                                        aContext, true, canStoreInRuleTree);
  6522     break;
  6524   default:
  6525     NS_ABORT_IF_FALSE(false,
  6526                       nsPrintfCString("unrecognized shadow unit %d",
  6527                                       boxShadowValue->GetUnit()).get());
  6530   // border-width, border-*-width: length, enum, inherit
  6531   nsStyleCoord  coord;
  6532   nsCSSRect ourBorderWidth;
  6533   ourBorderWidth.mTop = *aRuleData->ValueForBorderTopWidth();
  6534   ourBorderWidth.mRight = *aRuleData->ValueForBorderRightWidthValue();
  6535   ourBorderWidth.mBottom = *aRuleData->ValueForBorderBottomWidth();
  6536   ourBorderWidth.mLeft = *aRuleData->ValueForBorderLeftWidthValue();
  6537   AdjustLogicalBoxProp(aContext,
  6538                        *aRuleData->ValueForBorderLeftWidthLTRSource(),
  6539                        *aRuleData->ValueForBorderLeftWidthRTLSource(),
  6540                        *aRuleData->ValueForBorderStartWidthValue(),
  6541                        *aRuleData->ValueForBorderEndWidthValue(),
  6542                        NS_SIDE_LEFT, ourBorderWidth, canStoreInRuleTree);
  6543   AdjustLogicalBoxProp(aContext,
  6544                        *aRuleData->ValueForBorderRightWidthLTRSource(),
  6545                        *aRuleData->ValueForBorderRightWidthRTLSource(),
  6546                        *aRuleData->ValueForBorderEndWidthValue(),
  6547                        *aRuleData->ValueForBorderStartWidthValue(),
  6548                        NS_SIDE_RIGHT, ourBorderWidth, canStoreInRuleTree);
  6549   { // scope for compilers with broken |for| loop scoping
  6550     NS_FOR_CSS_SIDES(side) {
  6551       const nsCSSValue &value = ourBorderWidth.*(nsCSSRect::sides[side]);
  6552       NS_ASSERTION(eCSSUnit_Percent != value.GetUnit(),
  6553                    "Percentage borders not implemented yet "
  6554                    "If implementing, make sure to fix all consumers of "
  6555                    "nsStyleBorder, the IsPercentageAwareChild method, "
  6556                    "the nsAbsoluteContainingBlock::FrameDependsOnContainer "
  6557                    "method, the "
  6558                    "nsLineLayout::IsPercentageAwareReplacedElement method "
  6559                    "and probably some other places");
  6560       if (eCSSUnit_Enumerated == value.GetUnit()) {
  6561         NS_ASSERTION(value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
  6562                      value.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
  6563                      value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
  6564                      "Unexpected enum value");
  6565         border->SetBorderWidth(side,
  6566                                (mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
  6568       // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
  6569       else if (SetCoord(value, coord, nsStyleCoord(),
  6570                         SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
  6571                         aContext, mPresContext, canStoreInRuleTree)) {
  6572         NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
  6573         // clamp negative calc() to 0.
  6574         border->SetBorderWidth(side, std::max(coord.GetCoordValue(), 0));
  6576       else if (eCSSUnit_Inherit == value.GetUnit()) {
  6577         canStoreInRuleTree = false;
  6578         border->SetBorderWidth(side,
  6579                                parentBorder->GetComputedBorder().Side(side));
  6581       else if (eCSSUnit_Initial == value.GetUnit() ||
  6582                eCSSUnit_Unset == value.GetUnit()) {
  6583         border->SetBorderWidth(side,
  6584           (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
  6586       else {
  6587         NS_ASSERTION(eCSSUnit_Null == value.GetUnit(),
  6588                      "missing case handling border width");
  6593   // border-style, border-*-style: enum, inherit
  6594   nsCSSRect ourBorderStyle;
  6595   ourBorderStyle.mTop = *aRuleData->ValueForBorderTopStyle();
  6596   ourBorderStyle.mRight = *aRuleData->ValueForBorderRightStyleValue();
  6597   ourBorderStyle.mBottom = *aRuleData->ValueForBorderBottomStyle();
  6598   ourBorderStyle.mLeft = *aRuleData->ValueForBorderLeftStyleValue();
  6599   AdjustLogicalBoxProp(aContext,
  6600                        *aRuleData->ValueForBorderLeftStyleLTRSource(),
  6601                        *aRuleData->ValueForBorderLeftStyleRTLSource(),
  6602                        *aRuleData->ValueForBorderStartStyleValue(),
  6603                        *aRuleData->ValueForBorderEndStyleValue(),
  6604                        NS_SIDE_LEFT, ourBorderStyle, canStoreInRuleTree);
  6605   AdjustLogicalBoxProp(aContext,
  6606                        *aRuleData->ValueForBorderRightStyleLTRSource(),
  6607                        *aRuleData->ValueForBorderRightStyleRTLSource(),
  6608                        *aRuleData->ValueForBorderEndStyleValue(),
  6609                        *aRuleData->ValueForBorderStartStyleValue(),
  6610                        NS_SIDE_RIGHT, ourBorderStyle, canStoreInRuleTree);
  6611   { // scope for compilers with broken |for| loop scoping
  6612     NS_FOR_CSS_SIDES(side) {
  6613       const nsCSSValue &value = ourBorderStyle.*(nsCSSRect::sides[side]);
  6614       nsCSSUnit unit = value.GetUnit();
  6615       NS_ABORT_IF_FALSE(eCSSUnit_None != unit,
  6616                         "'none' should be handled as enumerated value");
  6617       if (eCSSUnit_Enumerated == unit) {
  6618         border->SetBorderStyle(side, value.GetIntValue());
  6620       else if (eCSSUnit_Initial == unit ||
  6621                eCSSUnit_Unset == unit) {
  6622         border->SetBorderStyle(side, NS_STYLE_BORDER_STYLE_NONE);
  6624       else if (eCSSUnit_Inherit == unit) {
  6625         canStoreInRuleTree = false;
  6626         border->SetBorderStyle(side, parentBorder->GetBorderStyle(side));
  6631   // -moz-border-*-colors: color, string, enum, none, inherit/initial
  6632   nscolor borderColor;
  6633   nscolor unused = NS_RGB(0,0,0);
  6635   static const nsCSSProperty borderColorsProps[] = {
  6636     eCSSProperty_border_top_colors,
  6637     eCSSProperty_border_right_colors,
  6638     eCSSProperty_border_bottom_colors,
  6639     eCSSProperty_border_left_colors
  6640   };
  6642   NS_FOR_CSS_SIDES(side) {
  6643     const nsCSSValue& value = *aRuleData->ValueFor(borderColorsProps[side]);
  6644     switch (value.GetUnit()) {
  6645     case eCSSUnit_Null:
  6646       break;
  6648     case eCSSUnit_Initial:
  6649     case eCSSUnit_Unset:
  6650     case eCSSUnit_None:
  6651       border->ClearBorderColors(side);
  6652       break;
  6654     case eCSSUnit_Inherit: {
  6655       canStoreInRuleTree = false;
  6656       border->ClearBorderColors(side);
  6657       if (parentContext) {
  6658         nsBorderColors *parentColors;
  6659         parentBorder->GetCompositeColors(side, &parentColors);
  6660         if (parentColors) {
  6661           border->EnsureBorderColors();
  6662           border->mBorderColors[side] = parentColors->Clone();
  6665       break;
  6668     case eCSSUnit_List:
  6669     case eCSSUnit_ListDep: {
  6670       // Some composite border color information has been specified for this
  6671       // border side.
  6672       border->EnsureBorderColors();
  6673       border->ClearBorderColors(side);
  6674       const nsCSSValueList* list = value.GetListValue();
  6675       while (list) {
  6676         if (SetColor(list->mValue, unused, mPresContext,
  6677                      aContext, borderColor, canStoreInRuleTree))
  6678           border->AppendBorderColor(side, borderColor);
  6679         else {
  6680           NS_NOTREACHED("unexpected item in -moz-border-*-colors list");
  6682         list = list->mNext;
  6684       break;
  6687     default:
  6688       NS_ABORT_IF_FALSE(false, "unrecognized border color unit");
  6692   // border-color, border-*-color: color, string, enum, inherit
  6693   bool foreground;
  6694   nsCSSRect ourBorderColor;
  6695   ourBorderColor.mTop = *aRuleData->ValueForBorderTopColor();
  6696   ourBorderColor.mRight = *aRuleData->ValueForBorderRightColorValue();
  6697   ourBorderColor.mBottom = *aRuleData->ValueForBorderBottomColor();
  6698   ourBorderColor.mLeft = *aRuleData->ValueForBorderLeftColorValue();
  6699   AdjustLogicalBoxProp(aContext,
  6700                        *aRuleData->ValueForBorderLeftColorLTRSource(),
  6701                        *aRuleData->ValueForBorderLeftColorRTLSource(),
  6702                        *aRuleData->ValueForBorderStartColorValue(),
  6703                        *aRuleData->ValueForBorderEndColorValue(),
  6704                        NS_SIDE_LEFT, ourBorderColor, canStoreInRuleTree);
  6705   AdjustLogicalBoxProp(aContext,
  6706                        *aRuleData->ValueForBorderRightColorLTRSource(),
  6707                        *aRuleData->ValueForBorderRightColorRTLSource(),
  6708                        *aRuleData->ValueForBorderEndColorValue(),
  6709                        *aRuleData->ValueForBorderStartColorValue(),
  6710                        NS_SIDE_RIGHT, ourBorderColor, canStoreInRuleTree);
  6711   { // scope for compilers with broken |for| loop scoping
  6712     NS_FOR_CSS_SIDES(side) {
  6713       const nsCSSValue &value = ourBorderColor.*(nsCSSRect::sides[side]);
  6714       if (eCSSUnit_Inherit == value.GetUnit()) {
  6715         canStoreInRuleTree = false;
  6716         if (parentContext) {
  6717           parentBorder->GetBorderColor(side, borderColor, foreground);
  6718           if (foreground) {
  6719             // We want to inherit the color from the parent, not use the
  6720             // color on the element where this chunk of style data will be
  6721             // used.  We can ensure that the data for the parent are fully
  6722             // computed (unlike for the element where this will be used, for
  6723             // which the color could be specified on a more specific rule).
  6724             border->SetBorderColor(side, parentContext->StyleColor()->mColor);
  6725           } else
  6726             border->SetBorderColor(side, borderColor);
  6727         } else {
  6728           // We're the root
  6729           border->SetBorderToForeground(side);
  6732       else if (SetColor(value, unused, mPresContext, aContext, borderColor,
  6733                         canStoreInRuleTree)) {
  6734         border->SetBorderColor(side, borderColor);
  6736       else if (eCSSUnit_Enumerated == value.GetUnit()) {
  6737         switch (value.GetIntValue()) {
  6738           case NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR:
  6739             border->SetBorderToForeground(side);
  6740             break;
  6741           default:
  6742             NS_NOTREACHED("Unexpected enumerated color");
  6743             break;
  6746       else if (eCSSUnit_Initial == value.GetUnit() ||
  6747                eCSSUnit_Unset == value.GetUnit()) {
  6748         border->SetBorderToForeground(side);
  6753   // border-radius: length, percent, inherit
  6755     const nsCSSProperty* subprops =
  6756       nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius);
  6757     NS_FOR_CSS_FULL_CORNERS(corner) {
  6758       int cx = NS_FULL_TO_HALF_CORNER(corner, false);
  6759       int cy = NS_FULL_TO_HALF_CORNER(corner, true);
  6760       const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
  6761       nsStyleCoord parentX = parentBorder->mBorderRadius.Get(cx);
  6762       nsStyleCoord parentY = parentBorder->mBorderRadius.Get(cy);
  6763       nsStyleCoord coordX, coordY;
  6765       if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
  6766                         SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
  6767                           SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
  6768                         aContext, mPresContext, canStoreInRuleTree)) {
  6769         border->mBorderRadius.Set(cx, coordX);
  6770         border->mBorderRadius.Set(cy, coordY);
  6775   // float-edge: enum, inherit, initial
  6776   SetDiscrete(*aRuleData->ValueForFloatEdge(),
  6777               border->mFloatEdge, canStoreInRuleTree,
  6778               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  6779               parentBorder->mFloatEdge,
  6780               NS_STYLE_FLOAT_EDGE_CONTENT, 0, 0, 0, 0);
  6782   // border-image-source
  6783   const nsCSSValue* borderImageSource = aRuleData->ValueForBorderImageSource();
  6784   if (borderImageSource->GetUnit() == eCSSUnit_Inherit) {
  6785     canStoreInRuleTree = false;
  6786     border->mBorderImageSource = parentBorder->mBorderImageSource;
  6787   } else {
  6788     SetStyleImage(aContext,
  6789                   *borderImageSource,
  6790                   border->mBorderImageSource,
  6791                   canStoreInRuleTree);
  6794   nsCSSValue borderImageSliceValue;
  6795   nsCSSValue borderImageSliceFill;
  6796   SetBorderImageSlice(*aRuleData->ValueForBorderImageSlice(),
  6797                       borderImageSliceValue, borderImageSliceFill);
  6799   // border-image-slice: fill
  6800   SetDiscrete(borderImageSliceFill,
  6801               border->mBorderImageFill,
  6802               canStoreInRuleTree,
  6803               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  6804               parentBorder->mBorderImageFill,
  6805               NS_STYLE_BORDER_IMAGE_SLICE_NOFILL, 0, 0, 0, 0);
  6807   nsCSSRect borderImageSlice;
  6808   SetBorderImageRect(borderImageSliceValue, borderImageSlice);
  6810   nsCSSRect borderImageWidth;
  6811   SetBorderImageRect(*aRuleData->ValueForBorderImageWidth(),
  6812                      borderImageWidth);
  6814   nsCSSRect borderImageOutset;
  6815   SetBorderImageRect(*aRuleData->ValueForBorderImageOutset(),
  6816                      borderImageOutset);
  6818   NS_FOR_CSS_SIDES (side) {
  6819     // border-image-slice
  6820     if (SetCoord(borderImageSlice.*(nsCSSRect::sides[side]), coord,
  6821                  parentBorder->mBorderImageSlice.Get(side),
  6822                  SETCOORD_FACTOR | SETCOORD_PERCENT |
  6823                    SETCOORD_INHERIT | SETCOORD_INITIAL_HUNDRED_PCT |
  6824                    SETCOORD_UNSET_INITIAL,
  6825                  aContext, mPresContext, canStoreInRuleTree)) {
  6826       border->mBorderImageSlice.Set(side, coord);
  6829     // border-image-width
  6830     // 'auto' here means "same as slice"
  6831     if (SetCoord(borderImageWidth.*(nsCSSRect::sides[side]), coord,
  6832                  parentBorder->mBorderImageWidth.Get(side),
  6833                  SETCOORD_LPAH | SETCOORD_FACTOR | SETCOORD_INITIAL_FACTOR_ONE |
  6834                    SETCOORD_UNSET_INITIAL,
  6835                  aContext, mPresContext, canStoreInRuleTree)) {
  6836       border->mBorderImageWidth.Set(side, coord);
  6839     // border-image-outset
  6840     if (SetCoord(borderImageOutset.*(nsCSSRect::sides[side]), coord,
  6841                  parentBorder->mBorderImageOutset.Get(side),
  6842                  SETCOORD_LENGTH | SETCOORD_FACTOR |
  6843                    SETCOORD_INHERIT | SETCOORD_INITIAL_FACTOR_ZERO |
  6844                    SETCOORD_UNSET_INITIAL,
  6845                  aContext, mPresContext, canStoreInRuleTree)) {
  6846       border->mBorderImageOutset.Set(side, coord);
  6850   // border-image-repeat
  6851   nsCSSValuePair borderImageRepeat;
  6852   SetBorderImagePair(*aRuleData->ValueForBorderImageRepeat(),
  6853                      borderImageRepeat);
  6855   SetDiscrete(borderImageRepeat.mXValue,
  6856               border->mBorderImageRepeatH,
  6857               canStoreInRuleTree,
  6858               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  6859               parentBorder->mBorderImageRepeatH,
  6860               NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
  6862   SetDiscrete(borderImageRepeat.mYValue,
  6863               border->mBorderImageRepeatV,
  6864               canStoreInRuleTree,
  6865               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  6866               parentBorder->mBorderImageRepeatV,
  6867               NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
  6869   border->TrackImage(aContext->PresContext());
  6871   COMPUTE_END_RESET(Border, border)
  6874 const void*
  6875 nsRuleNode::ComputePaddingData(void* aStartStruct,
  6876                                const nsRuleData* aRuleData,
  6877                                nsStyleContext* aContext,
  6878                                nsRuleNode* aHighestNode,
  6879                                const RuleDetail aRuleDetail,
  6880                                const bool aCanStoreInRuleTree)
  6882   COMPUTE_START_RESET(Padding, (), padding, parentPadding)
  6884   // padding: length, percent, inherit
  6885   nsStyleCoord  coord;
  6886   nsCSSRect ourPadding;
  6887   ourPadding.mTop = *aRuleData->ValueForPaddingTop();
  6888   ourPadding.mRight = *aRuleData->ValueForPaddingRightValue();
  6889   ourPadding.mBottom = *aRuleData->ValueForPaddingBottom();
  6890   ourPadding.mLeft = *aRuleData->ValueForPaddingLeftValue();
  6891   AdjustLogicalBoxProp(aContext,
  6892                        *aRuleData->ValueForPaddingLeftLTRSource(),
  6893                        *aRuleData->ValueForPaddingLeftRTLSource(),
  6894                        *aRuleData->ValueForPaddingStartValue(),
  6895                        *aRuleData->ValueForPaddingEndValue(),
  6896                        NS_SIDE_LEFT, ourPadding, canStoreInRuleTree);
  6897   AdjustLogicalBoxProp(aContext,
  6898                        *aRuleData->ValueForPaddingRightLTRSource(),
  6899                        *aRuleData->ValueForPaddingRightRTLSource(),
  6900                        *aRuleData->ValueForPaddingEndValue(),
  6901                        *aRuleData->ValueForPaddingStartValue(),
  6902                        NS_SIDE_RIGHT, ourPadding, canStoreInRuleTree);
  6903   NS_FOR_CSS_SIDES(side) {
  6904     nsStyleCoord parentCoord = parentPadding->mPadding.Get(side);
  6905     if (SetCoord(ourPadding.*(nsCSSRect::sides[side]),
  6906                  coord, parentCoord,
  6907                  SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  6908                    SETCOORD_UNSET_INITIAL,
  6909                  aContext, mPresContext, canStoreInRuleTree)) {
  6910       padding->mPadding.Set(side, coord);
  6914   padding->RecalcData();
  6915   COMPUTE_END_RESET(Padding, padding)
  6918 const void*
  6919 nsRuleNode::ComputeOutlineData(void* aStartStruct,
  6920                                const nsRuleData* aRuleData,
  6921                                nsStyleContext* aContext,
  6922                                nsRuleNode* aHighestNode,
  6923                                const RuleDetail aRuleDetail,
  6924                                const bool aCanStoreInRuleTree)
  6926   COMPUTE_START_RESET(Outline, (mPresContext), outline, parentOutline)
  6928   // outline-width: length, enum, inherit
  6929   const nsCSSValue* outlineWidthValue = aRuleData->ValueForOutlineWidth();
  6930   if (eCSSUnit_Initial == outlineWidthValue->GetUnit() ||
  6931       eCSSUnit_Unset == outlineWidthValue->GetUnit()) {
  6932     outline->mOutlineWidth =
  6933       nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
  6935   else {
  6936     SetCoord(*outlineWidthValue, outline->mOutlineWidth,
  6937              parentOutline->mOutlineWidth,
  6938              SETCOORD_LEH | SETCOORD_CALC_LENGTH_ONLY, aContext,
  6939              mPresContext, canStoreInRuleTree);
  6942   // outline-offset: length, inherit
  6943   nsStyleCoord tempCoord;
  6944   const nsCSSValue* outlineOffsetValue = aRuleData->ValueForOutlineOffset();
  6945   if (SetCoord(*outlineOffsetValue, tempCoord,
  6946                nsStyleCoord(parentOutline->mOutlineOffset,
  6947                             nsStyleCoord::CoordConstructor),
  6948                SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
  6949                  SETCOORD_UNSET_INITIAL,
  6950                aContext, mPresContext, canStoreInRuleTree)) {
  6951     outline->mOutlineOffset = tempCoord.GetCoordValue();
  6952   } else {
  6953     NS_ASSERTION(outlineOffsetValue->GetUnit() == eCSSUnit_Null,
  6954                  "unexpected unit");
  6957   // outline-color: color, string, enum, inherit
  6958   nscolor outlineColor;
  6959   nscolor unused = NS_RGB(0,0,0);
  6960   const nsCSSValue* outlineColorValue = aRuleData->ValueForOutlineColor();
  6961   if (eCSSUnit_Inherit == outlineColorValue->GetUnit()) {
  6962     canStoreInRuleTree = false;
  6963     if (parentContext) {
  6964       if (parentOutline->GetOutlineColor(outlineColor))
  6965         outline->SetOutlineColor(outlineColor);
  6966       else {
  6967         // We want to inherit the color from the parent, not use the
  6968         // color on the element where this chunk of style data will be
  6969         // used.  We can ensure that the data for the parent are fully
  6970         // computed (unlike for the element where this will be used, for
  6971         // which the color could be specified on a more specific rule).
  6972         outline->SetOutlineColor(parentContext->StyleColor()->mColor);
  6974     } else {
  6975       outline->SetOutlineInitialColor();
  6978   else if (SetColor(*outlineColorValue, unused, mPresContext,
  6979                     aContext, outlineColor, canStoreInRuleTree))
  6980     outline->SetOutlineColor(outlineColor);
  6981   else if (eCSSUnit_Enumerated == outlineColorValue->GetUnit() ||
  6982            eCSSUnit_Initial == outlineColorValue->GetUnit() ||
  6983            eCSSUnit_Unset == outlineColorValue->GetUnit()) {
  6984     outline->SetOutlineInitialColor();
  6987   // -moz-outline-radius: length, percent, inherit
  6989     const nsCSSProperty* subprops =
  6990       nsCSSProps::SubpropertyEntryFor(eCSSProperty__moz_outline_radius);
  6991     NS_FOR_CSS_FULL_CORNERS(corner) {
  6992       int cx = NS_FULL_TO_HALF_CORNER(corner, false);
  6993       int cy = NS_FULL_TO_HALF_CORNER(corner, true);
  6994       const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
  6995       nsStyleCoord parentX = parentOutline->mOutlineRadius.Get(cx);
  6996       nsStyleCoord parentY = parentOutline->mOutlineRadius.Get(cy);
  6997       nsStyleCoord coordX, coordY;
  6999       if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
  7000                         SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
  7001                           SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
  7002                         aContext, mPresContext, canStoreInRuleTree)) {
  7003         outline->mOutlineRadius.Set(cx, coordX);
  7004         outline->mOutlineRadius.Set(cy, coordY);
  7009   // outline-style: enum, inherit, initial
  7010   // cannot use SetDiscrete because of SetOutlineStyle
  7011   const nsCSSValue* outlineStyleValue = aRuleData->ValueForOutlineStyle();
  7012   nsCSSUnit unit = outlineStyleValue->GetUnit();
  7013   NS_ABORT_IF_FALSE(eCSSUnit_None != unit && eCSSUnit_Auto != unit,
  7014                     "'none' and 'auto' should be handled as enumerated values");
  7015   if (eCSSUnit_Enumerated == unit) {
  7016     outline->SetOutlineStyle(outlineStyleValue->GetIntValue());
  7017   } else if (eCSSUnit_Initial == unit ||
  7018              eCSSUnit_Unset == unit) {
  7019     outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_NONE);
  7020   } else if (eCSSUnit_Inherit == unit) {
  7021     canStoreInRuleTree = false;
  7022     outline->SetOutlineStyle(parentOutline->GetOutlineStyle());
  7025   outline->RecalcData(mPresContext);
  7026   COMPUTE_END_RESET(Outline, outline)
  7029 const void*
  7030 nsRuleNode::ComputeListData(void* aStartStruct,
  7031                             const nsRuleData* aRuleData,
  7032                             nsStyleContext* aContext,
  7033                             nsRuleNode* aHighestNode,
  7034                             const RuleDetail aRuleDetail,
  7035                             const bool aCanStoreInRuleTree)
  7037   COMPUTE_START_INHERITED(List, (), list, parentList)
  7039   // list-style-type: enum, inherit, initial
  7040   SetDiscrete(*aRuleData->ValueForListStyleType(),
  7041               list->mListStyleType, canStoreInRuleTree,
  7042               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  7043               parentList->mListStyleType,
  7044               NS_STYLE_LIST_STYLE_DISC, 0, 0, 0, 0);
  7046   // list-style-image: url, none, inherit
  7047   const nsCSSValue* imageValue = aRuleData->ValueForListStyleImage();
  7048   if (eCSSUnit_Image == imageValue->GetUnit()) {
  7049     NS_SET_IMAGE_REQUEST_WITH_DOC(list->SetListStyleImage,
  7050                                   aContext,
  7051                                   imageValue->GetImageValue)
  7053   else if (eCSSUnit_None == imageValue->GetUnit() ||
  7054            eCSSUnit_Initial == imageValue->GetUnit()) {
  7055     list->SetListStyleImage(nullptr);
  7057   else if (eCSSUnit_Inherit == imageValue->GetUnit() ||
  7058            eCSSUnit_Unset == imageValue->GetUnit()) {
  7059     canStoreInRuleTree = false;
  7060     NS_SET_IMAGE_REQUEST(list->SetListStyleImage,
  7061                          aContext,
  7062                          parentList->GetListStyleImage())
  7065   // list-style-position: enum, inherit, initial
  7066   SetDiscrete(*aRuleData->ValueForListStylePosition(),
  7067               list->mListStylePosition, canStoreInRuleTree,
  7068               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  7069               parentList->mListStylePosition,
  7070               NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, 0, 0, 0, 0);
  7072   // image region property: length, auto, inherit
  7073   const nsCSSValue* imageRegionValue = aRuleData->ValueForImageRegion();
  7074   switch (imageRegionValue->GetUnit()) {
  7075   case eCSSUnit_Inherit:
  7076   case eCSSUnit_Unset:
  7077     canStoreInRuleTree = false;
  7078     list->mImageRegion = parentList->mImageRegion;
  7079     break;
  7081   case eCSSUnit_Initial:
  7082   case eCSSUnit_Auto:
  7083     list->mImageRegion.SetRect(0,0,0,0);
  7084     break;
  7086   case eCSSUnit_Null:
  7087     break;
  7089   case eCSSUnit_Rect: {
  7090     const nsCSSRect& rgnRect = imageRegionValue->GetRectValue();
  7092     if (rgnRect.mTop.GetUnit() == eCSSUnit_Auto)
  7093       list->mImageRegion.y = 0;
  7094     else if (rgnRect.mTop.IsLengthUnit())
  7095       list->mImageRegion.y =
  7096         CalcLength(rgnRect.mTop, aContext, mPresContext, canStoreInRuleTree);
  7098     if (rgnRect.mBottom.GetUnit() == eCSSUnit_Auto)
  7099       list->mImageRegion.height = 0;
  7100     else if (rgnRect.mBottom.IsLengthUnit())
  7101       list->mImageRegion.height =
  7102         CalcLength(rgnRect.mBottom, aContext, mPresContext,
  7103                    canStoreInRuleTree) - list->mImageRegion.y;
  7105     if (rgnRect.mLeft.GetUnit() == eCSSUnit_Auto)
  7106       list->mImageRegion.x = 0;
  7107     else if (rgnRect.mLeft.IsLengthUnit())
  7108       list->mImageRegion.x =
  7109         CalcLength(rgnRect.mLeft, aContext, mPresContext, canStoreInRuleTree);
  7111     if (rgnRect.mRight.GetUnit() == eCSSUnit_Auto)
  7112       list->mImageRegion.width = 0;
  7113     else if (rgnRect.mRight.IsLengthUnit())
  7114       list->mImageRegion.width =
  7115         CalcLength(rgnRect.mRight, aContext, mPresContext,
  7116                    canStoreInRuleTree) - list->mImageRegion.x;
  7117     break;
  7120   default:
  7121     NS_ABORT_IF_FALSE(false, "unrecognized image-region unit");
  7124   COMPUTE_END_INHERITED(List, list)
  7127 static void
  7128 SetGridTrackBreadth(const nsCSSValue& aValue,
  7129                     nsStyleCoord& aResult,
  7130                     nsStyleContext* aStyleContext,
  7131                     nsPresContext* aPresContext,
  7132                     bool& aCanStoreInRuleTree)
  7134   nsCSSUnit unit = aValue.GetUnit();
  7135   if (unit == eCSSUnit_FlexFraction) {
  7136     aResult.SetFlexFractionValue(aValue.GetFloatValue());
  7137   } else {
  7138     MOZ_ASSERT(unit != eCSSUnit_Inherit && unit != eCSSUnit_Unset,
  7139                "Unexpected value that would use dummyParentCoord");
  7140     const nsStyleCoord dummyParentCoord;
  7141     SetCoord(aValue, aResult, dummyParentCoord,
  7142              SETCOORD_LPE | SETCOORD_STORE_CALC,
  7143              aStyleContext, aPresContext, aCanStoreInRuleTree);
  7147 static void
  7148 SetGridTrackSize(const nsCSSValue& aValue,
  7149                  nsStyleCoord& aResultMin,
  7150                  nsStyleCoord& aResultMax,
  7151                  nsStyleContext* aStyleContext,
  7152                  nsPresContext* aPresContext,
  7153                  bool& aCanStoreInRuleTree)
  7155   if (aValue.GetUnit() == eCSSUnit_Function) {
  7156     // A minmax() function.
  7157     nsCSSValue::Array* func = aValue.GetArrayValue();
  7158     NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_minmax,
  7159                  "Expected minmax(), got another function name");
  7160     SetGridTrackBreadth(func->Item(1), aResultMin,
  7161                         aStyleContext, aPresContext, aCanStoreInRuleTree);
  7162     SetGridTrackBreadth(func->Item(2), aResultMax,
  7163                         aStyleContext, aPresContext, aCanStoreInRuleTree);
  7164   } else if (aValue.GetUnit() == eCSSUnit_Auto) {
  7165     // 'auto' computes to 'minmax(min-content, max-content)'
  7166     aResultMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
  7167                            eStyleUnit_Enumerated);
  7168     aResultMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
  7169                            eStyleUnit_Enumerated);
  7170   } else {
  7171     // A single <track-breadth>,
  7172     // specifies identical min and max sizing functions.
  7173     SetGridTrackBreadth(aValue, aResultMin,
  7174                         aStyleContext, aPresContext, aCanStoreInRuleTree);
  7175     aResultMax = aResultMin;
  7179 static void
  7180 SetGridAutoColumnsRows(const nsCSSValue& aValue,
  7181                        nsStyleCoord& aResultMin,
  7182                        nsStyleCoord& aResultMax,
  7183                        const nsStyleCoord& aParentValueMin,
  7184                        const nsStyleCoord& aParentValueMax,
  7185                        nsStyleContext* aStyleContext,
  7186                        nsPresContext* aPresContext,
  7187                        bool& aCanStoreInRuleTree)
  7190   switch (aValue.GetUnit()) {
  7191   case eCSSUnit_Null:
  7192     break;
  7194   case eCSSUnit_Inherit:
  7195     aCanStoreInRuleTree = false;
  7196     aResultMin = aParentValueMin;
  7197     aResultMax = aParentValueMax;
  7198     break;
  7200   case eCSSUnit_Initial:
  7201   case eCSSUnit_Unset:
  7202     // The initial value is 'auto',
  7203     // which computes to 'minmax(min-content, max-content)'.
  7204     // (Explicitly-specified 'auto' values are handled in SetGridTrackSize.)
  7205     aResultMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
  7206                            eStyleUnit_Enumerated);
  7207     aResultMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
  7208                            eStyleUnit_Enumerated);
  7209     break;
  7211   default:
  7212     SetGridTrackSize(aValue, aResultMin, aResultMax,
  7213                      aStyleContext, aPresContext, aCanStoreInRuleTree);
  7217 static void
  7218 AppendGridLineNames(const nsCSSValue& aValue,
  7219                     nsStyleGridTemplate& aResult)
  7221   // Compute a <line-names> value
  7222   nsTArray<nsString>* nameList = aResult.mLineNameLists.AppendElement();
  7223   // Null unit means empty list, nothing more to do.
  7224   if (aValue.GetUnit() != eCSSUnit_Null) {
  7225     const nsCSSValueList* item = aValue.GetListValue();
  7226     do {
  7227       nsString* name = nameList->AppendElement();
  7228       item->mValue.GetStringValue(*name);
  7229       item = item->mNext;
  7230     } while (item);
  7234 static void
  7235 SetGridTrackList(const nsCSSValue& aValue,
  7236                  nsStyleGridTemplate& aResult,
  7237                  const nsStyleGridTemplate& aParentValue,
  7238                  nsStyleContext* aStyleContext,
  7239                  nsPresContext* aPresContext,
  7240                  bool& aCanStoreInRuleTree)
  7243   switch (aValue.GetUnit()) {
  7244   case eCSSUnit_Null:
  7245     break;
  7247   case eCSSUnit_Inherit:
  7248     aCanStoreInRuleTree = false;
  7249     aResult.mIsSubgrid = aParentValue.mIsSubgrid;
  7250     aResult.mLineNameLists = aParentValue.mLineNameLists;
  7251     aResult.mMinTrackSizingFunctions = aParentValue.mMinTrackSizingFunctions;
  7252     aResult.mMaxTrackSizingFunctions = aParentValue.mMaxTrackSizingFunctions;
  7253     break;
  7255   case eCSSUnit_Initial:
  7256   case eCSSUnit_Unset:
  7257   case eCSSUnit_None:
  7258     aResult.mIsSubgrid = false;
  7259     aResult.mLineNameLists.Clear();
  7260     aResult.mMinTrackSizingFunctions.Clear();
  7261     aResult.mMaxTrackSizingFunctions.Clear();
  7262     break;
  7264   default:
  7265     aResult.mLineNameLists.Clear();
  7266     aResult.mMinTrackSizingFunctions.Clear();
  7267     aResult.mMaxTrackSizingFunctions.Clear();
  7268     const nsCSSValueList* item = aValue.GetListValue();
  7269     if (item->mValue.GetUnit() == eCSSUnit_Enumerated &&
  7270         item->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) {
  7271       // subgrid <line-name-list>?
  7272       aResult.mIsSubgrid = true;
  7273       item = item->mNext;
  7274       while (item) {
  7275         AppendGridLineNames(item->mValue, aResult);
  7276         item = item->mNext;
  7278     } else {
  7279       // <track-list>
  7280       // The list is expected to have odd number of items, at least 3
  7281       // starting with a <line-names> (sub list of identifiers),
  7282       // and alternating between that and <track-size>.
  7283       aResult.mIsSubgrid = false;
  7284       for (;;) {
  7285         AppendGridLineNames(item->mValue, aResult);
  7286         item = item->mNext;
  7288         if (!item) {
  7289           break;
  7292         nsStyleCoord& min = *aResult.mMinTrackSizingFunctions.AppendElement();
  7293         nsStyleCoord& max = *aResult.mMaxTrackSizingFunctions.AppendElement();
  7294         SetGridTrackSize(item->mValue, min, max,
  7295                          aStyleContext, aPresContext, aCanStoreInRuleTree);
  7297         item = item->mNext;
  7298         MOZ_ASSERT(item, "Expected a eCSSUnit_List of odd length");
  7300       MOZ_ASSERT(!aResult.mMinTrackSizingFunctions.IsEmpty() &&
  7301                  aResult.mMinTrackSizingFunctions.Length() ==
  7302                  aResult.mMaxTrackSizingFunctions.Length() &&
  7303                  aResult.mMinTrackSizingFunctions.Length() + 1 ==
  7304                  aResult.mLineNameLists.Length(),
  7305                  "Inconstistent array lengths for nsStyleGridTemplate");
  7310 static void
  7311 SetGridTemplateAreas(const nsCSSValue& aValue,
  7312                      nsRefPtr<css::GridTemplateAreasValue>* aResult,
  7313                      css::GridTemplateAreasValue* aParentValue,
  7314                      bool& aCanStoreInRuleTree)
  7316   switch (aValue.GetUnit()) {
  7317   case eCSSUnit_Null:
  7318     break;
  7320   case eCSSUnit_Inherit:
  7321     aCanStoreInRuleTree = false;
  7322     *aResult = aParentValue;
  7323     break;
  7325   case eCSSUnit_Initial:
  7326   case eCSSUnit_Unset:
  7327   case eCSSUnit_None:
  7328     *aResult = nullptr;
  7329     break;
  7331   default:
  7332     *aResult = aValue.GetGridTemplateAreas();
  7336 static void
  7337 SetGridLine(const nsCSSValue& aValue,
  7338             nsStyleGridLine& aResult,
  7339             const nsStyleGridLine& aParentValue,
  7340             bool& aCanStoreInRuleTree)
  7343   switch (aValue.GetUnit()) {
  7344   case eCSSUnit_Null:
  7345     break;
  7347   case eCSSUnit_Inherit:
  7348     aCanStoreInRuleTree = false;
  7349     aResult = aParentValue;
  7350     break;
  7352   case eCSSUnit_Initial:
  7353   case eCSSUnit_Unset:
  7354   case eCSSUnit_Auto:
  7355     aResult.SetAuto();
  7356     break;
  7358   default:
  7359     aResult.SetAuto();  // Reset any existing value.
  7360     const nsCSSValueList* item = aValue.GetListValue();
  7361     do {
  7362       if (item->mValue.GetUnit() == eCSSUnit_Enumerated) {
  7363         aResult.mHasSpan = true;
  7364       } else if (item->mValue.GetUnit() == eCSSUnit_Integer) {
  7365         aResult.mInteger = item->mValue.GetIntValue();
  7366       } else if (item->mValue.GetUnit() == eCSSUnit_Ident) {
  7367         item->mValue.GetStringValue(aResult.mLineName);
  7368       } else {
  7369         NS_ASSERTION(false, "Unexpected unit");
  7371       item = item->mNext;
  7372     } while (item);
  7373     MOZ_ASSERT(!aResult.IsAuto(),
  7374                "should have set something away from default value");
  7378 const void*
  7379 nsRuleNode::ComputePositionData(void* aStartStruct,
  7380                                 const nsRuleData* aRuleData,
  7381                                 nsStyleContext* aContext,
  7382                                 nsRuleNode* aHighestNode,
  7383                                 const RuleDetail aRuleDetail,
  7384                                 const bool aCanStoreInRuleTree)
  7386   COMPUTE_START_RESET(Position, (), pos, parentPos)
  7388   // box offsets: length, percent, calc, auto, inherit
  7389   static const nsCSSProperty offsetProps[] = {
  7390     eCSSProperty_top,
  7391     eCSSProperty_right,
  7392     eCSSProperty_bottom,
  7393     eCSSProperty_left
  7394   };
  7395   nsStyleCoord  coord;
  7396   NS_FOR_CSS_SIDES(side) {
  7397     nsStyleCoord parentCoord = parentPos->mOffset.Get(side);
  7398     if (SetCoord(*aRuleData->ValueFor(offsetProps[side]),
  7399                  coord, parentCoord,
  7400                  SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
  7401                    SETCOORD_UNSET_INITIAL,
  7402                  aContext, mPresContext, canStoreInRuleTree)) {
  7403       pos->mOffset.Set(side, coord);
  7407   SetCoord(*aRuleData->ValueForWidth(), pos->mWidth, parentPos->mWidth,
  7408            SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
  7409              SETCOORD_UNSET_INITIAL,
  7410            aContext, mPresContext, canStoreInRuleTree);
  7411   SetCoord(*aRuleData->ValueForMinWidth(), pos->mMinWidth, parentPos->mMinWidth,
  7412            SETCOORD_LPEH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  7413              SETCOORD_UNSET_INITIAL,
  7414            aContext, mPresContext, canStoreInRuleTree);
  7415   SetCoord(*aRuleData->ValueForMaxWidth(), pos->mMaxWidth, parentPos->mMaxWidth,
  7416            SETCOORD_LPOEH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
  7417              SETCOORD_UNSET_INITIAL,
  7418            aContext, mPresContext, canStoreInRuleTree);
  7420   SetCoord(*aRuleData->ValueForHeight(), pos->mHeight, parentPos->mHeight,
  7421            SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
  7422              SETCOORD_UNSET_INITIAL,
  7423            aContext, mPresContext, canStoreInRuleTree);
  7424   SetCoord(*aRuleData->ValueForMinHeight(), pos->mMinHeight, parentPos->mMinHeight,
  7425            SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  7426              SETCOORD_UNSET_INITIAL,
  7427            aContext, mPresContext, canStoreInRuleTree);
  7428   SetCoord(*aRuleData->ValueForMaxHeight(), pos->mMaxHeight, parentPos->mMaxHeight,
  7429            SETCOORD_LPOH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
  7430              SETCOORD_UNSET_INITIAL,
  7431            aContext, mPresContext, canStoreInRuleTree);
  7433   // box-sizing: enum, inherit, initial
  7434   SetDiscrete(*aRuleData->ValueForBoxSizing(),
  7435               pos->mBoxSizing, canStoreInRuleTree,
  7436               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  7437               parentPos->mBoxSizing,
  7438               NS_STYLE_BOX_SIZING_CONTENT, 0, 0, 0, 0);
  7440   // align-content: enum, inherit, initial
  7441   SetDiscrete(*aRuleData->ValueForAlignContent(),
  7442               pos->mAlignContent, canStoreInRuleTree,
  7443               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  7444               parentPos->mAlignContent,
  7445               NS_STYLE_ALIGN_CONTENT_STRETCH, 0, 0, 0, 0);
  7447   // align-items: enum, inherit, initial
  7448   SetDiscrete(*aRuleData->ValueForAlignItems(),
  7449               pos->mAlignItems, canStoreInRuleTree,
  7450               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  7451               parentPos->mAlignItems,
  7452               NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE, 0, 0, 0, 0);
  7454   // align-self: enum, inherit, initial
  7455   // NOTE: align-self's initial value is the special keyword "auto", which is
  7456   // supposed to compute to our parent's computed value of "align-items".  So
  7457   // technically, "auto" itself is never a valid computed value for align-self,
  7458   // since it always computes to something else.  Despite that, we do actually
  7459   // store "auto" in nsStylePosition::mAlignSelf, as NS_STYLE_ALIGN_SELF_AUTO
  7460   // (and then resolve it as-necessary).  We do this because "auto" is the
  7461   // initial value for this property, so if we were to actually resolve it in
  7462   // nsStylePosition, we'd never be able to share any nsStylePosition structs
  7463   // in the rule tree, since their mAlignSelf values would depend on the parent
  7464   // style, by default.
  7465   if (aRuleData->ValueForAlignSelf()->GetUnit() == eCSSUnit_Inherit) {
  7466     // Special handling for "align-self: inherit", in case we're inheriting
  7467     // "align-self: auto", in which case we need to resolve the parent's "auto"
  7468     // and inherit that resolved value.
  7469     uint8_t inheritedAlignSelf = parentPos->mAlignSelf;
  7470     if (inheritedAlignSelf == NS_STYLE_ALIGN_SELF_AUTO) {
  7471       if (!parentContext) {
  7472         // We're the root node. Nothing to inherit from --> just use default
  7473         // value.
  7474         inheritedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
  7475       } else {
  7476         // Our parent's "auto" value should resolve to our grandparent's value
  7477         // for "align-items".  So, that's what we're supposed to inherit.
  7478         nsStyleContext* grandparentContext = parentContext->GetParent();
  7479         if (!grandparentContext) {
  7480           // No grandparent --> our parent is the root node, so its
  7481           // "align-self: auto" computes to the default "align-items" value:
  7482           inheritedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
  7483         } else {
  7484           // Normal case -- we have a grandparent.
  7485           // Its "align-items" value is what we should end up inheriting.
  7486           const nsStylePosition* grandparentPos =
  7487             grandparentContext->StylePosition();
  7488           inheritedAlignSelf = grandparentPos->mAlignItems;
  7493     pos->mAlignSelf = inheritedAlignSelf;
  7494     canStoreInRuleTree = false;
  7495   } else {
  7496     SetDiscrete(*aRuleData->ValueForAlignSelf(),
  7497                 pos->mAlignSelf, canStoreInRuleTree,
  7498                 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  7499                 parentPos->mAlignSelf, // (unused -- we handled inherit above)
  7500                 NS_STYLE_ALIGN_SELF_AUTO, // initial == auto
  7501                 0, 0, 0, 0);
  7504   // flex-basis: auto, length, percent, enum, calc, inherit, initial
  7505   // (Note: The flags here should match those used for 'width' property above.)
  7506   SetCoord(*aRuleData->ValueForFlexBasis(), pos->mFlexBasis, parentPos->mFlexBasis,
  7507            SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
  7508              SETCOORD_UNSET_INITIAL,
  7509            aContext, mPresContext, canStoreInRuleTree);
  7511   // flex-direction: enum, inherit, initial
  7512   SetDiscrete(*aRuleData->ValueForFlexDirection(),
  7513               pos->mFlexDirection, canStoreInRuleTree,
  7514               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  7515               parentPos->mFlexDirection,
  7516               NS_STYLE_FLEX_DIRECTION_ROW, 0, 0, 0, 0);
  7518   // flex-grow: float, inherit, initial
  7519   SetFactor(*aRuleData->ValueForFlexGrow(),
  7520             pos->mFlexGrow, canStoreInRuleTree,
  7521             parentPos->mFlexGrow, 0.0f,
  7522             SETFCT_UNSET_INITIAL);
  7524   // flex-shrink: float, inherit, initial
  7525   SetFactor(*aRuleData->ValueForFlexShrink(),
  7526             pos->mFlexShrink, canStoreInRuleTree,
  7527             parentPos->mFlexShrink, 1.0f,
  7528             SETFCT_UNSET_INITIAL);
  7530   // flex-wrap: enum, inherit, initial
  7531   SetDiscrete(*aRuleData->ValueForFlexWrap(),
  7532               pos->mFlexWrap, canStoreInRuleTree,
  7533               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  7534               parentPos->mFlexWrap,
  7535               NS_STYLE_FLEX_WRAP_NOWRAP, 0, 0, 0, 0);
  7537   // order: integer, inherit, initial
  7538   SetDiscrete(*aRuleData->ValueForOrder(),
  7539               pos->mOrder, canStoreInRuleTree,
  7540               SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
  7541               parentPos->mOrder,
  7542               NS_STYLE_ORDER_INITIAL, 0, 0, 0, 0);
  7544   // justify-content: enum, inherit, initial
  7545   SetDiscrete(*aRuleData->ValueForJustifyContent(),
  7546               pos->mJustifyContent, canStoreInRuleTree,
  7547               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  7548               parentPos->mJustifyContent,
  7549               NS_STYLE_JUSTIFY_CONTENT_FLEX_START, 0, 0, 0, 0);
  7551   // grid-auto-flow
  7552   const nsCSSValue& gridAutoFlow = *aRuleData->ValueForGridAutoFlow();
  7553   switch (gridAutoFlow.GetUnit()) {
  7554     case eCSSUnit_Null:
  7555       break;
  7556     case eCSSUnit_Inherit:
  7557       canStoreInRuleTree = false;
  7558       pos->mGridAutoFlow = parentPos->mGridAutoFlow;
  7559       break;
  7560     case eCSSUnit_Initial:
  7561     case eCSSUnit_Unset:
  7562       pos->mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_NONE;
  7563       break;
  7564     default:
  7565       NS_ASSERTION(gridAutoFlow.GetUnit() == eCSSUnit_Enumerated,
  7566                    "Unexpected unit");
  7567       pos->mGridAutoFlow = gridAutoFlow.GetIntValue();
  7570   // grid-auto-columns
  7571   SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoColumns(),
  7572                          pos->mGridAutoColumnsMin,
  7573                          pos->mGridAutoColumnsMax,
  7574                          parentPos->mGridAutoColumnsMin,
  7575                          parentPos->mGridAutoColumnsMax,
  7576                          aContext, mPresContext, canStoreInRuleTree);
  7578   // grid-auto-rows
  7579   SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoRows(),
  7580                          pos->mGridAutoRowsMin,
  7581                          pos->mGridAutoRowsMax,
  7582                          parentPos->mGridAutoRowsMin,
  7583                          parentPos->mGridAutoRowsMax,
  7584                          aContext, mPresContext, canStoreInRuleTree);
  7586   // grid-template-columns
  7587   SetGridTrackList(*aRuleData->ValueForGridTemplateColumns(),
  7588                    pos->mGridTemplateColumns, parentPos->mGridTemplateColumns,
  7589                    aContext, mPresContext, canStoreInRuleTree);
  7591   // grid-template-rows
  7592   SetGridTrackList(*aRuleData->ValueForGridTemplateRows(),
  7593                    pos->mGridTemplateRows, parentPos->mGridTemplateRows,
  7594                    aContext, mPresContext, canStoreInRuleTree);
  7596   // grid-tempate-areas
  7597   SetGridTemplateAreas(*aRuleData->ValueForGridTemplateAreas(),
  7598                        &pos->mGridTemplateAreas,
  7599                        parentPos->mGridTemplateAreas,
  7600                        canStoreInRuleTree);
  7602   // grid-auto-position
  7603   const nsCSSValue& gridAutoPosition = *aRuleData->ValueForGridAutoPosition();
  7604   switch (gridAutoPosition.GetUnit()) {
  7605     case eCSSUnit_Null:
  7606       break;
  7607     case eCSSUnit_Inherit:
  7608       canStoreInRuleTree = false;
  7609       pos->mGridAutoPositionColumn = parentPos->mGridAutoPositionColumn;
  7610       pos->mGridAutoPositionRow = parentPos->mGridAutoPositionRow;
  7611       break;
  7612     case eCSSUnit_Initial:
  7613     case eCSSUnit_Unset:
  7614       // '1 / 1'
  7615       pos->mGridAutoPositionColumn.SetToInteger(1);
  7616       pos->mGridAutoPositionRow.SetToInteger(1);
  7617       break;
  7618     default:
  7619       SetGridLine(gridAutoPosition.GetPairValue().mXValue,
  7620                   pos->mGridAutoPositionColumn,
  7621                   parentPos->mGridAutoPositionColumn,
  7622                   canStoreInRuleTree);
  7623       SetGridLine(gridAutoPosition.GetPairValue().mYValue,
  7624                   pos->mGridAutoPositionRow,
  7625                   parentPos->mGridAutoPositionRow,
  7626                   canStoreInRuleTree);
  7629   // grid-column-start
  7630   SetGridLine(*aRuleData->ValueForGridColumnStart(),
  7631               pos->mGridColumnStart,
  7632               parentPos->mGridColumnStart,
  7633               canStoreInRuleTree);
  7635   // grid-column-end
  7636   SetGridLine(*aRuleData->ValueForGridColumnEnd(),
  7637               pos->mGridColumnEnd,
  7638               parentPos->mGridColumnEnd,
  7639               canStoreInRuleTree);
  7641   // grid-row-start
  7642   SetGridLine(*aRuleData->ValueForGridRowStart(),
  7643               pos->mGridRowStart,
  7644               parentPos->mGridRowStart,
  7645               canStoreInRuleTree);
  7647   // grid-row-end
  7648   SetGridLine(*aRuleData->ValueForGridRowEnd(),
  7649               pos->mGridRowEnd,
  7650               parentPos->mGridRowEnd,
  7651               canStoreInRuleTree);
  7653   // z-index
  7654   const nsCSSValue* zIndexValue = aRuleData->ValueForZIndex();
  7655   if (! SetCoord(*zIndexValue, pos->mZIndex, parentPos->mZIndex,
  7656                  SETCOORD_IA | SETCOORD_INITIAL_AUTO | SETCOORD_UNSET_INITIAL,
  7657                  aContext, nullptr, canStoreInRuleTree)) {
  7658     if (eCSSUnit_Inherit == zIndexValue->GetUnit()) {
  7659       // handle inherit, because it's ok to inherit 'auto' here
  7660       canStoreInRuleTree = false;
  7661       pos->mZIndex = parentPos->mZIndex;
  7665   COMPUTE_END_RESET(Position, pos)
  7668 const void*
  7669 nsRuleNode::ComputeTableData(void* aStartStruct,
  7670                              const nsRuleData* aRuleData,
  7671                              nsStyleContext* aContext,
  7672                              nsRuleNode* aHighestNode,
  7673                              const RuleDetail aRuleDetail,
  7674                              const bool aCanStoreInRuleTree)
  7676   COMPUTE_START_RESET(Table, (), table, parentTable)
  7678   // table-layout: enum, inherit, initial
  7679   SetDiscrete(*aRuleData->ValueForTableLayout(),
  7680               table->mLayoutStrategy, canStoreInRuleTree,
  7681               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  7682               parentTable->mLayoutStrategy,
  7683               NS_STYLE_TABLE_LAYOUT_AUTO, 0, 0, 0, 0);
  7685   // span: pixels (not a real CSS prop)
  7686   const nsCSSValue* spanValue = aRuleData->ValueForSpan();
  7687   if (eCSSUnit_Enumerated == spanValue->GetUnit() ||
  7688       eCSSUnit_Integer == spanValue->GetUnit())
  7689     table->mSpan = spanValue->GetIntValue();
  7691   COMPUTE_END_RESET(Table, table)
  7694 const void*
  7695 nsRuleNode::ComputeTableBorderData(void* aStartStruct,
  7696                                    const nsRuleData* aRuleData,
  7697                                    nsStyleContext* aContext,
  7698                                    nsRuleNode* aHighestNode,
  7699                                    const RuleDetail aRuleDetail,
  7700                                    const bool aCanStoreInRuleTree)
  7702   COMPUTE_START_INHERITED(TableBorder, (mPresContext), table, parentTable)
  7704   // border-collapse: enum, inherit, initial
  7705   SetDiscrete(*aRuleData->ValueForBorderCollapse(), table->mBorderCollapse,
  7706               canStoreInRuleTree,
  7707               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  7708               parentTable->mBorderCollapse,
  7709               NS_STYLE_BORDER_SEPARATE, 0, 0, 0, 0);
  7711   const nsCSSValue* borderSpacingValue = aRuleData->ValueForBorderSpacing();
  7712   if (borderSpacingValue->GetUnit() != eCSSUnit_Null) {
  7713     // border-spacing-x/y: length, inherit
  7714     nsStyleCoord parentX(parentTable->mBorderSpacingX,
  7715                          nsStyleCoord::CoordConstructor);
  7716     nsStyleCoord parentY(parentTable->mBorderSpacingY,
  7717                          nsStyleCoord::CoordConstructor);
  7718     nsStyleCoord coordX, coordY;
  7720 #ifdef DEBUG
  7721     bool result =
  7722 #endif
  7723       SetPairCoords(*borderSpacingValue,
  7724                     coordX, coordY, parentX, parentY,
  7725                     SETCOORD_LH | SETCOORD_INITIAL_ZERO |
  7726                       SETCOORD_CALC_LENGTH_ONLY |
  7727                       SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INHERIT,
  7728                     aContext, mPresContext, canStoreInRuleTree);
  7729     NS_ASSERTION(result, "malformed table border value");
  7730     table->mBorderSpacingX = coordX.GetCoordValue();
  7731     table->mBorderSpacingY = coordY.GetCoordValue();
  7734   // caption-side: enum, inherit, initial
  7735   SetDiscrete(*aRuleData->ValueForCaptionSide(),
  7736               table->mCaptionSide, canStoreInRuleTree,
  7737               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  7738               parentTable->mCaptionSide,
  7739               NS_STYLE_CAPTION_SIDE_TOP, 0, 0, 0, 0);
  7741   // empty-cells: enum, inherit, initial
  7742   SetDiscrete(*aRuleData->ValueForEmptyCells(),
  7743               table->mEmptyCells, canStoreInRuleTree,
  7744               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  7745               parentTable->mEmptyCells,
  7746               (mPresContext->CompatibilityMode() == eCompatibility_NavQuirks)
  7747               ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
  7748               : NS_STYLE_TABLE_EMPTY_CELLS_SHOW,
  7749               0, 0, 0, 0);
  7751   COMPUTE_END_INHERITED(TableBorder, table)
  7754 const void*
  7755 nsRuleNode::ComputeContentData(void* aStartStruct,
  7756                                const nsRuleData* aRuleData,
  7757                                nsStyleContext* aContext,
  7758                                nsRuleNode* aHighestNode,
  7759                                const RuleDetail aRuleDetail,
  7760                                const bool aCanStoreInRuleTree)
  7762   uint32_t count;
  7763   nsAutoString buffer;
  7765   COMPUTE_START_RESET(Content, (), content, parentContent)
  7767   // content: [string, url, counter, attr, enum]+, normal, none, inherit
  7768   const nsCSSValue* contentValue = aRuleData->ValueForContent();
  7769   switch (contentValue->GetUnit()) {
  7770   case eCSSUnit_Null:
  7771     break;
  7773   case eCSSUnit_Normal:
  7774   case eCSSUnit_None:
  7775   case eCSSUnit_Initial:
  7776   case eCSSUnit_Unset:
  7777     // "normal", "none", "initial" and "unset" all mean no content
  7778     content->AllocateContents(0);
  7779     break;
  7781   case eCSSUnit_Inherit:
  7782     canStoreInRuleTree = false;
  7783     count = parentContent->ContentCount();
  7784     if (NS_SUCCEEDED(content->AllocateContents(count))) {
  7785       while (0 < count--) {
  7786         content->ContentAt(count) = parentContent->ContentAt(count);
  7789     break;
  7791   case eCSSUnit_Enumerated: {
  7792     NS_ABORT_IF_FALSE(contentValue->GetIntValue() ==
  7793                       NS_STYLE_CONTENT_ALT_CONTENT,
  7794                       "unrecognized solitary content keyword");
  7795     content->AllocateContents(1);
  7796     nsStyleContentData& data = content->ContentAt(0);
  7797     data.mType = eStyleContentType_AltContent;
  7798     data.mContent.mString = nullptr;
  7799     break;
  7802   case eCSSUnit_List:
  7803   case eCSSUnit_ListDep: {
  7804     const nsCSSValueList* contentValueList = contentValue->GetListValue();
  7805       count = 0;
  7806       while (contentValueList) {
  7807         count++;
  7808         contentValueList = contentValueList->mNext;
  7810       if (NS_SUCCEEDED(content->AllocateContents(count))) {
  7811         const nsAutoString  nullStr;
  7812         count = 0;
  7813         contentValueList = contentValue->GetListValue();
  7814         while (contentValueList) {
  7815           const nsCSSValue& value = contentValueList->mValue;
  7816           nsCSSUnit unit = value.GetUnit();
  7817           nsStyleContentType type;
  7818           nsStyleContentData &data = content->ContentAt(count++);
  7819           switch (unit) {
  7820           case eCSSUnit_String:   type = eStyleContentType_String;    break;
  7821           case eCSSUnit_Image:    type = eStyleContentType_Image;     break;
  7822           case eCSSUnit_Attr:     type = eStyleContentType_Attr;      break;
  7823           case eCSSUnit_Counter:  type = eStyleContentType_Counter;   break;
  7824           case eCSSUnit_Counters: type = eStyleContentType_Counters;  break;
  7825           case eCSSUnit_Enumerated:
  7826             switch (value.GetIntValue()) {
  7827             case NS_STYLE_CONTENT_OPEN_QUOTE:
  7828               type = eStyleContentType_OpenQuote;     break;
  7829             case NS_STYLE_CONTENT_CLOSE_QUOTE:
  7830               type = eStyleContentType_CloseQuote;    break;
  7831             case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
  7832               type = eStyleContentType_NoOpenQuote;   break;
  7833             case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
  7834               type = eStyleContentType_NoCloseQuote;  break;
  7835             default:
  7836               NS_ERROR("bad content value");
  7837               type = eStyleContentType_Uninitialized;
  7839             break;
  7840           default:
  7841             NS_ERROR("bad content type");
  7842             type = eStyleContentType_Uninitialized;
  7844           data.mType = type;
  7845           if (type == eStyleContentType_Image) {
  7846             NS_SET_IMAGE_REQUEST_WITH_DOC(data.SetImage,
  7847                                           aContext,
  7848                                           value.GetImageValue);
  7850           else if (type <= eStyleContentType_Attr) {
  7851             value.GetStringValue(buffer);
  7852             data.mContent.mString = NS_strdup(buffer.get());
  7854           else if (type <= eStyleContentType_Counters) {
  7855             data.mContent.mCounters = value.GetArrayValue();
  7856             data.mContent.mCounters->AddRef();
  7858           else {
  7859             data.mContent.mString = nullptr;
  7861           contentValueList = contentValueList->mNext;
  7864       break;
  7867   default:
  7868     NS_ABORT_IF_FALSE(false,
  7869                       nsPrintfCString("unrecognized content unit %d",
  7870                                       contentValue->GetUnit()).get());
  7873   // counter-increment: [string [int]]+, none, inherit
  7874   const nsCSSValue* counterIncrementValue =
  7875     aRuleData->ValueForCounterIncrement();
  7876   switch (counterIncrementValue->GetUnit()) {
  7877   case eCSSUnit_Null:
  7878     break;
  7880   case eCSSUnit_None:
  7881   case eCSSUnit_Initial:
  7882   case eCSSUnit_Unset:
  7883     content->AllocateCounterIncrements(0);
  7884     break;
  7886   case eCSSUnit_Inherit:
  7887     canStoreInRuleTree = false;
  7888     count = parentContent->CounterIncrementCount();
  7889     if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
  7890       while (0 < count--) {
  7891         const nsStyleCounterData *data =
  7892           parentContent->GetCounterIncrementAt(count);
  7893         content->SetCounterIncrementAt(count, data->mCounter, data->mValue);
  7896     break;
  7898   case eCSSUnit_PairList:
  7899   case eCSSUnit_PairListDep: {
  7900     const nsCSSValuePairList* ourIncrement =
  7901       counterIncrementValue->GetPairListValue();
  7902     NS_ABORT_IF_FALSE(ourIncrement->mXValue.GetUnit() == eCSSUnit_Ident,
  7903                       "unexpected value unit");
  7904     count = ListLength(ourIncrement);
  7905     if (NS_FAILED(content->AllocateCounterIncrements(count))) {
  7906       break;
  7909     count = 0;
  7910     for (const nsCSSValuePairList* p = ourIncrement; p; p = p->mNext, count++) {
  7911       int32_t increment;
  7912       if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
  7913         increment = p->mYValue.GetIntValue();
  7914       } else {
  7915         increment = 1;
  7917       p->mXValue.GetStringValue(buffer);
  7918       content->SetCounterIncrementAt(count, buffer, increment);
  7920     break;
  7923   default:
  7924     NS_ABORT_IF_FALSE(false, "unexpected value unit");
  7927   // counter-reset: [string [int]]+, none, inherit
  7928   const nsCSSValue* counterResetValue = aRuleData->ValueForCounterReset();
  7929   switch (counterResetValue->GetUnit()) {
  7930   case eCSSUnit_Null:
  7931     break;
  7933   case eCSSUnit_None:
  7934   case eCSSUnit_Initial:
  7935   case eCSSUnit_Unset:
  7936     content->AllocateCounterResets(0);
  7937     break;
  7939   case eCSSUnit_Inherit:
  7940     canStoreInRuleTree = false;
  7941     count = parentContent->CounterResetCount();
  7942     if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
  7943       while (0 < count--) {
  7944         const nsStyleCounterData *data =
  7945           parentContent->GetCounterResetAt(count);
  7946         content->SetCounterResetAt(count, data->mCounter, data->mValue);
  7949     break;
  7951   case eCSSUnit_PairList:
  7952   case eCSSUnit_PairListDep: {
  7953     const nsCSSValuePairList* ourReset =
  7954       counterResetValue->GetPairListValue();
  7955     NS_ABORT_IF_FALSE(ourReset->mXValue.GetUnit() == eCSSUnit_Ident,
  7956                       "unexpected value unit");
  7957     count = ListLength(ourReset);
  7958     if (NS_FAILED(content->AllocateCounterResets(count))) {
  7959       break;
  7962     count = 0;
  7963     for (const nsCSSValuePairList* p = ourReset; p; p = p->mNext, count++) {
  7964       int32_t reset;
  7965       if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
  7966         reset = p->mYValue.GetIntValue();
  7967       } else {
  7968         reset = 0;
  7970       p->mXValue.GetStringValue(buffer);
  7971       content->SetCounterResetAt(count, buffer, reset);
  7973     break;
  7976   default:
  7977     NS_ABORT_IF_FALSE(false, "unexpected value unit");
  7980   // marker-offset: length, auto, inherit
  7981   SetCoord(*aRuleData->ValueForMarkerOffset(), content->mMarkerOffset, parentContent->mMarkerOffset,
  7982            SETCOORD_LH | SETCOORD_AUTO | SETCOORD_INITIAL_AUTO |
  7983              SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INITIAL,
  7984            aContext, mPresContext, canStoreInRuleTree);
  7986   // If we ended up with an image, track it.
  7987   for (uint32_t i = 0; i < content->ContentCount(); ++i) {
  7988     if ((content->ContentAt(i).mType == eStyleContentType_Image) &&
  7989         content->ContentAt(i).mContent.mImage) {
  7990       content->ContentAt(i).TrackImage(aContext->PresContext());
  7994   COMPUTE_END_RESET(Content, content)
  7997 const void*
  7998 nsRuleNode::ComputeQuotesData(void* aStartStruct,
  7999                               const nsRuleData* aRuleData,
  8000                               nsStyleContext* aContext,
  8001                               nsRuleNode* aHighestNode,
  8002                               const RuleDetail aRuleDetail,
  8003                               const bool aCanStoreInRuleTree)
  8005   COMPUTE_START_INHERITED(Quotes, (), quotes, parentQuotes)
  8007   // quotes: inherit, initial, none, [string string]+
  8008   const nsCSSValue* quotesValue = aRuleData->ValueForQuotes();
  8009   switch (quotesValue->GetUnit()) {
  8010   case eCSSUnit_Null:
  8011     break;
  8012   case eCSSUnit_Inherit:
  8013   case eCSSUnit_Unset:
  8014     canStoreInRuleTree = false;
  8015     quotes->CopyFrom(*parentQuotes);
  8016     break;
  8017   case eCSSUnit_Initial:
  8018     quotes->SetInitial();
  8019     break;
  8020   case eCSSUnit_None:
  8021     quotes->AllocateQuotes(0);
  8022     break;
  8023   case eCSSUnit_PairList:
  8024   case eCSSUnit_PairListDep: {
  8025     const nsCSSValuePairList* ourQuotes
  8026       = quotesValue->GetPairListValue();
  8027     nsAutoString buffer;
  8028     nsAutoString closeBuffer;
  8029     uint32_t count = ListLength(ourQuotes);
  8030     if (NS_FAILED(quotes->AllocateQuotes(count))) {
  8031       break;
  8033     count = 0;
  8034     while (ourQuotes) {
  8035       NS_ABORT_IF_FALSE(ourQuotes->mXValue.GetUnit() == eCSSUnit_String &&
  8036                         ourQuotes->mYValue.GetUnit() == eCSSUnit_String,
  8037                         "improper list contents for quotes");
  8038       ourQuotes->mXValue.GetStringValue(buffer);
  8039       ourQuotes->mYValue.GetStringValue(closeBuffer);
  8040       quotes->SetQuotesAt(count++, buffer, closeBuffer);
  8041       ourQuotes = ourQuotes->mNext;
  8043     break;
  8045   default:
  8046     NS_ABORT_IF_FALSE(false, "unexpected value unit");
  8049   COMPUTE_END_INHERITED(Quotes, quotes)
  8052 const void*
  8053 nsRuleNode::ComputeXULData(void* aStartStruct,
  8054                            const nsRuleData* aRuleData,
  8055                            nsStyleContext* aContext,
  8056                            nsRuleNode* aHighestNode,
  8057                            const RuleDetail aRuleDetail,
  8058                            const bool aCanStoreInRuleTree)
  8060   COMPUTE_START_RESET(XUL, (), xul, parentXUL)
  8062   // box-align: enum, inherit, initial
  8063   SetDiscrete(*aRuleData->ValueForBoxAlign(),
  8064               xul->mBoxAlign, canStoreInRuleTree,
  8065               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  8066               parentXUL->mBoxAlign,
  8067               NS_STYLE_BOX_ALIGN_STRETCH, 0, 0, 0, 0);
  8069   // box-direction: enum, inherit, initial
  8070   SetDiscrete(*aRuleData->ValueForBoxDirection(),
  8071               xul->mBoxDirection, canStoreInRuleTree,
  8072               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  8073               parentXUL->mBoxDirection,
  8074               NS_STYLE_BOX_DIRECTION_NORMAL, 0, 0, 0, 0);
  8076   // box-flex: factor, inherit
  8077   SetFactor(*aRuleData->ValueForBoxFlex(),
  8078             xul->mBoxFlex, canStoreInRuleTree,
  8079             parentXUL->mBoxFlex, 0.0f,
  8080             SETFCT_UNSET_INITIAL);
  8082   // box-orient: enum, inherit, initial
  8083   SetDiscrete(*aRuleData->ValueForBoxOrient(),
  8084               xul->mBoxOrient, canStoreInRuleTree,
  8085               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  8086               parentXUL->mBoxOrient,
  8087               NS_STYLE_BOX_ORIENT_HORIZONTAL, 0, 0, 0, 0);
  8089   // box-pack: enum, inherit, initial
  8090   SetDiscrete(*aRuleData->ValueForBoxPack(),
  8091               xul->mBoxPack, canStoreInRuleTree,
  8092               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  8093               parentXUL->mBoxPack,
  8094               NS_STYLE_BOX_PACK_START, 0, 0, 0, 0);
  8096   // box-ordinal-group: integer, inherit, initial
  8097   SetDiscrete(*aRuleData->ValueForBoxOrdinalGroup(),
  8098               xul->mBoxOrdinal, canStoreInRuleTree,
  8099               SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
  8100               parentXUL->mBoxOrdinal, 1,
  8101               0, 0, 0, 0);
  8103   const nsCSSValue* stackSizingValue = aRuleData->ValueForStackSizing();
  8104   if (eCSSUnit_Inherit == stackSizingValue->GetUnit()) {
  8105     canStoreInRuleTree = false;
  8106     xul->mStretchStack = parentXUL->mStretchStack;
  8107   } else if (eCSSUnit_Initial == stackSizingValue->GetUnit() ||
  8108              eCSSUnit_Unset == stackSizingValue->GetUnit()) {
  8109     xul->mStretchStack = true;
  8110   } else if (eCSSUnit_Enumerated == stackSizingValue->GetUnit()) {
  8111     xul->mStretchStack = stackSizingValue->GetIntValue() ==
  8112       NS_STYLE_STACK_SIZING_STRETCH_TO_FIT;
  8115   COMPUTE_END_RESET(XUL, xul)
  8118 const void*
  8119 nsRuleNode::ComputeColumnData(void* aStartStruct,
  8120                               const nsRuleData* aRuleData,
  8121                               nsStyleContext* aContext,
  8122                               nsRuleNode* aHighestNode,
  8123                               const RuleDetail aRuleDetail,
  8124                               const bool aCanStoreInRuleTree)
  8126   COMPUTE_START_RESET(Column, (mPresContext), column, parent)
  8128   // column-width: length, auto, inherit
  8129   SetCoord(*aRuleData->ValueForColumnWidth(),
  8130            column->mColumnWidth, parent->mColumnWidth,
  8131            SETCOORD_LAH | SETCOORD_INITIAL_AUTO |
  8132              SETCOORD_CALC_LENGTH_ONLY | SETCOORD_CALC_CLAMP_NONNEGATIVE |
  8133              SETCOORD_UNSET_INITIAL,
  8134            aContext, mPresContext, canStoreInRuleTree);
  8136   // column-gap: length, inherit, normal
  8137   SetCoord(*aRuleData->ValueForColumnGap(),
  8138            column->mColumnGap, parent->mColumnGap,
  8139            SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
  8140              SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INITIAL,
  8141            aContext, mPresContext, canStoreInRuleTree);
  8142   // clamp negative calc() to 0
  8143   if (column->mColumnGap.GetUnit() == eStyleUnit_Coord) {
  8144     column->mColumnGap.SetCoordValue(
  8145       std::max(column->mColumnGap.GetCoordValue(), 0));
  8148   // column-count: auto, integer, inherit
  8149   const nsCSSValue* columnCountValue = aRuleData->ValueForColumnCount();
  8150   if (eCSSUnit_Auto == columnCountValue->GetUnit() ||
  8151       eCSSUnit_Initial == columnCountValue->GetUnit() ||
  8152       eCSSUnit_Unset == columnCountValue->GetUnit()) {
  8153     column->mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
  8154   } else if (eCSSUnit_Integer == columnCountValue->GetUnit()) {
  8155     column->mColumnCount = columnCountValue->GetIntValue();
  8156     // Max kMaxColumnCount columns - wallpaper for bug 345583.
  8157     column->mColumnCount = std::min(column->mColumnCount,
  8158                                     nsStyleColumn::kMaxColumnCount);
  8159   } else if (eCSSUnit_Inherit == columnCountValue->GetUnit()) {
  8160     canStoreInRuleTree = false;
  8161     column->mColumnCount = parent->mColumnCount;
  8164   // column-rule-width: length, enum, inherit
  8165   const nsCSSValue& widthValue = *aRuleData->ValueForColumnRuleWidth();
  8166   if (eCSSUnit_Initial == widthValue.GetUnit() ||
  8167       eCSSUnit_Unset == widthValue.GetUnit()) {
  8168     column->SetColumnRuleWidth(
  8169         (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
  8171   else if (eCSSUnit_Enumerated == widthValue.GetUnit()) {
  8172     NS_ASSERTION(widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
  8173                  widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
  8174                  widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
  8175                  "Unexpected enum value");
  8176     column->SetColumnRuleWidth(
  8177         (mPresContext->GetBorderWidthTable())[widthValue.GetIntValue()]);
  8179   else if (eCSSUnit_Inherit == widthValue.GetUnit()) {
  8180     column->SetColumnRuleWidth(parent->GetComputedColumnRuleWidth());
  8181     canStoreInRuleTree = false;
  8183   else if (widthValue.IsLengthUnit() || widthValue.IsCalcUnit()) {
  8184     nscoord len =
  8185       CalcLength(widthValue, aContext, mPresContext, canStoreInRuleTree);
  8186     if (len < 0) {
  8187       // FIXME: This is untested (by test_value_storage.html) for
  8188       // column-rule-width since it gets covered up by the border
  8189       // rounding code.
  8190       NS_ASSERTION(widthValue.IsCalcUnit(),
  8191                    "parser should have rejected negative length");
  8192       len = 0;
  8194     column->SetColumnRuleWidth(len);
  8197   // column-rule-style: enum, inherit
  8198   const nsCSSValue& styleValue = *aRuleData->ValueForColumnRuleStyle();
  8199   NS_ABORT_IF_FALSE(eCSSUnit_None != styleValue.GetUnit(),
  8200                     "'none' should be handled as enumerated value");
  8201   if (eCSSUnit_Enumerated == styleValue.GetUnit()) {
  8202     column->mColumnRuleStyle = styleValue.GetIntValue();
  8204   else if (eCSSUnit_Initial == styleValue.GetUnit() ||
  8205            eCSSUnit_Unset == styleValue.GetUnit()) {
  8206     column->mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
  8208   else if (eCSSUnit_Inherit == styleValue.GetUnit()) {
  8209     canStoreInRuleTree = false;
  8210     column->mColumnRuleStyle = parent->mColumnRuleStyle;
  8213   // column-rule-color: color, inherit
  8214   const nsCSSValue& colorValue = *aRuleData->ValueForColumnRuleColor();
  8215   if (eCSSUnit_Inherit == colorValue.GetUnit()) {
  8216     canStoreInRuleTree = false;
  8217     column->mColumnRuleColorIsForeground = false;
  8218     if (parent->mColumnRuleColorIsForeground) {
  8219       if (parentContext) {
  8220         column->mColumnRuleColor = parentContext->StyleColor()->mColor;
  8221       } else {
  8222         nsStyleColor defaultColumnRuleColor(mPresContext);
  8223         column->mColumnRuleColor = defaultColumnRuleColor.mColor;
  8225     } else {
  8226       column->mColumnRuleColor = parent->mColumnRuleColor;
  8229   else if (eCSSUnit_Initial == colorValue.GetUnit() ||
  8230            eCSSUnit_Unset == colorValue.GetUnit() ||
  8231            eCSSUnit_Enumerated == colorValue.GetUnit()) {
  8232     column->mColumnRuleColorIsForeground = true;
  8234   else if (SetColor(colorValue, 0, mPresContext, aContext,
  8235                     column->mColumnRuleColor, canStoreInRuleTree)) {
  8236     column->mColumnRuleColorIsForeground = false;
  8239   // column-fill: enum
  8240   SetDiscrete(*aRuleData->ValueForColumnFill(),
  8241                 column->mColumnFill, canStoreInRuleTree,
  8242                 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  8243                 parent->mColumnFill,
  8244                 NS_STYLE_COLUMN_FILL_BALANCE,
  8245                 0, 0, 0, 0);
  8247   COMPUTE_END_RESET(Column, column)
  8250 static void
  8251 SetSVGPaint(const nsCSSValue& aValue, const nsStyleSVGPaint& parentPaint,
  8252             nsPresContext* aPresContext, nsStyleContext *aContext,
  8253             nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
  8254             bool& aCanStoreInRuleTree)
  8256   nscolor color;
  8258   if (aValue.GetUnit() == eCSSUnit_Inherit ||
  8259       aValue.GetUnit() == eCSSUnit_Unset) {
  8260     aResult = parentPaint;
  8261     aCanStoreInRuleTree = false;
  8262   } else if (aValue.GetUnit() == eCSSUnit_None) {
  8263     aResult.SetType(eStyleSVGPaintType_None);
  8264   } else if (aValue.GetUnit() == eCSSUnit_Initial) {
  8265     aResult.SetType(aInitialPaintType);
  8266     aResult.mPaint.mColor = NS_RGB(0, 0, 0);
  8267     aResult.mFallbackColor = NS_RGB(0, 0, 0);
  8268   } else if (SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aContext,
  8269                       color, aCanStoreInRuleTree)) {
  8270     aResult.SetType(eStyleSVGPaintType_Color);
  8271     aResult.mPaint.mColor = color;
  8272   } else if (aValue.GetUnit() == eCSSUnit_Pair) {
  8273     const nsCSSValuePair& pair = aValue.GetPairValue();
  8275     if (pair.mXValue.GetUnit() == eCSSUnit_URL) {
  8276       aResult.SetType(eStyleSVGPaintType_Server);
  8277       aResult.mPaint.mPaintServer = pair.mXValue.GetURLValue();
  8278       NS_IF_ADDREF(aResult.mPaint.mPaintServer);
  8279     } else if (pair.mXValue.GetUnit() == eCSSUnit_Enumerated) {
  8281       switch (pair.mXValue.GetIntValue()) {
  8282       case NS_COLOR_CONTEXT_FILL:
  8283         aResult.SetType(eStyleSVGPaintType_ContextFill);
  8284         break;
  8285       case NS_COLOR_CONTEXT_STROKE:
  8286         aResult.SetType(eStyleSVGPaintType_ContextStroke);
  8287         break;
  8288       default:
  8289         NS_NOTREACHED("unknown keyword as paint server value");
  8292     } else {
  8293       NS_NOTREACHED("malformed paint server value");
  8296     if (pair.mYValue.GetUnit() == eCSSUnit_None) {
  8297       aResult.mFallbackColor = NS_RGBA(0, 0, 0, 0);
  8298     } else {
  8299       NS_ABORT_IF_FALSE(pair.mYValue.GetUnit() != eCSSUnit_Inherit,
  8300                         "cannot inherit fallback colour");
  8301       SetColor(pair.mYValue, NS_RGB(0, 0, 0), aPresContext, aContext,
  8302                aResult.mFallbackColor, aCanStoreInRuleTree);
  8304   } else {
  8305     NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Null,
  8306                       "malformed paint server value");
  8310 static void
  8311 SetSVGOpacity(const nsCSSValue& aValue,
  8312               float& aOpacityField, nsStyleSVGOpacitySource& aOpacityTypeField,
  8313               bool& aCanStoreInRuleTree,
  8314               float aParentOpacity, nsStyleSVGOpacitySource aParentOpacityType)
  8316   if (eCSSUnit_Enumerated == aValue.GetUnit()) {
  8317     switch (aValue.GetIntValue()) {
  8318     case NS_STYLE_CONTEXT_FILL_OPACITY:
  8319       aOpacityTypeField = eStyleSVGOpacitySource_ContextFillOpacity;
  8320       break;
  8321     case NS_STYLE_CONTEXT_STROKE_OPACITY:
  8322       aOpacityTypeField = eStyleSVGOpacitySource_ContextStrokeOpacity;
  8323       break;
  8324     default:
  8325       NS_NOTREACHED("SetSVGOpacity: Unknown keyword");
  8327     // Fall back on fully opaque
  8328     aOpacityField = 1.0f;
  8329   } else if (eCSSUnit_Inherit == aValue.GetUnit() ||
  8330              eCSSUnit_Unset == aValue.GetUnit()) {
  8331     aCanStoreInRuleTree = false;
  8332     aOpacityField = aParentOpacity;
  8333     aOpacityTypeField = aParentOpacityType;
  8334   } else if (eCSSUnit_Null != aValue.GetUnit()) {
  8335     SetFactor(aValue, aOpacityField, aCanStoreInRuleTree,
  8336               aParentOpacity, 1.0f, SETFCT_OPACITY);
  8337     aOpacityTypeField = eStyleSVGOpacitySource_Normal;
  8341 const void*
  8342 nsRuleNode::ComputeSVGData(void* aStartStruct,
  8343                            const nsRuleData* aRuleData,
  8344                            nsStyleContext* aContext,
  8345                            nsRuleNode* aHighestNode,
  8346                            const RuleDetail aRuleDetail,
  8347                            const bool aCanStoreInRuleTree)
  8349   COMPUTE_START_INHERITED(SVG, (), svg, parentSVG)
  8351   // clip-rule: enum, inherit, initial
  8352   SetDiscrete(*aRuleData->ValueForClipRule(),
  8353               svg->mClipRule, canStoreInRuleTree,
  8354               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  8355               parentSVG->mClipRule,
  8356               NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
  8358   // color-interpolation: enum, inherit, initial
  8359   SetDiscrete(*aRuleData->ValueForColorInterpolation(),
  8360               svg->mColorInterpolation, canStoreInRuleTree,
  8361               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  8362               parentSVG->mColorInterpolation,
  8363               NS_STYLE_COLOR_INTERPOLATION_SRGB, 0, 0, 0, 0);
  8365   // color-interpolation-filters: enum, inherit, initial
  8366   SetDiscrete(*aRuleData->ValueForColorInterpolationFilters(),
  8367               svg->mColorInterpolationFilters, canStoreInRuleTree,
  8368               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  8369               parentSVG->mColorInterpolationFilters,
  8370               NS_STYLE_COLOR_INTERPOLATION_LINEARRGB, 0, 0, 0, 0);
  8372   // fill:
  8373   SetSVGPaint(*aRuleData->ValueForFill(),
  8374               parentSVG->mFill, mPresContext, aContext,
  8375               svg->mFill, eStyleSVGPaintType_Color, canStoreInRuleTree);
  8377   // fill-opacity: factor, inherit, initial,
  8378   // context-fill-opacity, context-stroke-opacity
  8379   nsStyleSVGOpacitySource contextFillOpacity = svg->mFillOpacitySource;
  8380   SetSVGOpacity(*aRuleData->ValueForFillOpacity(),
  8381                 svg->mFillOpacity, contextFillOpacity, canStoreInRuleTree,
  8382                 parentSVG->mFillOpacity, parentSVG->mFillOpacitySource);
  8383   svg->mFillOpacitySource = contextFillOpacity;
  8385   // fill-rule: enum, inherit, initial
  8386   SetDiscrete(*aRuleData->ValueForFillRule(),
  8387               svg->mFillRule, canStoreInRuleTree,
  8388               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  8389               parentSVG->mFillRule,
  8390               NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
  8392   // image-rendering: enum, inherit
  8393   SetDiscrete(*aRuleData->ValueForImageRendering(),
  8394               svg->mImageRendering, canStoreInRuleTree,
  8395               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  8396               parentSVG->mImageRendering,
  8397               NS_STYLE_IMAGE_RENDERING_AUTO, 0, 0, 0, 0);
  8399   // marker-end: url, none, inherit
  8400   const nsCSSValue* markerEndValue = aRuleData->ValueForMarkerEnd();
  8401   if (eCSSUnit_URL == markerEndValue->GetUnit()) {
  8402     svg->mMarkerEnd = markerEndValue->GetURLValue();
  8403   } else if (eCSSUnit_None == markerEndValue->GetUnit() ||
  8404              eCSSUnit_Initial == markerEndValue->GetUnit()) {
  8405     svg->mMarkerEnd = nullptr;
  8406   } else if (eCSSUnit_Inherit == markerEndValue->GetUnit() ||
  8407              eCSSUnit_Unset == markerEndValue->GetUnit()) {
  8408     canStoreInRuleTree = false;
  8409     svg->mMarkerEnd = parentSVG->mMarkerEnd;
  8412   // marker-mid: url, none, inherit
  8413   const nsCSSValue* markerMidValue = aRuleData->ValueForMarkerMid();
  8414   if (eCSSUnit_URL == markerMidValue->GetUnit()) {
  8415     svg->mMarkerMid = markerMidValue->GetURLValue();
  8416   } else if (eCSSUnit_None == markerMidValue->GetUnit() ||
  8417              eCSSUnit_Initial == markerMidValue->GetUnit()) {
  8418     svg->mMarkerMid = nullptr;
  8419   } else if (eCSSUnit_Inherit == markerMidValue->GetUnit() ||
  8420              eCSSUnit_Unset == markerMidValue->GetUnit()) {
  8421     canStoreInRuleTree = false;
  8422     svg->mMarkerMid = parentSVG->mMarkerMid;
  8425   // marker-start: url, none, inherit
  8426   const nsCSSValue* markerStartValue = aRuleData->ValueForMarkerStart();
  8427   if (eCSSUnit_URL == markerStartValue->GetUnit()) {
  8428     svg->mMarkerStart = markerStartValue->GetURLValue();
  8429   } else if (eCSSUnit_None == markerStartValue->GetUnit() ||
  8430              eCSSUnit_Initial == markerStartValue->GetUnit()) {
  8431     svg->mMarkerStart = nullptr;
  8432   } else if (eCSSUnit_Inherit == markerStartValue->GetUnit() ||
  8433              eCSSUnit_Unset == markerStartValue->GetUnit()) {
  8434     canStoreInRuleTree = false;
  8435     svg->mMarkerStart = parentSVG->mMarkerStart;
  8438   // paint-order: enum (bit field), inherit, initial
  8439   const nsCSSValue* paintOrderValue = aRuleData->ValueForPaintOrder();
  8440   switch (paintOrderValue->GetUnit()) {
  8441     case eCSSUnit_Null:
  8442       break;
  8444     case eCSSUnit_Enumerated:
  8445       static_assert
  8446         (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <= 8,
  8447          "SVGStyleStruct::mPaintOrder not big enough");
  8448       svg->mPaintOrder = static_cast<uint8_t>(paintOrderValue->GetIntValue());
  8449       break;
  8451     case eCSSUnit_Inherit:
  8452     case eCSSUnit_Unset:
  8453       canStoreInRuleTree = false;
  8454       svg->mPaintOrder = parentSVG->mPaintOrder;
  8455       break;
  8457     case eCSSUnit_Initial:
  8458       svg->mPaintOrder = NS_STYLE_PAINT_ORDER_NORMAL;
  8459       break;
  8461     default:
  8462       NS_NOTREACHED("unexpected unit");
  8465   // shape-rendering: enum, inherit
  8466   SetDiscrete(*aRuleData->ValueForShapeRendering(),
  8467               svg->mShapeRendering, canStoreInRuleTree,
  8468               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  8469               parentSVG->mShapeRendering,
  8470               NS_STYLE_SHAPE_RENDERING_AUTO, 0, 0, 0, 0);
  8472   // stroke:
  8473   SetSVGPaint(*aRuleData->ValueForStroke(),
  8474               parentSVG->mStroke, mPresContext, aContext,
  8475               svg->mStroke, eStyleSVGPaintType_None, canStoreInRuleTree);
  8477   // stroke-dasharray: <dasharray>, none, inherit, context-value
  8478   const nsCSSValue* strokeDasharrayValue = aRuleData->ValueForStrokeDasharray();
  8479   switch (strokeDasharrayValue->GetUnit()) {
  8480   case eCSSUnit_Null:
  8481     break;
  8483   case eCSSUnit_Inherit:
  8484   case eCSSUnit_Unset:
  8485     canStoreInRuleTree = false;
  8486     svg->mStrokeDasharrayFromObject = parentSVG->mStrokeDasharrayFromObject;
  8487     // only do the copy if weren't already set up by the copy constructor
  8488     // FIXME Bug 389408: This is broken when aStartStruct is non-null!
  8489     if (!svg->mStrokeDasharray) {
  8490       svg->mStrokeDasharrayLength = parentSVG->mStrokeDasharrayLength;
  8491       if (svg->mStrokeDasharrayLength) {
  8492         svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
  8493         if (svg->mStrokeDasharray)
  8494           memcpy(svg->mStrokeDasharray,
  8495                  parentSVG->mStrokeDasharray,
  8496                  svg->mStrokeDasharrayLength * sizeof(nsStyleCoord));
  8497         else
  8498           svg->mStrokeDasharrayLength = 0;
  8501     break;
  8503   case eCSSUnit_Enumerated:
  8504     NS_ABORT_IF_FALSE(strokeDasharrayValue->GetIntValue() ==
  8505                             NS_STYLE_STROKE_PROP_CONTEXT_VALUE,
  8506                       "Unknown keyword for stroke-dasharray");
  8507     svg->mStrokeDasharrayFromObject = true;
  8508     delete [] svg->mStrokeDasharray;
  8509     svg->mStrokeDasharray = nullptr;
  8510     svg->mStrokeDasharrayLength = 0;
  8511     break;
  8513   case eCSSUnit_Initial:
  8514   case eCSSUnit_None:
  8515     svg->mStrokeDasharrayFromObject = false;
  8516     delete [] svg->mStrokeDasharray;
  8517     svg->mStrokeDasharray = nullptr;
  8518     svg->mStrokeDasharrayLength = 0;
  8519     break;
  8521   case eCSSUnit_List:
  8522   case eCSSUnit_ListDep: {
  8523     svg->mStrokeDasharrayFromObject = false;
  8524     delete [] svg->mStrokeDasharray;
  8525     svg->mStrokeDasharray = nullptr;
  8526     svg->mStrokeDasharrayLength = 0;
  8528     // count number of values
  8529     const nsCSSValueList *value = strokeDasharrayValue->GetListValue();
  8530     svg->mStrokeDasharrayLength = ListLength(value);
  8532     NS_ASSERTION(svg->mStrokeDasharrayLength != 0, "no dasharray items");
  8534     svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
  8536     if (svg->mStrokeDasharray) {
  8537       uint32_t i = 0;
  8538       while (nullptr != value) {
  8539         SetCoord(value->mValue,
  8540                  svg->mStrokeDasharray[i++], nsStyleCoord(),
  8541                  SETCOORD_LP | SETCOORD_FACTOR,
  8542                  aContext, mPresContext, canStoreInRuleTree);
  8543         value = value->mNext;
  8545     } else {
  8546       svg->mStrokeDasharrayLength = 0;
  8548     break;
  8551   default:
  8552     NS_ABORT_IF_FALSE(false, "unrecognized dasharray unit");
  8555   // stroke-dashoffset: <dashoffset>, inherit
  8556   const nsCSSValue *strokeDashoffsetValue =
  8557     aRuleData->ValueForStrokeDashoffset();
  8558   svg->mStrokeDashoffsetFromObject =
  8559     strokeDashoffsetValue->GetUnit() == eCSSUnit_Enumerated &&
  8560     strokeDashoffsetValue->GetIntValue() == NS_STYLE_STROKE_PROP_CONTEXT_VALUE;
  8561   if (svg->mStrokeDashoffsetFromObject) {
  8562     svg->mStrokeDashoffset.SetCoordValue(0);
  8563   } else {
  8564     SetCoord(*aRuleData->ValueForStrokeDashoffset(),
  8565              svg->mStrokeDashoffset, parentSVG->mStrokeDashoffset,
  8566              SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_INITIAL_ZERO |
  8567                SETCOORD_UNSET_INHERIT,
  8568              aContext, mPresContext, canStoreInRuleTree);
  8571   // stroke-linecap: enum, inherit, initial
  8572   SetDiscrete(*aRuleData->ValueForStrokeLinecap(),
  8573               svg->mStrokeLinecap, canStoreInRuleTree,
  8574               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  8575               parentSVG->mStrokeLinecap,
  8576               NS_STYLE_STROKE_LINECAP_BUTT, 0, 0, 0, 0);
  8578   // stroke-linejoin: enum, inherit, initial
  8579   SetDiscrete(*aRuleData->ValueForStrokeLinejoin(),
  8580               svg->mStrokeLinejoin, canStoreInRuleTree,
  8581               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  8582               parentSVG->mStrokeLinejoin,
  8583               NS_STYLE_STROKE_LINEJOIN_MITER, 0, 0, 0, 0);
  8585   // stroke-miterlimit: <miterlimit>, inherit
  8586   SetFactor(*aRuleData->ValueForStrokeMiterlimit(),
  8587             svg->mStrokeMiterlimit,
  8588             canStoreInRuleTree,
  8589             parentSVG->mStrokeMiterlimit, 4.0f,
  8590             SETFCT_UNSET_INHERIT);
  8592   // stroke-opacity:
  8593   nsStyleSVGOpacitySource contextStrokeOpacity = svg->mStrokeOpacitySource;
  8594   SetSVGOpacity(*aRuleData->ValueForStrokeOpacity(),
  8595                 svg->mStrokeOpacity, contextStrokeOpacity, canStoreInRuleTree,
  8596                 parentSVG->mStrokeOpacity, parentSVG->mStrokeOpacitySource);
  8597   svg->mStrokeOpacitySource = contextStrokeOpacity;
  8599   // stroke-width:
  8600   const nsCSSValue* strokeWidthValue = aRuleData->ValueForStrokeWidth();
  8601   switch (strokeWidthValue->GetUnit()) {
  8602   case eCSSUnit_Enumerated:
  8603     NS_ABORT_IF_FALSE(strokeWidthValue->GetIntValue() ==
  8604                         NS_STYLE_STROKE_PROP_CONTEXT_VALUE,
  8605                       "Unrecognized keyword for stroke-width");
  8606     svg->mStrokeWidthFromObject = true;
  8607     svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
  8608     break;
  8610   case eCSSUnit_Initial:
  8611     svg->mStrokeWidthFromObject = false;
  8612     svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
  8613     break;
  8615   default:
  8616     svg->mStrokeWidthFromObject = false;
  8617     SetCoord(*strokeWidthValue,
  8618              svg->mStrokeWidth, parentSVG->mStrokeWidth,
  8619              SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_UNSET_INHERIT,
  8620              aContext, mPresContext, canStoreInRuleTree);
  8623   // text-anchor: enum, inherit, initial
  8624   SetDiscrete(*aRuleData->ValueForTextAnchor(),
  8625               svg->mTextAnchor, canStoreInRuleTree,
  8626               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  8627               parentSVG->mTextAnchor,
  8628               NS_STYLE_TEXT_ANCHOR_START, 0, 0, 0, 0);
  8630   // text-rendering: enum, inherit, initial
  8631   SetDiscrete(*aRuleData->ValueForTextRendering(),
  8632               svg->mTextRendering, canStoreInRuleTree,
  8633               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  8634               parentSVG->mTextRendering,
  8635               NS_STYLE_TEXT_RENDERING_AUTO, 0, 0, 0, 0);
  8637   COMPUTE_END_INHERITED(SVG, svg)
  8640 // Returns true if the nsStyleFilter was successfully set using the nsCSSValue.
  8641 bool
  8642 nsRuleNode::SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
  8643                                      const nsCSSValue& aValue,
  8644                                      nsStyleContext* aStyleContext,
  8645                                      nsPresContext* aPresContext,
  8646                                      bool& aCanStoreInRuleTree)
  8648   nsCSSUnit unit = aValue.GetUnit();
  8649   if (unit == eCSSUnit_URL) {
  8650     nsIURI* url = aValue.GetURLValue();
  8651     if (!url)
  8652       return false;
  8653     aStyleFilter->SetURL(url);
  8654     return true;
  8657   NS_ABORT_IF_FALSE(unit == eCSSUnit_Function, "expected a filter function");
  8659   nsCSSValue::Array* filterFunction = aValue.GetArrayValue();
  8660   nsCSSKeyword functionName =
  8661     (nsCSSKeyword)filterFunction->Item(0).GetIntValue();
  8663   int32_t type;
  8664   DebugOnly<bool> foundKeyword =
  8665     nsCSSProps::FindKeyword(functionName,
  8666                             nsCSSProps::kFilterFunctionKTable,
  8667                             type);
  8668   NS_ABORT_IF_FALSE(foundKeyword, "unknown filter type");
  8669   if (type == NS_STYLE_FILTER_DROP_SHADOW) {
  8670     nsRefPtr<nsCSSShadowArray> shadowArray = GetShadowData(
  8671       filterFunction->Item(1).GetListValue(),
  8672       aStyleContext,
  8673       false,
  8674       aCanStoreInRuleTree);
  8675     aStyleFilter->SetDropShadow(shadowArray);
  8676     return true;
  8679   int32_t mask = SETCOORD_PERCENT | SETCOORD_FACTOR;
  8680   if (type == NS_STYLE_FILTER_BLUR) {
  8681     mask = SETCOORD_LENGTH | SETCOORD_STORE_CALC;
  8682   } else if (type == NS_STYLE_FILTER_HUE_ROTATE) {
  8683     mask = SETCOORD_ANGLE;
  8686   NS_ABORT_IF_FALSE(filterFunction->Count() == 2,
  8687                     "all filter functions should have "
  8688                     "exactly one argument");
  8690   nsCSSValue& arg = filterFunction->Item(1);
  8691   nsStyleCoord filterParameter;
  8692   DebugOnly<bool> didSetCoord = SetCoord(arg, filterParameter,
  8693                                          nsStyleCoord(), mask,
  8694                                          aStyleContext, aPresContext,
  8695                                          aCanStoreInRuleTree);
  8696   aStyleFilter->SetFilterParameter(filterParameter, type);
  8697   NS_ABORT_IF_FALSE(didSetCoord, "unexpected unit");
  8698   return true;
  8701 const void*
  8702 nsRuleNode::ComputeSVGResetData(void* aStartStruct,
  8703                                 const nsRuleData* aRuleData,
  8704                                 nsStyleContext* aContext,
  8705                                 nsRuleNode* aHighestNode,
  8706                                 const RuleDetail aRuleDetail,
  8707                                 const bool aCanStoreInRuleTree)
  8709   COMPUTE_START_RESET(SVGReset, (), svgReset, parentSVGReset)
  8711   // stop-color:
  8712   const nsCSSValue* stopColorValue = aRuleData->ValueForStopColor();
  8713   if (eCSSUnit_Initial == stopColorValue->GetUnit() ||
  8714       eCSSUnit_Unset == stopColorValue->GetUnit()) {
  8715     svgReset->mStopColor = NS_RGB(0, 0, 0);
  8716   } else {
  8717     SetColor(*stopColorValue, parentSVGReset->mStopColor,
  8718              mPresContext, aContext, svgReset->mStopColor, canStoreInRuleTree);
  8721   // flood-color:
  8722   const nsCSSValue* floodColorValue = aRuleData->ValueForFloodColor();
  8723   if (eCSSUnit_Initial == floodColorValue->GetUnit() ||
  8724       eCSSUnit_Unset == floodColorValue->GetUnit()) {
  8725     svgReset->mFloodColor = NS_RGB(0, 0, 0);
  8726   } else {
  8727     SetColor(*floodColorValue, parentSVGReset->mFloodColor,
  8728              mPresContext, aContext, svgReset->mFloodColor, canStoreInRuleTree);
  8731   // lighting-color:
  8732   const nsCSSValue* lightingColorValue = aRuleData->ValueForLightingColor();
  8733   if (eCSSUnit_Initial == lightingColorValue->GetUnit() ||
  8734       eCSSUnit_Unset == lightingColorValue->GetUnit()) {
  8735     svgReset->mLightingColor = NS_RGB(255, 255, 255);
  8736   } else {
  8737     SetColor(*lightingColorValue, parentSVGReset->mLightingColor,
  8738              mPresContext, aContext, svgReset->mLightingColor,
  8739              canStoreInRuleTree);
  8742   // clip-path: url, none, inherit
  8743   const nsCSSValue* clipPathValue = aRuleData->ValueForClipPath();
  8744   if (eCSSUnit_URL == clipPathValue->GetUnit()) {
  8745     svgReset->mClipPath = clipPathValue->GetURLValue();
  8746   } else if (eCSSUnit_None == clipPathValue->GetUnit() ||
  8747              eCSSUnit_Initial == clipPathValue->GetUnit() ||
  8748              eCSSUnit_Unset == clipPathValue->GetUnit()) {
  8749     svgReset->mClipPath = nullptr;
  8750   } else if (eCSSUnit_Inherit == clipPathValue->GetUnit()) {
  8751     canStoreInRuleTree = false;
  8752     svgReset->mClipPath = parentSVGReset->mClipPath;
  8755   // stop-opacity:
  8756   SetFactor(*aRuleData->ValueForStopOpacity(),
  8757             svgReset->mStopOpacity, canStoreInRuleTree,
  8758             parentSVGReset->mStopOpacity, 1.0f,
  8759             SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
  8761   // flood-opacity:
  8762   SetFactor(*aRuleData->ValueForFloodOpacity(),
  8763             svgReset->mFloodOpacity, canStoreInRuleTree,
  8764             parentSVGReset->mFloodOpacity, 1.0f,
  8765             SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
  8767   // dominant-baseline: enum, inherit, initial
  8768   SetDiscrete(*aRuleData->ValueForDominantBaseline(),
  8769               svgReset->mDominantBaseline,
  8770               canStoreInRuleTree,
  8771               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  8772               parentSVGReset->mDominantBaseline,
  8773               NS_STYLE_DOMINANT_BASELINE_AUTO, 0, 0, 0, 0);
  8775   // vector-effect: enum, inherit, initial
  8776   SetDiscrete(*aRuleData->ValueForVectorEffect(),
  8777               svgReset->mVectorEffect,
  8778               canStoreInRuleTree,
  8779               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  8780               parentSVGReset->mVectorEffect,
  8781               NS_STYLE_VECTOR_EFFECT_NONE, 0, 0, 0, 0);
  8783   // filter: url, none, inherit
  8784   const nsCSSValue* filterValue = aRuleData->ValueForFilter();
  8785   switch (filterValue->GetUnit()) {
  8786     case eCSSUnit_Null:
  8787       break;
  8788     case eCSSUnit_None:
  8789     case eCSSUnit_Initial:
  8790     case eCSSUnit_Unset:
  8791       svgReset->mFilters.Clear();
  8792       break;
  8793     case eCSSUnit_Inherit:
  8794       canStoreInRuleTree = false;
  8795       svgReset->mFilters = parentSVGReset->mFilters;
  8796       break;
  8797     case eCSSUnit_List:
  8798     case eCSSUnit_ListDep: {
  8799       svgReset->mFilters.Clear();
  8800       const nsCSSValueList* cur = filterValue->GetListValue();
  8801       while (cur) {
  8802         nsStyleFilter styleFilter;
  8803         if (!SetStyleFilterToCSSValue(&styleFilter, cur->mValue, aContext,
  8804                                       mPresContext, canStoreInRuleTree)) {
  8805           svgReset->mFilters.Clear();
  8806           break;
  8808         NS_ABORT_IF_FALSE(styleFilter.GetType() != NS_STYLE_FILTER_NONE,
  8809                           "filter should be set");
  8810         svgReset->mFilters.AppendElement(styleFilter);
  8811         cur = cur->mNext;
  8813       break;
  8815     default:
  8816       NS_NOTREACHED("unexpected unit");
  8819   // mask: url, none, inherit
  8820   const nsCSSValue* maskValue = aRuleData->ValueForMask();
  8821   if (eCSSUnit_URL == maskValue->GetUnit()) {
  8822     svgReset->mMask = maskValue->GetURLValue();
  8823   } else if (eCSSUnit_None == maskValue->GetUnit() ||
  8824              eCSSUnit_Initial == maskValue->GetUnit() ||
  8825              eCSSUnit_Unset == maskValue->GetUnit()) {
  8826     svgReset->mMask = nullptr;
  8827   } else if (eCSSUnit_Inherit == maskValue->GetUnit()) {
  8828     canStoreInRuleTree = false;
  8829     svgReset->mMask = parentSVGReset->mMask;
  8832   // mask-type: enum, inherit, initial
  8833   SetDiscrete(*aRuleData->ValueForMaskType(),
  8834               svgReset->mMaskType,
  8835               canStoreInRuleTree,
  8836               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  8837               parentSVGReset->mMaskType,
  8838               NS_STYLE_MASK_TYPE_LUMINANCE, 0, 0, 0, 0);
  8840   COMPUTE_END_RESET(SVGReset, svgReset)
  8843 const void*
  8844 nsRuleNode::ComputeVariablesData(void* aStartStruct,
  8845                                  const nsRuleData* aRuleData,
  8846                                  nsStyleContext* aContext,
  8847                                  nsRuleNode* aHighestNode,
  8848                                  const RuleDetail aRuleDetail,
  8849                                  const bool aCanStoreInRuleTree)
  8851   COMPUTE_START_INHERITED(Variables, (), variables, parentVariables)
  8853   MOZ_ASSERT(aRuleData->mVariables,
  8854              "shouldn't be in ComputeVariablesData if there were no variable "
  8855              "declarations specified");
  8857   CSSVariableResolver resolver(&variables->mVariables);
  8858   resolver.Resolve(&parentVariables->mVariables,
  8859                    aRuleData->mVariables);
  8860   canStoreInRuleTree = false;
  8862   COMPUTE_END_INHERITED(Variables, variables)
  8865 const void*
  8866 nsRuleNode::GetStyleData(nsStyleStructID aSID,
  8867                          nsStyleContext* aContext,
  8868                          bool aComputeData)
  8870   NS_ASSERTION(IsUsedDirectly(),
  8871                "if we ever call this on rule nodes that aren't used "
  8872                "directly, we should adjust handling of mDependentBits "
  8873                "in some way.");
  8875   const void *data;
  8876   data = mStyleData.GetStyleData(aSID);
  8877   if (MOZ_LIKELY(data != nullptr))
  8878     return data; // We have a fully specified struct. Just return it.
  8880   if (MOZ_UNLIKELY(!aComputeData))
  8881     return nullptr;
  8883   // Nothing is cached.  We'll have to delve further and examine our rules.
  8884   data = WalkRuleTree(aSID, aContext);
  8886   NS_ABORT_IF_FALSE(data, "should have aborted on out-of-memory");
  8887   return data;
  8890 // See comments above in GetStyleData for an explanation of what the
  8891 // code below does.
  8892 #define STYLE_STRUCT(name_, checkdata_cb_)                                    \
  8893 const nsStyle##name_*                                                         \
  8894 nsRuleNode::GetStyle##name_(nsStyleContext* aContext, bool aComputeData)      \
  8895 {                                                                             \
  8896   NS_ASSERTION(IsUsedDirectly(),                                              \
  8897                "if we ever call this on rule nodes that aren't used "         \
  8898                "directly, we should adjust handling of mDependentBits "       \
  8899                "in some way.");                                               \
  8901   const nsStyle##name_ *data;                                                 \
  8902   data = mStyleData.GetStyle##name_();                                        \
  8903   if (MOZ_LIKELY(data != nullptr))                                            \
  8904     return data;                                                              \
  8906   if (MOZ_UNLIKELY(!aComputeData))                                            \
  8907     return nullptr;                                                           \
  8909   data = static_cast<const nsStyle##name_ *>                                  \
  8910            (WalkRuleTree(eStyleStruct_##name_, aContext));                    \
  8912   NS_ABORT_IF_FALSE(data, "should have aborted on out-of-memory");            \
  8913   return data;                                                                \
  8915 #include "nsStyleStructList.h"
  8916 #undef STYLE_STRUCT
  8918 void
  8919 nsRuleNode::Mark()
  8921   for (nsRuleNode *node = this;
  8922        node && !(node->mDependentBits & NS_RULE_NODE_GC_MARK);
  8923        node = node->mParent)
  8924     node->mDependentBits |= NS_RULE_NODE_GC_MARK;
  8927 static PLDHashOperator
  8928 SweepRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
  8929                       uint32_t number, void *arg)
  8931   ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
  8932   if (entry->mRuleNode->Sweep())
  8933     return PL_DHASH_REMOVE; // implies NEXT, unless |ed with STOP
  8934   return PL_DHASH_NEXT;
  8937 bool
  8938 nsRuleNode::Sweep()
  8940   // If we're not marked, then we have to delete ourself.
  8941   // However, we never allow the root node to GC itself, because nsStyleSet
  8942   // wants to hold onto the root node and not worry about re-creating a
  8943   // rule walker if the root node is deleted.
  8944   if (!(mDependentBits & NS_RULE_NODE_GC_MARK) &&
  8945       // Skip this only if we're the *current* root and not an old one.
  8946       !(IsRoot() && mPresContext->StyleSet()->GetRuleTree() == this)) {
  8947     Destroy();
  8948     return true;
  8951   // Clear our mark, for the next time around.
  8952   mDependentBits &= ~NS_RULE_NODE_GC_MARK;
  8954   // Call sweep on the children, since some may not be marked, and
  8955   // remove any deleted children from the child lists.
  8956   if (HaveChildren()) {
  8957     uint32_t childrenDestroyed;
  8958     if (ChildrenAreHashed()) {
  8959       PLDHashTable *children = ChildrenHash();
  8960       uint32_t oldChildCount = children->entryCount;
  8961       PL_DHashTableEnumerate(children, SweepRuleNodeChildren, nullptr);
  8962       childrenDestroyed = children->entryCount - oldChildCount;
  8963     } else {
  8964       childrenDestroyed = 0;
  8965       for (nsRuleNode **children = ChildrenListPtr(); *children; ) {
  8966         nsRuleNode *next = (*children)->mNextSibling;
  8967         if ((*children)->Sweep()) {
  8968           // This rule node was destroyed, so implicitly advance by
  8969           // making *children point to the next entry.
  8970           *children = next;
  8971           ++childrenDestroyed;
  8972         } else {
  8973           // Advance.
  8974           children = &(*children)->mNextSibling;
  8978     mRefCnt -= childrenDestroyed;
  8979     NS_POSTCONDITION(IsRoot() || mRefCnt > 0,
  8980                      "We didn't get swept, so we'd better have style contexts "
  8981                      "pointing to us or to one of our descendants, which means "
  8982                      "we'd better have a nonzero mRefCnt here!");
  8984   return false;
  8987 /* static */ bool
  8988 nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
  8989                                     uint32_t ruleTypeMask,
  8990                                     bool aAuthorColorsAllowed)
  8992   uint32_t inheritBits = 0;
  8993   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND)
  8994     inheritBits |= NS_STYLE_INHERIT_BIT(Background);
  8996   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER)
  8997     inheritBits |= NS_STYLE_INHERIT_BIT(Border);
  8999   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING)
  9000     inheritBits |= NS_STYLE_INHERIT_BIT(Padding);
  9002   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW)
  9003     inheritBits |= NS_STYLE_INHERIT_BIT(Text);
  9005   // properties in the SIDS, whether or not we care about them
  9006   size_t nprops = 0,
  9007          backgroundOffset, borderOffset, paddingOffset, textShadowOffset;
  9009   // We put the reset properties the start of the nsCSSValue array....
  9011   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
  9012     backgroundOffset = nprops;
  9013     nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Background);
  9016   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
  9017     borderOffset = nprops;
  9018     nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Border);
  9021   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
  9022     paddingOffset = nprops;
  9023     nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Padding);
  9026   // ...and the inherited properties at the end of the array.
  9027   size_t inheritedOffset = nprops;
  9029   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
  9030     textShadowOffset = nprops;
  9031     nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Text);
  9034   void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
  9035   AutoCSSValueArray dataArray(dataStorage, nprops);
  9037   /* We're relying on the use of |aStyleContext| not mutating it! */
  9038   nsRuleData ruleData(inheritBits, dataArray.get(),
  9039                       aStyleContext->PresContext(), aStyleContext);
  9041   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
  9042     ruleData.mValueOffsets[eStyleStruct_Background] = backgroundOffset;
  9045   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
  9046     ruleData.mValueOffsets[eStyleStruct_Border] = borderOffset;
  9049   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
  9050     ruleData.mValueOffsets[eStyleStruct_Padding] = paddingOffset;
  9053   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
  9054     ruleData.mValueOffsets[eStyleStruct_Text] = textShadowOffset;
  9057   static const nsCSSProperty backgroundValues[] = {
  9058     eCSSProperty_background_color,
  9059     eCSSProperty_background_image,
  9060   };
  9062   static const nsCSSProperty borderValues[] = {
  9063     eCSSProperty_border_top_color,
  9064     eCSSProperty_border_top_style,
  9065     eCSSProperty_border_top_width,
  9066     eCSSProperty_border_right_color_value,
  9067     eCSSProperty_border_right_style_value,
  9068     eCSSProperty_border_right_width_value,
  9069     eCSSProperty_border_bottom_color,
  9070     eCSSProperty_border_bottom_style,
  9071     eCSSProperty_border_bottom_width,
  9072     eCSSProperty_border_left_color_value,
  9073     eCSSProperty_border_left_style_value,
  9074     eCSSProperty_border_left_width_value,
  9075     eCSSProperty_border_start_color_value,
  9076     eCSSProperty_border_start_style_value,
  9077     eCSSProperty_border_start_width_value,
  9078     eCSSProperty_border_end_color_value,
  9079     eCSSProperty_border_end_style_value,
  9080     eCSSProperty_border_end_width_value,
  9081     eCSSProperty_border_top_left_radius,
  9082     eCSSProperty_border_top_right_radius,
  9083     eCSSProperty_border_bottom_right_radius,
  9084     eCSSProperty_border_bottom_left_radius,
  9085   };
  9087   static const nsCSSProperty paddingValues[] = {
  9088     eCSSProperty_padding_top,
  9089     eCSSProperty_padding_right_value,
  9090     eCSSProperty_padding_bottom,
  9091     eCSSProperty_padding_left_value,
  9092     eCSSProperty_padding_start_value,
  9093     eCSSProperty_padding_end_value,
  9094   };
  9096   static const nsCSSProperty textShadowValues[] = {
  9097     eCSSProperty_text_shadow
  9098   };
  9100   // Number of properties we care about
  9101   size_t nValues = 0;
  9103   nsCSSValue* values[MOZ_ARRAY_LENGTH(backgroundValues) +
  9104                      MOZ_ARRAY_LENGTH(borderValues) +
  9105                      MOZ_ARRAY_LENGTH(paddingValues) +
  9106                      MOZ_ARRAY_LENGTH(textShadowValues)];
  9108   nsCSSProperty properties[MOZ_ARRAY_LENGTH(backgroundValues) +
  9109                            MOZ_ARRAY_LENGTH(borderValues) +
  9110                            MOZ_ARRAY_LENGTH(paddingValues) +
  9111                            MOZ_ARRAY_LENGTH(textShadowValues)];
  9113   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
  9114     for (uint32_t i = 0, i_end = ArrayLength(backgroundValues);
  9115          i < i_end; ++i) {
  9116       properties[nValues] = backgroundValues[i];
  9117       values[nValues++] = ruleData.ValueFor(backgroundValues[i]);
  9121   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
  9122     for (uint32_t i = 0, i_end = ArrayLength(borderValues);
  9123          i < i_end; ++i) {
  9124       properties[nValues] = borderValues[i];
  9125       values[nValues++] = ruleData.ValueFor(borderValues[i]);
  9129   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
  9130     for (uint32_t i = 0, i_end = ArrayLength(paddingValues);
  9131          i < i_end; ++i) {
  9132       properties[nValues] = paddingValues[i];
  9133       values[nValues++] = ruleData.ValueFor(paddingValues[i]);
  9137   if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
  9138     for (uint32_t i = 0, i_end = ArrayLength(textShadowValues);
  9139          i < i_end; ++i) {
  9140       properties[nValues] = textShadowValues[i];
  9141       values[nValues++] = ruleData.ValueFor(textShadowValues[i]);
  9145   nsStyleContext* styleContext = aStyleContext;
  9147   // We need to be careful not to count styles covered up by user-important or
  9148   // UA-important declarations.  But we do want to catch explicit inherit
  9149   // styling in those and check our parent style context to see whether we have
  9150   // user styling for those properties.  Note that we don't care here about
  9151   // inheritance due to lack of a specified value, since all the properties we
  9152   // care about are reset properties.
  9153   bool haveExplicitUAInherit;
  9154   do {
  9155     haveExplicitUAInherit = false;
  9156     for (nsRuleNode* ruleNode = styleContext->RuleNode(); ruleNode;
  9157          ruleNode = ruleNode->GetParent()) {
  9158       nsIStyleRule *rule = ruleNode->GetRule();
  9159       if (rule) {
  9160         ruleData.mLevel = ruleNode->GetLevel();
  9161         ruleData.mIsImportantRule = ruleNode->IsImportantRule();
  9163         rule->MapRuleInfoInto(&ruleData);
  9165         if (ruleData.mLevel == nsStyleSet::eAgentSheet ||
  9166             ruleData.mLevel == nsStyleSet::eUserSheet) {
  9167           // This is a rule whose effect we want to ignore, so if any of
  9168           // the properties we care about were set, set them to the dummy
  9169           // value that they'll never otherwise get.
  9170           for (uint32_t i = 0; i < nValues; ++i) {
  9171             nsCSSUnit unit = values[i]->GetUnit();
  9172             if (unit != eCSSUnit_Null &&
  9173                 unit != eCSSUnit_Dummy &&
  9174                 unit != eCSSUnit_DummyInherit) {
  9175               if (unit == eCSSUnit_Inherit ||
  9176                   (i >= inheritedOffset && unit == eCSSUnit_Unset)) {
  9177                 haveExplicitUAInherit = true;
  9178                 values[i]->SetDummyInheritValue();
  9179               } else {
  9180                 values[i]->SetDummyValue();
  9184         } else {
  9185           // If any of the values we care about was set by the above rule,
  9186           // we have author style.
  9187           for (uint32_t i = 0; i < nValues; ++i) {
  9188             if (values[i]->GetUnit() != eCSSUnit_Null &&
  9189                 values[i]->GetUnit() != eCSSUnit_Dummy && // see above
  9190                 values[i]->GetUnit() != eCSSUnit_DummyInherit) {
  9191               // If author colors are not allowed, only claim to have
  9192               // author-specified rules if we're looking at a non-color
  9193               // property or if we're looking at the background color and it's
  9194               // set to transparent.  Anything else should get set to a dummy
  9195               // value instead.
  9196               if (aAuthorColorsAllowed ||
  9197                   !nsCSSProps::PropHasFlags(properties[i],
  9198                      CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED) ||
  9199                   (properties[i] == eCSSProperty_background_color &&
  9200                    !values[i]->IsNonTransparentColor())) {
  9201                 return true;
  9204               values[i]->SetDummyValue();
  9211     if (haveExplicitUAInherit) {
  9212       // reset all the eCSSUnit_Null values to eCSSUnit_Dummy (since they're
  9213       // not styled by the author, or by anyone else), and then reset all the
  9214       // eCSSUnit_DummyInherit values to eCSSUnit_Null (so we will be able to
  9215       // detect them being styled by the author) and move up to our parent
  9216       // style context.
  9217       for (uint32_t i = 0; i < nValues; ++i)
  9218         if (values[i]->GetUnit() == eCSSUnit_Null)
  9219           values[i]->SetDummyValue();
  9220       for (uint32_t i = 0; i < nValues; ++i)
  9221         if (values[i]->GetUnit() == eCSSUnit_DummyInherit)
  9222           values[i]->Reset();
  9223       styleContext = styleContext->GetParent();
  9225   } while (haveExplicitUAInherit && styleContext);
  9227   return false;
  9230 /* static */
  9231 bool
  9232 nsRuleNode::ComputeColor(const nsCSSValue& aValue, nsPresContext* aPresContext,
  9233                          nsStyleContext* aStyleContext, nscolor& aResult)
  9235   MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Inherit,
  9236              "aValue shouldn't have eCSSUnit_Inherit");
  9237   MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Initial,
  9238              "aValue shouldn't have eCSSUnit_Initial");
  9239   MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Unset,
  9240              "aValue shouldn't have eCSSUnit_Unset");
  9242   bool canStoreInRuleTree;
  9243   bool ok = SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aStyleContext,
  9244                      aResult, canStoreInRuleTree);
  9245   MOZ_ASSERT(ok || !(aPresContext && aStyleContext));
  9246   return ok;

mercurial