layout/style/nsRuleNode.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/style/nsRuleNode.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,9247 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=78: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/*
    1.11 + * a node in the lexicographic tree of rules that match an element,
    1.12 + * responsible for converting the rules' information into computed style
    1.13 + */
    1.14 +
    1.15 +#include <algorithm>
    1.16 +
    1.17 +#include "mozilla/ArrayUtils.h"
    1.18 +#include "mozilla/Assertions.h"
    1.19 +#include "mozilla/DebugOnly.h"
    1.20 +#include "mozilla/Likely.h"
    1.21 +#include "mozilla/LookAndFeel.h"
    1.22 +
    1.23 +#include "nsRuleNode.h"
    1.24 +#include "nscore.h"
    1.25 +#include "nsIWidget.h"
    1.26 +#include "nsIPresShell.h"
    1.27 +#include "nsFontMetrics.h"
    1.28 +#include "gfxFont.h"
    1.29 +#include "nsCSSPseudoElements.h"
    1.30 +#include "nsThemeConstants.h"
    1.31 +#include "pldhash.h"
    1.32 +#include "nsStyleContext.h"
    1.33 +#include "nsStyleSet.h"
    1.34 +#include "nsStyleStruct.h"
    1.35 +#include "nsSize.h"
    1.36 +#include "nsRuleData.h"
    1.37 +#include "gfxUserFontSet.h"
    1.38 +#include "nsIStyleRule.h"
    1.39 +#include "nsBidiUtils.h"
    1.40 +#include "nsStyleStructInlines.h"
    1.41 +#include "nsCSSProps.h"
    1.42 +#include "nsTArray.h"
    1.43 +#include "nsContentUtils.h"
    1.44 +#include "CSSCalc.h"
    1.45 +#include "nsPrintfCString.h"
    1.46 +#include "nsRenderingContext.h"
    1.47 +#include "nsStyleUtil.h"
    1.48 +#include "nsIDocument.h"
    1.49 +#include "prtime.h"
    1.50 +#include "CSSVariableResolver.h"
    1.51 +#include "nsCSSParser.h"
    1.52 +
    1.53 +#if defined(_MSC_VER) || defined(__MINGW32__)
    1.54 +#include <malloc.h>
    1.55 +#ifdef _MSC_VER
    1.56 +#define alloca _alloca
    1.57 +#endif
    1.58 +#endif
    1.59 +#ifdef SOLARIS
    1.60 +#include <alloca.h>
    1.61 +#endif
    1.62 +
    1.63 +using std::max;
    1.64 +using std::min;
    1.65 +using namespace mozilla;
    1.66 +using namespace mozilla::dom;
    1.67 +
    1.68 +#define NS_SET_IMAGE_REQUEST(method_, context_, request_)                   \
    1.69 +  if ((context_)->PresContext()->IsDynamic()) {                               \
    1.70 +    method_(request_);                                                      \
    1.71 +  } else {                                                                  \
    1.72 +    nsRefPtr<imgRequestProxy> req = nsContentUtils::GetStaticRequest(request_); \
    1.73 +    method_(req);                                                           \
    1.74 +  }
    1.75 +
    1.76 +#define NS_SET_IMAGE_REQUEST_WITH_DOC(method_, context_, requestgetter_)      \
    1.77 +  {                                                                           \
    1.78 +    nsIDocument* doc = (context_)->PresContext()->Document();                 \
    1.79 +    NS_SET_IMAGE_REQUEST(method_, context_, requestgetter_(doc))              \
    1.80 +  }
    1.81 +
    1.82 +/*
    1.83 + * For storage of an |nsRuleNode|'s children in a PLDHashTable.
    1.84 + */
    1.85 +
    1.86 +struct ChildrenHashEntry : public PLDHashEntryHdr {
    1.87 +  // key is |mRuleNode->GetKey()|
    1.88 +  nsRuleNode *mRuleNode;
    1.89 +};
    1.90 +
    1.91 +/* static */ PLDHashNumber
    1.92 +nsRuleNode::ChildrenHashHashKey(PLDHashTable *aTable, const void *aKey)
    1.93 +{
    1.94 +  const nsRuleNode::Key *key =
    1.95 +    static_cast<const nsRuleNode::Key*>(aKey);
    1.96 +  // Disagreement on importance and level for the same rule is extremely
    1.97 +  // rare, so hash just on the rule.
    1.98 +  return PL_DHashVoidPtrKeyStub(aTable, key->mRule);
    1.99 +}
   1.100 +
   1.101 +/* static */ bool
   1.102 +nsRuleNode::ChildrenHashMatchEntry(PLDHashTable *aTable,
   1.103 +                                   const PLDHashEntryHdr *aHdr,
   1.104 +                                   const void *aKey)
   1.105 +{
   1.106 +  const ChildrenHashEntry *entry =
   1.107 +    static_cast<const ChildrenHashEntry*>(aHdr);
   1.108 +  const nsRuleNode::Key *key =
   1.109 +    static_cast<const nsRuleNode::Key*>(aKey);
   1.110 +  return entry->mRuleNode->GetKey() == *key;
   1.111 +}
   1.112 +
   1.113 +/* static */ const PLDHashTableOps
   1.114 +nsRuleNode::ChildrenHashOps = {
   1.115 +  // It's probably better to allocate the table itself using malloc and
   1.116 +  // free rather than the pres shell's arena because the table doesn't
   1.117 +  // grow very often and the pres shell's arena doesn't recycle very
   1.118 +  // large size allocations.
   1.119 +  PL_DHashAllocTable,
   1.120 +  PL_DHashFreeTable,
   1.121 +  ChildrenHashHashKey,
   1.122 +  ChildrenHashMatchEntry,
   1.123 +  PL_DHashMoveEntryStub,
   1.124 +  PL_DHashClearEntryStub,
   1.125 +  PL_DHashFinalizeStub,
   1.126 +  nullptr
   1.127 +};
   1.128 +
   1.129 +
   1.130 +// EnsureBlockDisplay:
   1.131 +//  - if the display value (argument) is not a block-type
   1.132 +//    then we set it to a valid block display value
   1.133 +//  - For enforcing the floated/positioned element CSS2 rules
   1.134 +//  - We allow the behavior of "list-item" to be customized.
   1.135 +//    CSS21 says that position/float do not convert 'list-item' to 'block',
   1.136 +//    but it explicitly does not define whether 'list-item' should be
   1.137 +//    converted to block *on the root node*. To allow for flexibility
   1.138 +//    (so that we don't have to support a list-item root node), this method
   1.139 +//    lets the caller pick either behavior, using the 'aConvertListItem' arg.
   1.140 +//    Reference: http://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo
   1.141 +/* static */
   1.142 +void
   1.143 +nsRuleNode::EnsureBlockDisplay(uint8_t& display,
   1.144 +                               bool aConvertListItem /* = false */)
   1.145 +{
   1.146 +  // see if the display value is already a block
   1.147 +  switch (display) {
   1.148 +  case NS_STYLE_DISPLAY_LIST_ITEM :
   1.149 +    if (aConvertListItem) {
   1.150 +      display = NS_STYLE_DISPLAY_BLOCK;
   1.151 +      break;
   1.152 +    } // else, fall through to share the 'break' for non-changing display vals
   1.153 +  case NS_STYLE_DISPLAY_NONE :
   1.154 +    // never change display:none *ever*
   1.155 +  case NS_STYLE_DISPLAY_TABLE :
   1.156 +  case NS_STYLE_DISPLAY_BLOCK :
   1.157 +  case NS_STYLE_DISPLAY_FLEX :
   1.158 +  case NS_STYLE_DISPLAY_GRID :
   1.159 +    // do not muck with these at all - already blocks
   1.160 +    // This is equivalent to nsStyleDisplay::IsBlockOutside.  (XXX Maybe we
   1.161 +    // should just call that?)
   1.162 +    // This needs to match the check done in
   1.163 +    // nsCSSFrameConstructor::FindMathMLData for <math>.
   1.164 +    break;
   1.165 +
   1.166 +  case NS_STYLE_DISPLAY_INLINE_TABLE :
   1.167 +    // make inline tables into tables
   1.168 +    display = NS_STYLE_DISPLAY_TABLE;
   1.169 +    break;
   1.170 +
   1.171 +  case NS_STYLE_DISPLAY_INLINE_FLEX:
   1.172 +    // make inline flex containers into flex containers
   1.173 +    display = NS_STYLE_DISPLAY_FLEX;
   1.174 +    break;
   1.175 +
   1.176 +  case NS_STYLE_DISPLAY_INLINE_GRID:
   1.177 +    // make inline grid containers into grid containers
   1.178 +    display = NS_STYLE_DISPLAY_GRID;
   1.179 +    break;
   1.180 +
   1.181 +  default :
   1.182 +    // make it a block
   1.183 +    display = NS_STYLE_DISPLAY_BLOCK;
   1.184 +  }
   1.185 +}
   1.186 +
   1.187 +static nscoord CalcLengthWith(const nsCSSValue& aValue,
   1.188 +                              nscoord aFontSize,
   1.189 +                              const nsStyleFont* aStyleFont,
   1.190 +                              nsStyleContext* aStyleContext,
   1.191 +                              nsPresContext* aPresContext,
   1.192 +                              bool aUseProvidedRootEmSize,
   1.193 +                              bool aUseUserFontSet,
   1.194 +                              bool& aCanStoreInRuleTree);
   1.195 +
   1.196 +struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
   1.197 +                           public css::NumbersAlreadyNormalizedOps
   1.198 +{
   1.199 +  // All of the parameters to CalcLengthWith except aValue.
   1.200 +  const nscoord mFontSize;
   1.201 +  const nsStyleFont* const mStyleFont;
   1.202 +  nsStyleContext* const mStyleContext;
   1.203 +  nsPresContext* const mPresContext;
   1.204 +  const bool mUseProvidedRootEmSize;
   1.205 +  const bool mUseUserFontSet;
   1.206 +  bool& mCanStoreInRuleTree;
   1.207 +
   1.208 +  CalcLengthCalcOps(nscoord aFontSize, const nsStyleFont* aStyleFont,
   1.209 +                    nsStyleContext* aStyleContext, nsPresContext* aPresContext,
   1.210 +                    bool aUseProvidedRootEmSize, bool aUseUserFontSet,
   1.211 +                    bool& aCanStoreInRuleTree)
   1.212 +    : mFontSize(aFontSize),
   1.213 +      mStyleFont(aStyleFont),
   1.214 +      mStyleContext(aStyleContext),
   1.215 +      mPresContext(aPresContext),
   1.216 +      mUseProvidedRootEmSize(aUseProvidedRootEmSize),
   1.217 +      mUseUserFontSet(aUseUserFontSet),
   1.218 +      mCanStoreInRuleTree(aCanStoreInRuleTree)
   1.219 +  {
   1.220 +  }
   1.221 +
   1.222 +  result_type ComputeLeafValue(const nsCSSValue& aValue)
   1.223 +  {
   1.224 +    return CalcLengthWith(aValue, mFontSize, mStyleFont,
   1.225 +                          mStyleContext, mPresContext, mUseProvidedRootEmSize,
   1.226 +                          mUseUserFontSet, mCanStoreInRuleTree);
   1.227 +  }
   1.228 +};
   1.229 +
   1.230 +static inline nscoord ScaleCoord(const nsCSSValue &aValue, float factor)
   1.231 +{
   1.232 +  return NSToCoordRoundWithClamp(aValue.GetFloatValue() * factor);
   1.233 +}
   1.234 +
   1.235 +already_AddRefed<nsFontMetrics>
   1.236 +GetMetricsFor(nsPresContext* aPresContext,
   1.237 +              nsStyleContext* aStyleContext,
   1.238 +              const nsStyleFont* aStyleFont,
   1.239 +              nscoord aFontSize, // overrides value from aStyleFont
   1.240 +              bool aUseUserFontSet)
   1.241 +{
   1.242 +  nsFont font = aStyleFont->mFont;
   1.243 +  font.size = aFontSize;
   1.244 +  gfxUserFontSet *fs = nullptr;
   1.245 +  if (aUseUserFontSet) {
   1.246 +    fs = aPresContext->GetUserFontSet();
   1.247 +  }
   1.248 +  gfxTextPerfMetrics *tp = aPresContext->GetTextPerfMetrics();
   1.249 +  nsRefPtr<nsFontMetrics> fm;
   1.250 +  aPresContext->DeviceContext()->GetMetricsFor(font,
   1.251 +                                               aStyleFont->mLanguage,
   1.252 +                                               fs, tp, *getter_AddRefs(fm));
   1.253 +  return fm.forget();
   1.254 +}
   1.255 +
   1.256 +
   1.257 +static nsSize CalcViewportUnitsScale(nsPresContext* aPresContext)
   1.258 +{
   1.259 +  // The caller is making use of viewport units, so notify the pres context
   1.260 +  // that it will need to rebuild the rule tree if the size of the viewport
   1.261 +  // changes.
   1.262 +  aPresContext->SetUsesViewportUnits(true);
   1.263 +
   1.264 +  // The default (when we have 'overflow: auto' on the root element, or
   1.265 +  // trivially for 'overflow: hidden' since we never have scrollbars in that
   1.266 +  // case) is to define the scale of the viewport units without considering
   1.267 +  // scrollbars.
   1.268 +  nsSize viewportSize(aPresContext->GetVisibleArea().Size());
   1.269 +
   1.270 +  // Check for 'overflow: scroll' styles on the root scroll frame. If we find
   1.271 +  // any, the standard requires us to take scrollbars into account.
   1.272 +  nsIScrollableFrame* scrollFrame =
   1.273 +    aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
   1.274 +  if (scrollFrame) {
   1.275 +    ScrollbarStyles styles(scrollFrame->GetScrollbarStyles());
   1.276 +
   1.277 +    if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL ||
   1.278 +        styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
   1.279 +      // Gather scrollbar size information.
   1.280 +      nsRefPtr<nsRenderingContext> context =
   1.281 +        aPresContext->PresShell()->CreateReferenceRenderingContext();
   1.282 +      nsMargin sizes(scrollFrame->GetDesiredScrollbarSizes(aPresContext, context));
   1.283 +
   1.284 +      if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
   1.285 +        // 'overflow-x: scroll' means we must consider the horizontal scrollbar,
   1.286 +        // which affects the scale of viewport height units.
   1.287 +        viewportSize.height -= sizes.TopBottom();
   1.288 +      }
   1.289 +
   1.290 +      if (styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
   1.291 +        // 'overflow-y: scroll' means we must consider the vertical scrollbar,
   1.292 +        // which affects the scale of viewport width units.
   1.293 +        viewportSize.width -= sizes.LeftRight();
   1.294 +      }
   1.295 +    }
   1.296 +  }
   1.297 +
   1.298 +  return viewportSize;
   1.299 +}
   1.300 +
   1.301 +static nscoord CalcLengthWith(const nsCSSValue& aValue,
   1.302 +                              nscoord aFontSize,
   1.303 +                              const nsStyleFont* aStyleFont,
   1.304 +                              nsStyleContext* aStyleContext,
   1.305 +                              nsPresContext* aPresContext,
   1.306 +                              bool aUseProvidedRootEmSize,
   1.307 +                              // aUseUserFontSet should always be true
   1.308 +                              // except when called from
   1.309 +                              // CalcLengthWithInitialFont.
   1.310 +                              bool aUseUserFontSet,
   1.311 +                              bool& aCanStoreInRuleTree)
   1.312 +{
   1.313 +  NS_ASSERTION(aValue.IsLengthUnit() || aValue.IsCalcUnit(),
   1.314 +               "not a length or calc unit");
   1.315 +  NS_ASSERTION(aStyleFont || aStyleContext,
   1.316 +               "Must have style data");
   1.317 +  NS_ASSERTION(!aStyleFont || !aStyleContext,
   1.318 +               "Duplicate sources of data");
   1.319 +  NS_ASSERTION(aPresContext, "Must have prescontext");
   1.320 +
   1.321 +  if (aValue.IsFixedLengthUnit()) {
   1.322 +    return aValue.GetFixedLength(aPresContext);
   1.323 +  }
   1.324 +  if (aValue.IsPixelLengthUnit()) {
   1.325 +    return aValue.GetPixelLength();
   1.326 +  }
   1.327 +  if (aValue.IsCalcUnit()) {
   1.328 +    // For properties for which lengths are the *only* units accepted in
   1.329 +    // calc(), we can handle calc() here and just compute a final
   1.330 +    // result.  We ensure that we don't get to this code for other
   1.331 +    // properties by not calling CalcLength in those cases:  SetCoord
   1.332 +    // only calls CalcLength for a calc when it is appropriate to do so.
   1.333 +    CalcLengthCalcOps ops(aFontSize, aStyleFont,
   1.334 +                          aStyleContext, aPresContext,
   1.335 +                          aUseProvidedRootEmSize, aUseUserFontSet,
   1.336 +                          aCanStoreInRuleTree);
   1.337 +    return css::ComputeCalc(aValue, ops);
   1.338 +  }
   1.339 +  switch (aValue.GetUnit()) {
   1.340 +    // nsPresContext::SetVisibleArea and
   1.341 +    // nsPresContext::MediaFeatureValuesChanged handle dynamic changes
   1.342 +    // of the basis for viewport units by rebuilding the rule tree and
   1.343 +    // style context tree.  Not caching them in the rule tree wouldn't
   1.344 +    // be sufficient to handle these changes because we also need a way
   1.345 +    // to get rid of cached values in the style context tree without any
   1.346 +    // changes in specified style.  We can either do this by not caching
   1.347 +    // in the rule tree and then throwing away the style context tree
   1.348 +    // for dynamic viewport size changes, or by allowing caching in the
   1.349 +    // rule tree and using the existing rebuild style data path that
   1.350 +    // throws away the style context and the rule tree.
   1.351 +    // Thus we do cache viewport units in the rule tree.  This allows us
   1.352 +    // to benefit from the performance advantages of the rule tree
   1.353 +    // (e.g., faster dynamic changes on other things, like transforms)
   1.354 +    // and allows us not to need an additional code path, in exchange
   1.355 +    // for an increased cost to dynamic changes to the viewport size
   1.356 +    // when viewport units are in use.
   1.357 +    case eCSSUnit_ViewportWidth: {
   1.358 +      return ScaleCoord(aValue, 0.01f * CalcViewportUnitsScale(aPresContext).width);
   1.359 +    }
   1.360 +    case eCSSUnit_ViewportHeight: {
   1.361 +      return ScaleCoord(aValue, 0.01f * CalcViewportUnitsScale(aPresContext).height);
   1.362 +    }
   1.363 +    case eCSSUnit_ViewportMin: {
   1.364 +      nsSize vuScale(CalcViewportUnitsScale(aPresContext));
   1.365 +      return ScaleCoord(aValue, 0.01f * min(vuScale.width, vuScale.height));
   1.366 +    }
   1.367 +    case eCSSUnit_ViewportMax: {
   1.368 +      nsSize vuScale(CalcViewportUnitsScale(aPresContext));
   1.369 +      return ScaleCoord(aValue, 0.01f * max(vuScale.width, vuScale.height));
   1.370 +    }
   1.371 +    // While we could deal with 'rem' units correctly by simply not
   1.372 +    // caching any data that uses them in the rule tree, it's valuable
   1.373 +    // to store them in the rule tree (for faster dynamic changes of
   1.374 +    // other things).  And since the font size of the root element
   1.375 +    // changes rarely, we instead handle dynamic changes to the root
   1.376 +    // element's font size by rebuilding all style data in
   1.377 +    // nsCSSFrameConstructor::RestyleElement.
   1.378 +    case eCSSUnit_RootEM: {
   1.379 +      aPresContext->SetUsesRootEMUnits(true);
   1.380 +      nscoord rootFontSize;
   1.381 +
   1.382 +      // NOTE: Be very careful with |styleFont|, since we haven't set
   1.383 +      // aCanStoreInRuleTree to false yet, so we don't want to introduce
   1.384 +      // any dependencies on aStyleContext's data here.
   1.385 +      const nsStyleFont *styleFont =
   1.386 +        aStyleFont ? aStyleFont : aStyleContext->StyleFont();
   1.387 +
   1.388 +      if (aUseProvidedRootEmSize) {
   1.389 +        // We should use the provided aFontSize as the reference length to
   1.390 +        // scale. This only happens when we are calculating font-size or
   1.391 +        // an equivalent (scriptminsize or CalcLengthWithInitialFont) on
   1.392 +        // the root element, in which case aFontSize is already the
   1.393 +        // value we want.
   1.394 +        if (aFontSize == -1) {
   1.395 +          // XXX Should this be styleFont->mSize instead to avoid taking
   1.396 +          // minfontsize prefs into account?
   1.397 +          aFontSize = styleFont->mFont.size;
   1.398 +        }
   1.399 +        rootFontSize = aFontSize;
   1.400 +      } else if (aStyleContext && !aStyleContext->GetParent()) {
   1.401 +        // This is the root element (XXX we don't really know this, but
   1.402 +        // nsRuleNode::SetFont makes the same assumption!), so we should
   1.403 +        // use StyleFont on this context to get the root element's
   1.404 +        // font size.
   1.405 +        rootFontSize = styleFont->mFont.size;
   1.406 +      } else {
   1.407 +        // This is not the root element or we are calculating something other
   1.408 +        // than font size, so rem is relative to the root element's font size.
   1.409 +        nsRefPtr<nsStyleContext> rootStyle;
   1.410 +        const nsStyleFont *rootStyleFont = styleFont;
   1.411 +        Element* docElement = aPresContext->Document()->GetRootElement();
   1.412 +
   1.413 +        if (docElement) {
   1.414 +          rootStyle = aPresContext->StyleSet()->ResolveStyleFor(docElement,
   1.415 +                                                                nullptr);
   1.416 +          rootStyleFont = rootStyle->StyleFont();
   1.417 +        }
   1.418 +
   1.419 +        rootFontSize = rootStyleFont->mFont.size;
   1.420 +      }
   1.421 +
   1.422 +      return ScaleCoord(aValue, float(rootFontSize));
   1.423 +    }
   1.424 +    default:
   1.425 +      // Fall through to the code for units that can't be stored in the
   1.426 +      // rule tree because they depend on font data.
   1.427 +      break;
   1.428 +  }
   1.429 +  // Common code for units that depend on the element's font data and
   1.430 +  // thus can't be stored in the rule tree:
   1.431 +  aCanStoreInRuleTree = false;
   1.432 +  const nsStyleFont *styleFont =
   1.433 +    aStyleFont ? aStyleFont : aStyleContext->StyleFont();
   1.434 +  if (aFontSize == -1) {
   1.435 +    // XXX Should this be styleFont->mSize instead to avoid taking minfontsize
   1.436 +    // prefs into account?
   1.437 +    aFontSize = styleFont->mFont.size;
   1.438 +  }
   1.439 +  switch (aValue.GetUnit()) {
   1.440 +    case eCSSUnit_EM: {
   1.441 +      // CSS2.1 specifies that this unit scales to the computed font
   1.442 +      // size, not the em-width in the font metrics, despite the name.
   1.443 +      return ScaleCoord(aValue, float(aFontSize));
   1.444 +    }
   1.445 +    case eCSSUnit_XHeight: {
   1.446 +      nsRefPtr<nsFontMetrics> fm =
   1.447 +        GetMetricsFor(aPresContext, aStyleContext, styleFont,
   1.448 +                      aFontSize, aUseUserFontSet);
   1.449 +      return ScaleCoord(aValue, float(fm->XHeight()));
   1.450 +    }
   1.451 +    case eCSSUnit_Char: {
   1.452 +      nsRefPtr<nsFontMetrics> fm =
   1.453 +        GetMetricsFor(aPresContext, aStyleContext, styleFont,
   1.454 +                      aFontSize, aUseUserFontSet);
   1.455 +      gfxFloat zeroWidth = (fm->GetThebesFontGroup()->GetFontAt(0)
   1.456 +                            ->GetMetrics().zeroOrAveCharWidth);
   1.457 +
   1.458 +      return ScaleCoord(aValue, ceil(aPresContext->AppUnitsPerDevPixel() *
   1.459 +                                     zeroWidth));
   1.460 +    }
   1.461 +    default:
   1.462 +      NS_NOTREACHED("unexpected unit");
   1.463 +      break;
   1.464 +  }
   1.465 +  return 0;
   1.466 +}
   1.467 +
   1.468 +/* static */ nscoord
   1.469 +nsRuleNode::CalcLength(const nsCSSValue& aValue,
   1.470 +                       nsStyleContext* aStyleContext,
   1.471 +                       nsPresContext* aPresContext,
   1.472 +                       bool& aCanStoreInRuleTree)
   1.473 +{
   1.474 +  NS_ASSERTION(aStyleContext, "Must have style data");
   1.475 +
   1.476 +  return CalcLengthWith(aValue, -1, nullptr,
   1.477 +                        aStyleContext, aPresContext,
   1.478 +                        false, true, aCanStoreInRuleTree);
   1.479 +}
   1.480 +
   1.481 +/* Inline helper function to redirect requests to CalcLength. */
   1.482 +static inline nscoord CalcLength(const nsCSSValue& aValue,
   1.483 +                                 nsStyleContext* aStyleContext,
   1.484 +                                 nsPresContext* aPresContext,
   1.485 +                                 bool& aCanStoreInRuleTree)
   1.486 +{
   1.487 +  return nsRuleNode::CalcLength(aValue, aStyleContext,
   1.488 +                                aPresContext, aCanStoreInRuleTree);
   1.489 +}
   1.490 +
   1.491 +/* static */ nscoord
   1.492 +nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
   1.493 +                                      const nsCSSValue& aValue)
   1.494 +{
   1.495 +  nsStyleFont defaultFont(aPresContext); // FIXME: best language?
   1.496 +  bool canStoreInRuleTree;
   1.497 +  return CalcLengthWith(aValue, -1, &defaultFont,
   1.498 +                        nullptr, aPresContext,
   1.499 +                        true, false, canStoreInRuleTree);
   1.500 +}
   1.501 +
   1.502 +struct LengthPercentPairCalcOps : public css::NumbersAlreadyNormalizedOps
   1.503 +{
   1.504 +  typedef nsRuleNode::ComputedCalc result_type;
   1.505 +
   1.506 +  LengthPercentPairCalcOps(nsStyleContext* aContext,
   1.507 +                           nsPresContext* aPresContext,
   1.508 +                           bool& aCanStoreInRuleTree)
   1.509 +    : mContext(aContext),
   1.510 +      mPresContext(aPresContext),
   1.511 +      mCanStoreInRuleTree(aCanStoreInRuleTree),
   1.512 +      mHasPercent(false) {}
   1.513 +
   1.514 +  nsStyleContext* mContext;
   1.515 +  nsPresContext* mPresContext;
   1.516 +  bool& mCanStoreInRuleTree;
   1.517 +  bool mHasPercent;
   1.518 +
   1.519 +  result_type ComputeLeafValue(const nsCSSValue& aValue)
   1.520 +  {
   1.521 +    if (aValue.GetUnit() == eCSSUnit_Percent) {
   1.522 +      mHasPercent = true;
   1.523 +      return result_type(0, aValue.GetPercentValue());
   1.524 +    }
   1.525 +    return result_type(CalcLength(aValue, mContext, mPresContext,
   1.526 +                                  mCanStoreInRuleTree),
   1.527 +                       0.0f);
   1.528 +  }
   1.529 +
   1.530 +  result_type
   1.531 +  MergeAdditive(nsCSSUnit aCalcFunction,
   1.532 +                result_type aValue1, result_type aValue2)
   1.533 +  {
   1.534 +    if (aCalcFunction == eCSSUnit_Calc_Plus) {
   1.535 +      return result_type(NSCoordSaturatingAdd(aValue1.mLength,
   1.536 +                                              aValue2.mLength),
   1.537 +                         aValue1.mPercent + aValue2.mPercent);
   1.538 +    }
   1.539 +    NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Minus,
   1.540 +                      "min() and max() are not allowed in calc() on "
   1.541 +                      "transform");
   1.542 +    return result_type(NSCoordSaturatingSubtract(aValue1.mLength,
   1.543 +                                                 aValue2.mLength, 0),
   1.544 +                       aValue1.mPercent - aValue2.mPercent);
   1.545 +  }
   1.546 +
   1.547 +  result_type
   1.548 +  MergeMultiplicativeL(nsCSSUnit aCalcFunction,
   1.549 +                       float aValue1, result_type aValue2)
   1.550 +  {
   1.551 +    NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_L,
   1.552 +                      "unexpected unit");
   1.553 +    return result_type(NSCoordSaturatingMultiply(aValue2.mLength, aValue1),
   1.554 +                       aValue1 * aValue2.mPercent);
   1.555 +  }
   1.556 +
   1.557 +  result_type
   1.558 +  MergeMultiplicativeR(nsCSSUnit aCalcFunction,
   1.559 +                       result_type aValue1, float aValue2)
   1.560 +  {
   1.561 +    NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_R ||
   1.562 +                      aCalcFunction == eCSSUnit_Calc_Divided,
   1.563 +                      "unexpected unit");
   1.564 +    if (aCalcFunction == eCSSUnit_Calc_Divided) {
   1.565 +      aValue2 = 1.0f / aValue2;
   1.566 +    }
   1.567 +    return result_type(NSCoordSaturatingMultiply(aValue1.mLength, aValue2),
   1.568 +                       aValue1.mPercent * aValue2);
   1.569 +  }
   1.570 +
   1.571 +};
   1.572 +
   1.573 +static void
   1.574 +SpecifiedCalcToComputedCalc(const nsCSSValue& aValue, nsStyleCoord& aCoord, 
   1.575 +                            nsStyleContext* aStyleContext,
   1.576 +                            bool& aCanStoreInRuleTree)
   1.577 +{
   1.578 +  LengthPercentPairCalcOps ops(aStyleContext, aStyleContext->PresContext(),
   1.579 +                               aCanStoreInRuleTree);
   1.580 +  nsRuleNode::ComputedCalc vals = ComputeCalc(aValue, ops);
   1.581 +
   1.582 +  nsStyleCoord::Calc *calcObj =
   1.583 +    new (aStyleContext->Alloc(sizeof(nsStyleCoord::Calc))) nsStyleCoord::Calc;
   1.584 +  // Because we use aStyleContext->Alloc(), we have to store the result
   1.585 +  // on the style context and not in the rule tree.
   1.586 +  aCanStoreInRuleTree = false;
   1.587 +
   1.588 +  calcObj->mLength = vals.mLength;
   1.589 +  calcObj->mPercent = vals.mPercent;
   1.590 +  calcObj->mHasPercent = ops.mHasPercent;
   1.591 +
   1.592 +  aCoord.SetCalcValue(calcObj);
   1.593 +}
   1.594 +
   1.595 +/* static */ nsRuleNode::ComputedCalc
   1.596 +nsRuleNode::SpecifiedCalcToComputedCalc(const nsCSSValue& aValue,
   1.597 +                                        nsStyleContext* aStyleContext,
   1.598 +                                        nsPresContext* aPresContext,
   1.599 +                                        bool& aCanStoreInRuleTree)
   1.600 +{
   1.601 +  LengthPercentPairCalcOps ops(aStyleContext, aPresContext,
   1.602 +                               aCanStoreInRuleTree);
   1.603 +  return ComputeCalc(aValue, ops);
   1.604 +}
   1.605 +
   1.606 +// This is our public API for handling calc() expressions that involve
   1.607 +// percentages.
   1.608 +/* static */ nscoord
   1.609 +nsRuleNode::ComputeComputedCalc(const nsStyleCoord& aValue,
   1.610 +                                nscoord aPercentageBasis)
   1.611 +{
   1.612 +  nsStyleCoord::Calc *calc = aValue.GetCalcValue();
   1.613 +  return calc->mLength +
   1.614 +         NSToCoordFloorClamped(aPercentageBasis * calc->mPercent);
   1.615 +}
   1.616 +
   1.617 +/* static */ nscoord
   1.618 +nsRuleNode::ComputeCoordPercentCalc(const nsStyleCoord& aCoord,
   1.619 +                                    nscoord aPercentageBasis)
   1.620 +{
   1.621 +  switch (aCoord.GetUnit()) {
   1.622 +    case eStyleUnit_Coord:
   1.623 +      return aCoord.GetCoordValue();
   1.624 +    case eStyleUnit_Percent:
   1.625 +      return NSToCoordFloorClamped(aPercentageBasis * aCoord.GetPercentValue());
   1.626 +    case eStyleUnit_Calc:
   1.627 +      return ComputeComputedCalc(aCoord, aPercentageBasis);
   1.628 +    default:
   1.629 +      NS_ABORT_IF_FALSE(false, "unexpected unit");
   1.630 +      return 0;
   1.631 +  }
   1.632 +}
   1.633 +
   1.634 +/* Given an enumerated value that represents a box position, converts it to
   1.635 + * a float representing the percentage of the box it corresponds to.  For
   1.636 + * example, "center" becomes 0.5f.
   1.637 + *
   1.638 + * @param aEnumValue The enumerated value.
   1.639 + * @return The float percent it corresponds to.
   1.640 + */
   1.641 +static float
   1.642 +GetFloatFromBoxPosition(int32_t aEnumValue)
   1.643 +{
   1.644 +  switch (aEnumValue) {
   1.645 +  case NS_STYLE_BG_POSITION_LEFT:
   1.646 +  case NS_STYLE_BG_POSITION_TOP:
   1.647 +    return 0.0f;
   1.648 +  case NS_STYLE_BG_POSITION_RIGHT:
   1.649 +  case NS_STYLE_BG_POSITION_BOTTOM:
   1.650 +    return 1.0f;
   1.651 +  default:
   1.652 +    NS_NOTREACHED("unexpected value");
   1.653 +    // fall through
   1.654 +  case NS_STYLE_BG_POSITION_CENTER:
   1.655 +    return 0.5f;
   1.656 +  }
   1.657 +}
   1.658 +
   1.659 +#define SETCOORD_NORMAL                 0x01   // N
   1.660 +#define SETCOORD_AUTO                   0x02   // A
   1.661 +#define SETCOORD_INHERIT                0x04   // H
   1.662 +#define SETCOORD_PERCENT                0x08   // P
   1.663 +#define SETCOORD_FACTOR                 0x10   // F
   1.664 +#define SETCOORD_LENGTH                 0x20   // L
   1.665 +#define SETCOORD_INTEGER                0x40   // I
   1.666 +#define SETCOORD_ENUMERATED             0x80   // E
   1.667 +#define SETCOORD_NONE                   0x100  // O
   1.668 +#define SETCOORD_INITIAL_ZERO           0x200
   1.669 +#define SETCOORD_INITIAL_AUTO           0x400
   1.670 +#define SETCOORD_INITIAL_NONE           0x800
   1.671 +#define SETCOORD_INITIAL_NORMAL         0x1000
   1.672 +#define SETCOORD_INITIAL_HALF           0x2000
   1.673 +#define SETCOORD_INITIAL_HUNDRED_PCT    0x00004000
   1.674 +#define SETCOORD_INITIAL_FACTOR_ONE     0x00008000
   1.675 +#define SETCOORD_INITIAL_FACTOR_ZERO    0x00010000
   1.676 +#define SETCOORD_CALC_LENGTH_ONLY       0x00020000
   1.677 +#define SETCOORD_CALC_CLAMP_NONNEGATIVE 0x00040000 // modifier for CALC_LENGTH_ONLY
   1.678 +#define SETCOORD_STORE_CALC             0x00080000
   1.679 +#define SETCOORD_BOX_POSITION           0x00100000 // exclusive with _ENUMERATED
   1.680 +#define SETCOORD_ANGLE                  0x00200000
   1.681 +#define SETCOORD_UNSET_INHERIT          0x00400000
   1.682 +#define SETCOORD_UNSET_INITIAL          0x00800000
   1.683 +
   1.684 +#define SETCOORD_LP     (SETCOORD_LENGTH | SETCOORD_PERCENT)
   1.685 +#define SETCOORD_LH     (SETCOORD_LENGTH | SETCOORD_INHERIT)
   1.686 +#define SETCOORD_AH     (SETCOORD_AUTO | SETCOORD_INHERIT)
   1.687 +#define SETCOORD_LAH    (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT)
   1.688 +#define SETCOORD_LPH    (SETCOORD_LP | SETCOORD_INHERIT)
   1.689 +#define SETCOORD_LPAH   (SETCOORD_LP | SETCOORD_AH)
   1.690 +#define SETCOORD_LPE    (SETCOORD_LP | SETCOORD_ENUMERATED)
   1.691 +#define SETCOORD_LPEH   (SETCOORD_LPE | SETCOORD_INHERIT)
   1.692 +#define SETCOORD_LPAEH  (SETCOORD_LPAH | SETCOORD_ENUMERATED)
   1.693 +#define SETCOORD_LPO    (SETCOORD_LP | SETCOORD_NONE)
   1.694 +#define SETCOORD_LPOH   (SETCOORD_LPH | SETCOORD_NONE)
   1.695 +#define SETCOORD_LPOEH  (SETCOORD_LPOH | SETCOORD_ENUMERATED)
   1.696 +#define SETCOORD_LE     (SETCOORD_LENGTH | SETCOORD_ENUMERATED)
   1.697 +#define SETCOORD_LEH    (SETCOORD_LE | SETCOORD_INHERIT)
   1.698 +#define SETCOORD_IA     (SETCOORD_INTEGER | SETCOORD_AUTO)
   1.699 +#define SETCOORD_LAE    (SETCOORD_LENGTH | SETCOORD_AUTO | SETCOORD_ENUMERATED)
   1.700 +
   1.701 +// changes aCoord iff it returns true
   1.702 +static bool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
   1.703 +                       const nsStyleCoord& aParentCoord,
   1.704 +                       int32_t aMask, nsStyleContext* aStyleContext,
   1.705 +                       nsPresContext* aPresContext,
   1.706 +                       bool& aCanStoreInRuleTree)
   1.707 +{
   1.708 +  bool result = true;
   1.709 +  if (aValue.GetUnit() == eCSSUnit_Null) {
   1.710 +    result = false;
   1.711 +  }
   1.712 +  else if ((((aMask & SETCOORD_LENGTH) != 0) &&
   1.713 +            aValue.IsLengthUnit()) ||
   1.714 +           (((aMask & SETCOORD_CALC_LENGTH_ONLY) != 0) &&
   1.715 +            aValue.IsCalcUnit())) {
   1.716 +    nscoord len = CalcLength(aValue, aStyleContext, aPresContext,
   1.717 +                             aCanStoreInRuleTree);
   1.718 +    if ((aMask & SETCOORD_CALC_CLAMP_NONNEGATIVE) && len < 0) {
   1.719 +      NS_ASSERTION(aValue.IsCalcUnit(),
   1.720 +                   "parser should have ensured no nonnegative lengths");
   1.721 +      len = 0;
   1.722 +    }
   1.723 +    aCoord.SetCoordValue(len);
   1.724 +  }
   1.725 +  else if (((aMask & SETCOORD_PERCENT) != 0) &&
   1.726 +           (aValue.GetUnit() == eCSSUnit_Percent)) {
   1.727 +    aCoord.SetPercentValue(aValue.GetPercentValue());
   1.728 +  }
   1.729 +  else if (((aMask & SETCOORD_INTEGER) != 0) &&
   1.730 +           (aValue.GetUnit() == eCSSUnit_Integer)) {
   1.731 +    aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Integer);
   1.732 +  }
   1.733 +  else if (((aMask & SETCOORD_ENUMERATED) != 0) &&
   1.734 +           (aValue.GetUnit() == eCSSUnit_Enumerated)) {
   1.735 +    aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Enumerated);
   1.736 +  }
   1.737 +  else if (((aMask & SETCOORD_BOX_POSITION) != 0) &&
   1.738 +           (aValue.GetUnit() == eCSSUnit_Enumerated)) {
   1.739 +    aCoord.SetPercentValue(GetFloatFromBoxPosition(aValue.GetIntValue()));
   1.740 +  }
   1.741 +  else if (((aMask & SETCOORD_AUTO) != 0) &&
   1.742 +           (aValue.GetUnit() == eCSSUnit_Auto)) {
   1.743 +    aCoord.SetAutoValue();
   1.744 +  }
   1.745 +  else if ((((aMask & SETCOORD_INHERIT) != 0) &&
   1.746 +            aValue.GetUnit() == eCSSUnit_Inherit) ||
   1.747 +           (((aMask & SETCOORD_UNSET_INHERIT) != 0) &&
   1.748 +            aValue.GetUnit() == eCSSUnit_Unset)) {
   1.749 +    aCoord = aParentCoord;  // just inherit value from parent
   1.750 +    aCanStoreInRuleTree = false;
   1.751 +  }
   1.752 +  else if (((aMask & SETCOORD_NORMAL) != 0) &&
   1.753 +           (aValue.GetUnit() == eCSSUnit_Normal)) {
   1.754 +    aCoord.SetNormalValue();
   1.755 +  }
   1.756 +  else if (((aMask & SETCOORD_NONE) != 0) &&
   1.757 +           (aValue.GetUnit() == eCSSUnit_None)) {
   1.758 +    aCoord.SetNoneValue();
   1.759 +  }
   1.760 +  else if (((aMask & SETCOORD_FACTOR) != 0) &&
   1.761 +           (aValue.GetUnit() == eCSSUnit_Number)) {
   1.762 +    aCoord.SetFactorValue(aValue.GetFloatValue());
   1.763 +  }
   1.764 +  else if (((aMask & SETCOORD_STORE_CALC) != 0) &&
   1.765 +           (aValue.IsCalcUnit())) {
   1.766 +    SpecifiedCalcToComputedCalc(aValue, aCoord, aStyleContext,
   1.767 +                                aCanStoreInRuleTree);
   1.768 +  }
   1.769 +  else if (aValue.GetUnit() == eCSSUnit_Initial ||
   1.770 +           (aValue.GetUnit() == eCSSUnit_Unset &&
   1.771 +            ((aMask & SETCOORD_UNSET_INITIAL) != 0))) {
   1.772 +    if ((aMask & SETCOORD_INITIAL_AUTO) != 0) {
   1.773 +      aCoord.SetAutoValue();
   1.774 +    }
   1.775 +    else if ((aMask & SETCOORD_INITIAL_ZERO) != 0) {
   1.776 +      aCoord.SetCoordValue(0);
   1.777 +    }
   1.778 +    else if ((aMask & SETCOORD_INITIAL_FACTOR_ZERO) != 0) {
   1.779 +      aCoord.SetFactorValue(0.0f);
   1.780 +    }
   1.781 +    else if ((aMask & SETCOORD_INITIAL_NONE) != 0) {
   1.782 +      aCoord.SetNoneValue();
   1.783 +    }
   1.784 +    else if ((aMask & SETCOORD_INITIAL_NORMAL) != 0) {
   1.785 +      aCoord.SetNormalValue();
   1.786 +    }
   1.787 +    else if ((aMask & SETCOORD_INITIAL_HALF) != 0) {
   1.788 +      aCoord.SetPercentValue(0.5f);
   1.789 +    }
   1.790 +    else if ((aMask & SETCOORD_INITIAL_HUNDRED_PCT) != 0) {
   1.791 +      aCoord.SetPercentValue(1.0f);
   1.792 +    }
   1.793 +    else if ((aMask & SETCOORD_INITIAL_FACTOR_ONE) != 0) {
   1.794 +      aCoord.SetFactorValue(1.0f);
   1.795 +    }
   1.796 +    else {
   1.797 +      result = false;  // didn't set anything
   1.798 +    }
   1.799 +  }
   1.800 +  else if ((aMask & SETCOORD_ANGLE) != 0 &&
   1.801 +           (aValue.IsAngularUnit())) {
   1.802 +    nsStyleUnit unit;
   1.803 +    switch (aValue.GetUnit()) {
   1.804 +      case eCSSUnit_Degree: unit = eStyleUnit_Degree; break;
   1.805 +      case eCSSUnit_Grad:   unit = eStyleUnit_Grad; break;
   1.806 +      case eCSSUnit_Radian: unit = eStyleUnit_Radian; break;
   1.807 +      case eCSSUnit_Turn:   unit = eStyleUnit_Turn; break;
   1.808 +      default: NS_NOTREACHED("unrecognized angular unit");
   1.809 +        unit = eStyleUnit_Degree;
   1.810 +    }
   1.811 +    aCoord.SetAngleValue(aValue.GetAngleValue(), unit);
   1.812 +  }
   1.813 +  else {
   1.814 +    result = false;  // didn't set anything
   1.815 +  }
   1.816 +  return result;
   1.817 +}
   1.818 +
   1.819 +// This inline function offers a shortcut for SetCoord() by refusing to accept
   1.820 +// SETCOORD_LENGTH, SETCOORD_INHERIT and SETCOORD_UNSET_* masks.
   1.821 +static inline bool SetAbsCoord(const nsCSSValue& aValue,
   1.822 +                                 nsStyleCoord& aCoord,
   1.823 +                                 int32_t aMask)
   1.824 +{
   1.825 +  NS_ABORT_IF_FALSE((aMask & (SETCOORD_LH | SETCOORD_UNSET_INHERIT |
   1.826 +                              SETCOORD_UNSET_INITIAL)) == 0,
   1.827 +                    "does not handle SETCOORD_LENGTH, SETCOORD_INHERIT and "
   1.828 +                    "SETCOORD_UNSET_*");
   1.829 +
   1.830 +  // The values of the following variables will never be used; so it does not
   1.831 +  // matter what to set.
   1.832 +  const nsStyleCoord dummyParentCoord;
   1.833 +  nsStyleContext* dummyStyleContext = nullptr;
   1.834 +  nsPresContext* dummyPresContext = nullptr;
   1.835 +  bool dummyCanStoreInRuleTree = true;
   1.836 +
   1.837 +  bool rv = SetCoord(aValue, aCoord, dummyParentCoord, aMask,
   1.838 +                       dummyStyleContext, dummyPresContext,
   1.839 +                       dummyCanStoreInRuleTree);
   1.840 +  NS_ABORT_IF_FALSE(dummyCanStoreInRuleTree,
   1.841 +                    "SetCoord() should not modify dummyCanStoreInRuleTree.");
   1.842 +
   1.843 +  return rv;
   1.844 +}
   1.845 +
   1.846 +/* Given a specified value that might be a pair value, call SetCoord twice,
   1.847 + * either using each member of the pair, or using the unpaired value twice.
   1.848 + */
   1.849 +static bool
   1.850 +SetPairCoords(const nsCSSValue& aValue,
   1.851 +              nsStyleCoord& aCoordX, nsStyleCoord& aCoordY,
   1.852 +              const nsStyleCoord& aParentX, const nsStyleCoord& aParentY,
   1.853 +              int32_t aMask, nsStyleContext* aStyleContext,
   1.854 +              nsPresContext* aPresContext, bool& aCanStoreInRuleTree)
   1.855 +{
   1.856 +  const nsCSSValue& valX =
   1.857 +    aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mXValue : aValue;
   1.858 +  const nsCSSValue& valY =
   1.859 +    aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mYValue : aValue;
   1.860 +
   1.861 +  bool cX = SetCoord(valX, aCoordX, aParentX, aMask, aStyleContext,
   1.862 +                       aPresContext, aCanStoreInRuleTree);
   1.863 +  mozilla::DebugOnly<bool> cY = SetCoord(valY, aCoordY, aParentY, aMask, 
   1.864 +                       aStyleContext, aPresContext, aCanStoreInRuleTree);
   1.865 +  NS_ABORT_IF_FALSE(cX == cY, "changed one but not the other");
   1.866 +  return cX;
   1.867 +}
   1.868 +
   1.869 +static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
   1.870 +                       nsPresContext* aPresContext, nsStyleContext *aContext,
   1.871 +                       nscolor& aResult, bool& aCanStoreInRuleTree)
   1.872 +{
   1.873 +  bool    result = false;
   1.874 +  nsCSSUnit unit = aValue.GetUnit();
   1.875 +
   1.876 +  if (aValue.IsNumericColorUnit()) {
   1.877 +    aResult = aValue.GetColorValue();
   1.878 +    result = true;
   1.879 +  }
   1.880 +  else if (eCSSUnit_Ident == unit) {
   1.881 +    nsAutoString  value;
   1.882 +    aValue.GetStringValue(value);
   1.883 +    nscolor rgba;
   1.884 +    if (NS_ColorNameToRGB(value, &rgba)) {
   1.885 +      aResult = rgba;
   1.886 +      result = true;
   1.887 +    }
   1.888 +  }
   1.889 +  else if (eCSSUnit_EnumColor == unit) {
   1.890 +    int32_t intValue = aValue.GetIntValue();
   1.891 +    if (0 <= intValue) {
   1.892 +      LookAndFeel::ColorID colorID = (LookAndFeel::ColorID) intValue;
   1.893 +      bool useStandinsForNativeColors = aPresContext &&
   1.894 +                                        !aPresContext->IsChrome();
   1.895 +      if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID,
   1.896 +                                    useStandinsForNativeColors, &aResult))) {
   1.897 +        result = true;
   1.898 +      }
   1.899 +    }
   1.900 +    else {
   1.901 +      aResult = NS_RGB(0, 0, 0);
   1.902 +      result = false;
   1.903 +      switch (intValue) {
   1.904 +        case NS_COLOR_MOZ_HYPERLINKTEXT:
   1.905 +          if (aPresContext) {
   1.906 +            aResult = aPresContext->DefaultLinkColor();
   1.907 +            result = true;
   1.908 +          }
   1.909 +          break;
   1.910 +        case NS_COLOR_MOZ_VISITEDHYPERLINKTEXT:
   1.911 +          if (aPresContext) {
   1.912 +            aResult = aPresContext->DefaultVisitedLinkColor();
   1.913 +            result = true;
   1.914 +          }
   1.915 +          break;
   1.916 +        case NS_COLOR_MOZ_ACTIVEHYPERLINKTEXT:
   1.917 +          if (aPresContext) {
   1.918 +            aResult = aPresContext->DefaultActiveLinkColor();
   1.919 +            result = true;
   1.920 +          }
   1.921 +          break;
   1.922 +        case NS_COLOR_CURRENTCOLOR:
   1.923 +          // The data computed from this can't be shared in the rule tree
   1.924 +          // because they could be used on a node with a different color
   1.925 +          aCanStoreInRuleTree = false;
   1.926 +          if (aContext) {
   1.927 +            aResult = aContext->StyleColor()->mColor;
   1.928 +            result = true;
   1.929 +          }
   1.930 +          break;
   1.931 +        case NS_COLOR_MOZ_DEFAULT_COLOR:
   1.932 +          if (aPresContext) {
   1.933 +            aResult = aPresContext->DefaultColor();
   1.934 +            result = true;
   1.935 +          }
   1.936 +          break;
   1.937 +        case NS_COLOR_MOZ_DEFAULT_BACKGROUND_COLOR:
   1.938 +          if (aPresContext) {
   1.939 +            aResult = aPresContext->DefaultBackgroundColor();
   1.940 +            result = true;
   1.941 +          }
   1.942 +          break;
   1.943 +        default:
   1.944 +          NS_NOTREACHED("Should never have an unknown negative colorID.");
   1.945 +          break;
   1.946 +      }
   1.947 +    }
   1.948 +  }
   1.949 +  else if (eCSSUnit_Inherit == unit) {
   1.950 +    aResult = aParentColor;
   1.951 +    result = true;
   1.952 +    aCanStoreInRuleTree = false;
   1.953 +  }
   1.954 +  else if (eCSSUnit_Enumerated == unit &&
   1.955 +           aValue.GetIntValue() == NS_STYLE_COLOR_INHERIT_FROM_BODY) {
   1.956 +    NS_ASSERTION(aPresContext->CompatibilityMode() == eCompatibility_NavQuirks,
   1.957 +                 "Should only get this value in quirks mode");
   1.958 +    // We just grab the color from the prescontext, and rely on the fact that
   1.959 +    // if the body color ever changes all its descendants will get new style
   1.960 +    // contexts (but NOT necessarily new rulenodes).
   1.961 +    aResult = aPresContext->BodyTextColor();
   1.962 +    result = true;
   1.963 +    aCanStoreInRuleTree = false;
   1.964 +  }
   1.965 +  return result;
   1.966 +}
   1.967 +
   1.968 +static void SetGradientCoord(const nsCSSValue& aValue, nsPresContext* aPresContext,
   1.969 +                             nsStyleContext* aContext, nsStyleCoord& aResult,
   1.970 +                             bool& aCanStoreInRuleTree)
   1.971 +{
   1.972 +  // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
   1.973 +  if (!SetCoord(aValue, aResult, nsStyleCoord(),
   1.974 +                SETCOORD_LPO | SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC,
   1.975 +                aContext, aPresContext, aCanStoreInRuleTree)) {
   1.976 +    NS_NOTREACHED("unexpected unit for gradient anchor point");
   1.977 +    aResult.SetNoneValue();
   1.978 +  }
   1.979 +}
   1.980 +
   1.981 +static void SetGradient(const nsCSSValue& aValue, nsPresContext* aPresContext,
   1.982 +                        nsStyleContext* aContext, nsStyleGradient& aResult,
   1.983 +                        bool& aCanStoreInRuleTree)
   1.984 +{
   1.985 +  NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Gradient,
   1.986 +                    "The given data is not a gradient");
   1.987 +
   1.988 +  const nsCSSValueGradient* gradient = aValue.GetGradientValue();
   1.989 +
   1.990 +  if (gradient->mIsExplicitSize) {
   1.991 +    SetCoord(gradient->GetRadiusX(), aResult.mRadiusX, nsStyleCoord(),
   1.992 +             SETCOORD_LP | SETCOORD_STORE_CALC,
   1.993 +             aContext, aPresContext, aCanStoreInRuleTree);
   1.994 +    if (gradient->GetRadiusY().GetUnit() != eCSSUnit_None) {
   1.995 +      SetCoord(gradient->GetRadiusY(), aResult.mRadiusY, nsStyleCoord(),
   1.996 +               SETCOORD_LP | SETCOORD_STORE_CALC,
   1.997 +               aContext, aPresContext, aCanStoreInRuleTree);
   1.998 +      aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
   1.999 +    } else {
  1.1000 +      aResult.mRadiusY = aResult.mRadiusX;
  1.1001 +      aResult.mShape = NS_STYLE_GRADIENT_SHAPE_CIRCULAR;
  1.1002 +    }
  1.1003 +    aResult.mSize = NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE;
  1.1004 +  } else if (gradient->mIsRadial) {
  1.1005 +    if (gradient->GetRadialShape().GetUnit() == eCSSUnit_Enumerated) {
  1.1006 +      aResult.mShape = gradient->GetRadialShape().GetIntValue();
  1.1007 +    } else {
  1.1008 +      NS_ASSERTION(gradient->GetRadialShape().GetUnit() == eCSSUnit_None,
  1.1009 +                   "bad unit for radial shape");
  1.1010 +      aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
  1.1011 +    }
  1.1012 +    if (gradient->GetRadialSize().GetUnit() == eCSSUnit_Enumerated) {
  1.1013 +      aResult.mSize = gradient->GetRadialSize().GetIntValue();
  1.1014 +    } else {
  1.1015 +      NS_ASSERTION(gradient->GetRadialSize().GetUnit() == eCSSUnit_None,
  1.1016 +                   "bad unit for radial shape");
  1.1017 +      aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
  1.1018 +    }
  1.1019 +  } else {
  1.1020 +    NS_ASSERTION(gradient->GetRadialShape().GetUnit() == eCSSUnit_None,
  1.1021 +                 "bad unit for linear shape");
  1.1022 +    NS_ASSERTION(gradient->GetRadialSize().GetUnit() == eCSSUnit_None,
  1.1023 +                 "bad unit for linear size");
  1.1024 +    aResult.mShape = NS_STYLE_GRADIENT_SHAPE_LINEAR;
  1.1025 +    aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
  1.1026 +  }
  1.1027 +
  1.1028 +  aResult.mLegacySyntax = gradient->mIsLegacySyntax;
  1.1029 +
  1.1030 +  // bg-position
  1.1031 +  SetGradientCoord(gradient->mBgPos.mXValue, aPresContext, aContext,
  1.1032 +                   aResult.mBgPosX, aCanStoreInRuleTree);
  1.1033 +
  1.1034 +  SetGradientCoord(gradient->mBgPos.mYValue, aPresContext, aContext,
  1.1035 +                   aResult.mBgPosY, aCanStoreInRuleTree);
  1.1036 +
  1.1037 +  aResult.mRepeating = gradient->mIsRepeating;
  1.1038 +
  1.1039 +  // angle
  1.1040 +  const nsStyleCoord dummyParentCoord;
  1.1041 +  if (!SetCoord(gradient->mAngle, aResult.mAngle, dummyParentCoord, SETCOORD_ANGLE,
  1.1042 +                aContext, aPresContext, aCanStoreInRuleTree)) {
  1.1043 +    NS_ASSERTION(gradient->mAngle.GetUnit() == eCSSUnit_None,
  1.1044 +                 "bad unit for gradient angle");
  1.1045 +    aResult.mAngle.SetNoneValue();
  1.1046 +  }
  1.1047 +
  1.1048 +  // stops
  1.1049 +  for (uint32_t i = 0; i < gradient->mStops.Length(); i++) {
  1.1050 +    nsStyleGradientStop stop;
  1.1051 +    const nsCSSValueGradientStop &valueStop = gradient->mStops[i];
  1.1052 +
  1.1053 +    if (!SetCoord(valueStop.mLocation, stop.mLocation,
  1.1054 +                  nsStyleCoord(), SETCOORD_LPO | SETCOORD_STORE_CALC,
  1.1055 +                  aContext, aPresContext, aCanStoreInRuleTree)) {
  1.1056 +      NS_NOTREACHED("unexpected unit for gradient stop location");
  1.1057 +    }
  1.1058 +
  1.1059 +    // inherit is not a valid color for stops, so we pass in a dummy
  1.1060 +    // parent color
  1.1061 +    NS_ASSERTION(valueStop.mColor.GetUnit() != eCSSUnit_Inherit,
  1.1062 +                 "inherit is not a valid color for gradient stops");
  1.1063 +    SetColor(valueStop.mColor, NS_RGB(0, 0, 0), aPresContext,
  1.1064 +             aContext, stop.mColor, aCanStoreInRuleTree);
  1.1065 +
  1.1066 +    aResult.mStops.AppendElement(stop);
  1.1067 +  }
  1.1068 +}
  1.1069 +
  1.1070 +// -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
  1.1071 +static void SetStyleImageToImageRect(nsStyleContext* aStyleContext,
  1.1072 +                                     const nsCSSValue& aValue,
  1.1073 +                                     nsStyleImage& aResult)
  1.1074 +{
  1.1075 +  NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Function &&
  1.1076 +                    aValue.EqualsFunction(eCSSKeyword__moz_image_rect),
  1.1077 +                    "the value is not valid -moz-image-rect()");
  1.1078 +
  1.1079 +  nsCSSValue::Array* arr = aValue.GetArrayValue();
  1.1080 +  NS_ABORT_IF_FALSE(arr && arr->Count() == 6, "invalid number of arguments");
  1.1081 +
  1.1082 +  // <uri>
  1.1083 +  if (arr->Item(1).GetUnit() == eCSSUnit_Image) {
  1.1084 +    NS_SET_IMAGE_REQUEST_WITH_DOC(aResult.SetImageData,
  1.1085 +                                  aStyleContext,
  1.1086 +                                  arr->Item(1).GetImageValue)
  1.1087 +  } else {
  1.1088 +    NS_WARNING("nsCSSValue::Image::Image() failed?");
  1.1089 +  }
  1.1090 +
  1.1091 +  // <top>, <right>, <bottom>, <left>
  1.1092 +  nsStyleSides cropRect;
  1.1093 +  NS_FOR_CSS_SIDES(side) {
  1.1094 +    nsStyleCoord coord;
  1.1095 +    const nsCSSValue& val = arr->Item(2 + side);
  1.1096 +
  1.1097 +#ifdef DEBUG
  1.1098 +    bool unitOk =
  1.1099 +#endif
  1.1100 +      SetAbsCoord(val, coord, SETCOORD_FACTOR | SETCOORD_PERCENT);
  1.1101 +    NS_ABORT_IF_FALSE(unitOk, "Incorrect data structure created by CSS parser");
  1.1102 +    cropRect.Set(side, coord);
  1.1103 +  }
  1.1104 +  aResult.SetCropRect(&cropRect);
  1.1105 +}
  1.1106 +
  1.1107 +static void SetStyleImage(nsStyleContext* aStyleContext,
  1.1108 +                          const nsCSSValue& aValue,
  1.1109 +                          nsStyleImage& aResult,
  1.1110 +                          bool& aCanStoreInRuleTree)
  1.1111 +{
  1.1112 +  if (aValue.GetUnit() == eCSSUnit_Null) {
  1.1113 +    return;
  1.1114 +  }
  1.1115 +
  1.1116 +  aResult.SetNull();
  1.1117 +
  1.1118 +  switch (aValue.GetUnit()) {
  1.1119 +    case eCSSUnit_Image:
  1.1120 +      NS_SET_IMAGE_REQUEST_WITH_DOC(aResult.SetImageData,
  1.1121 +                                    aStyleContext,
  1.1122 +                                    aValue.GetImageValue)
  1.1123 +      break;
  1.1124 +    case eCSSUnit_Function:
  1.1125 +      if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
  1.1126 +        SetStyleImageToImageRect(aStyleContext, aValue, aResult);
  1.1127 +      } else {
  1.1128 +        NS_NOTREACHED("-moz-image-rect() is the only expected function");
  1.1129 +      }
  1.1130 +      break;
  1.1131 +    case eCSSUnit_Gradient:
  1.1132 +    {
  1.1133 +      nsStyleGradient* gradient = new nsStyleGradient();
  1.1134 +      if (gradient) {
  1.1135 +        SetGradient(aValue, aStyleContext->PresContext(), aStyleContext,
  1.1136 +                    *gradient, aCanStoreInRuleTree);
  1.1137 +        aResult.SetGradientData(gradient);
  1.1138 +      }
  1.1139 +      break;
  1.1140 +    }
  1.1141 +    case eCSSUnit_Element:
  1.1142 +      aResult.SetElementId(aValue.GetStringBufferValue());
  1.1143 +      break;
  1.1144 +    case eCSSUnit_Initial:
  1.1145 +    case eCSSUnit_Unset:
  1.1146 +    case eCSSUnit_None:
  1.1147 +      break;
  1.1148 +    default:
  1.1149 +      // We might have eCSSUnit_URL values for if-visited style
  1.1150 +      // contexts, which we can safely treat like 'none'.  Otherwise
  1.1151 +      // this is an unexpected unit.
  1.1152 +      NS_ASSERTION(aStyleContext->IsStyleIfVisited() &&
  1.1153 +                   aValue.GetUnit() == eCSSUnit_URL,
  1.1154 +                   "unexpected unit; maybe nsCSSValue::Image::Image() failed?");
  1.1155 +      break;
  1.1156 +  }
  1.1157 +}
  1.1158 +
  1.1159 +// flags for SetDiscrete - align values with SETCOORD_* constants
  1.1160 +// where possible
  1.1161 +
  1.1162 +#define SETDSC_NORMAL                 0x01   // N
  1.1163 +#define SETDSC_AUTO                   0x02   // A
  1.1164 +#define SETDSC_INTEGER                0x40   // I
  1.1165 +#define SETDSC_ENUMERATED             0x80   // E
  1.1166 +#define SETDSC_NONE                   0x100  // O
  1.1167 +#define SETDSC_SYSTEM_FONT            0x2000
  1.1168 +#define SETDSC_UNSET_INHERIT          0x00400000
  1.1169 +#define SETDSC_UNSET_INITIAL          0x00800000
  1.1170 +
  1.1171 +// no caller cares whether aField was changed or not
  1.1172 +template <typename FieldT,
  1.1173 +          typename T1, typename T2, typename T3, typename T4, typename T5>
  1.1174 +static void
  1.1175 +SetDiscrete(const nsCSSValue& aValue, FieldT & aField,
  1.1176 +            bool& aCanStoreInRuleTree, uint32_t aMask,
  1.1177 +            FieldT aParentValue,
  1.1178 +            T1 aInitialValue,
  1.1179 +            T2 aAutoValue,
  1.1180 +            T3 aNoneValue,
  1.1181 +            T4 aNormalValue,
  1.1182 +            T5 aSystemFontValue)
  1.1183 +{
  1.1184 +  switch (aValue.GetUnit()) {
  1.1185 +  case eCSSUnit_Null:
  1.1186 +    return;
  1.1187 +
  1.1188 +    // every caller of SetDiscrete provides inherit and initial
  1.1189 +    // alternatives, so we don't require them to say so in the mask
  1.1190 +  case eCSSUnit_Inherit:
  1.1191 +    aCanStoreInRuleTree = false;
  1.1192 +    aField = aParentValue;
  1.1193 +    return;
  1.1194 +
  1.1195 +  case eCSSUnit_Initial:
  1.1196 +    aField = aInitialValue;
  1.1197 +    return;
  1.1198 +
  1.1199 +    // every caller provides one or other of these alternatives,
  1.1200 +    // but they have to say which
  1.1201 +  case eCSSUnit_Enumerated:
  1.1202 +    if (aMask & SETDSC_ENUMERATED) {
  1.1203 +      aField = aValue.GetIntValue();
  1.1204 +      return;
  1.1205 +    }
  1.1206 +    break;
  1.1207 +
  1.1208 +  case eCSSUnit_Integer:
  1.1209 +    if (aMask & SETDSC_INTEGER) {
  1.1210 +      aField = aValue.GetIntValue();
  1.1211 +      return;
  1.1212 +    }
  1.1213 +    break;
  1.1214 +
  1.1215 +    // remaining possibilities in descending order of frequency of use
  1.1216 +  case eCSSUnit_Auto:
  1.1217 +    if (aMask & SETDSC_AUTO) {
  1.1218 +      aField = aAutoValue;
  1.1219 +      return;
  1.1220 +    }
  1.1221 +    break;
  1.1222 +
  1.1223 +  case eCSSUnit_None:
  1.1224 +    if (aMask & SETDSC_NONE) {
  1.1225 +      aField = aNoneValue;
  1.1226 +      return;
  1.1227 +    }
  1.1228 +    break;
  1.1229 +
  1.1230 +  case eCSSUnit_Normal:
  1.1231 +    if (aMask & SETDSC_NORMAL) {
  1.1232 +      aField = aNormalValue;
  1.1233 +      return;
  1.1234 +    }
  1.1235 +    break;
  1.1236 +
  1.1237 +  case eCSSUnit_System_Font:
  1.1238 +    if (aMask & SETDSC_SYSTEM_FONT) {
  1.1239 +      aField = aSystemFontValue;
  1.1240 +      return;
  1.1241 +    }
  1.1242 +    break;
  1.1243 +
  1.1244 +  case eCSSUnit_Unset:
  1.1245 +    if (aMask & SETDSC_UNSET_INHERIT) {
  1.1246 +      aCanStoreInRuleTree = false;
  1.1247 +      aField = aParentValue;
  1.1248 +      return;
  1.1249 +    }
  1.1250 +    if (aMask & SETDSC_UNSET_INITIAL) {
  1.1251 +      aField = aInitialValue;
  1.1252 +      return;
  1.1253 +    }
  1.1254 +    break;
  1.1255 +
  1.1256 +  default:
  1.1257 +    break;
  1.1258 +  }
  1.1259 +
  1.1260 +  NS_NOTREACHED("SetDiscrete: inappropriate unit");
  1.1261 +}
  1.1262 +
  1.1263 +// flags for SetFactor
  1.1264 +#define SETFCT_POSITIVE 0x01        // assert value is >= 0.0f
  1.1265 +#define SETFCT_OPACITY  0x02        // clamp value to [0.0f .. 1.0f]
  1.1266 +#define SETFCT_NONE     0x04        // allow _None (uses aInitialValue).
  1.1267 +#define SETFCT_UNSET_INHERIT  0x00400000
  1.1268 +#define SETFCT_UNSET_INITIAL  0x00800000
  1.1269 +
  1.1270 +static void
  1.1271 +SetFactor(const nsCSSValue& aValue, float& aField, bool& aCanStoreInRuleTree,
  1.1272 +          float aParentValue, float aInitialValue, uint32_t aFlags = 0)
  1.1273 +{
  1.1274 +  switch (aValue.GetUnit()) {
  1.1275 +  case eCSSUnit_Null:
  1.1276 +    return;
  1.1277 +
  1.1278 +  case eCSSUnit_Number:
  1.1279 +    aField = aValue.GetFloatValue();
  1.1280 +    if (aFlags & SETFCT_POSITIVE) {
  1.1281 +      NS_ASSERTION(aField >= 0.0f, "negative value for positive-only property");
  1.1282 +      if (aField < 0.0f)
  1.1283 +        aField = 0.0f;
  1.1284 +    }
  1.1285 +    if (aFlags & SETFCT_OPACITY) {
  1.1286 +      if (aField < 0.0f)
  1.1287 +        aField = 0.0f;
  1.1288 +      if (aField > 1.0f)
  1.1289 +        aField = 1.0f;
  1.1290 +    }
  1.1291 +    return;
  1.1292 +
  1.1293 +  case eCSSUnit_Inherit:
  1.1294 +    aCanStoreInRuleTree = false;
  1.1295 +    aField = aParentValue;
  1.1296 +    return;
  1.1297 +
  1.1298 +  case eCSSUnit_Initial:
  1.1299 +    aField = aInitialValue;
  1.1300 +    return;
  1.1301 +
  1.1302 +  case eCSSUnit_None:
  1.1303 +    if (aFlags & SETFCT_NONE) {
  1.1304 +      aField = aInitialValue;
  1.1305 +      return;
  1.1306 +    }
  1.1307 +    break;
  1.1308 +
  1.1309 +  case eCSSUnit_Unset:
  1.1310 +    if (aFlags & SETFCT_UNSET_INHERIT) {
  1.1311 +      aCanStoreInRuleTree = false;
  1.1312 +      aField = aParentValue;
  1.1313 +      return;
  1.1314 +    }
  1.1315 +    if (aFlags & SETFCT_UNSET_INITIAL) {
  1.1316 +      aField = aInitialValue;
  1.1317 +      return;
  1.1318 +    }
  1.1319 +    break;
  1.1320 +
  1.1321 +  default:
  1.1322 +    break;
  1.1323 +  }
  1.1324 +
  1.1325 +  NS_NOTREACHED("SetFactor: inappropriate unit");
  1.1326 +}
  1.1327 +
  1.1328 +// Overloaded new operator. Initializes the memory to 0 and relies on an arena
  1.1329 +// (which comes from the presShell) to perform the allocation.
  1.1330 +void*
  1.1331 +nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
  1.1332 +{
  1.1333 +  // Check the recycle list first.
  1.1334 +  return aPresContext->PresShell()->AllocateByObjectID(nsPresArena::nsRuleNode_id, sz);
  1.1335 +}
  1.1336 +
  1.1337 +/* static */ PLDHashOperator
  1.1338 +nsRuleNode::EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
  1.1339 +                                    uint32_t number, void *arg)
  1.1340 +{
  1.1341 +  ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
  1.1342 +  nsRuleNode ***destroyQueueTail = static_cast<nsRuleNode***>(arg);
  1.1343 +  **destroyQueueTail = entry->mRuleNode;
  1.1344 +  *destroyQueueTail = &entry->mRuleNode->mNextSibling;
  1.1345 +  return PL_DHASH_NEXT;
  1.1346 +}
  1.1347 +
  1.1348 +// Overridden to prevent the global delete from being called, since the memory
  1.1349 +// came out of an nsIArena instead of the global delete operator's heap.
  1.1350 +void
  1.1351 +nsRuleNode::DestroyInternal(nsRuleNode ***aDestroyQueueTail)
  1.1352 +{
  1.1353 +  nsRuleNode *destroyQueue, **destroyQueueTail;
  1.1354 +  if (aDestroyQueueTail) {
  1.1355 +    destroyQueueTail = *aDestroyQueueTail;
  1.1356 +  } else {
  1.1357 +    destroyQueue = nullptr;
  1.1358 +    destroyQueueTail = &destroyQueue;
  1.1359 +  }
  1.1360 +
  1.1361 +  if (ChildrenAreHashed()) {
  1.1362 +    PLDHashTable *children = ChildrenHash();
  1.1363 +    PL_DHashTableEnumerate(children, EnqueueRuleNodeChildren,
  1.1364 +                           &destroyQueueTail);
  1.1365 +    *destroyQueueTail = nullptr; // ensure null-termination
  1.1366 +    PL_DHashTableDestroy(children);
  1.1367 +  } else if (HaveChildren()) {
  1.1368 +    *destroyQueueTail = ChildrenList();
  1.1369 +    do {
  1.1370 +      destroyQueueTail = &(*destroyQueueTail)->mNextSibling;
  1.1371 +    } while (*destroyQueueTail);
  1.1372 +  }
  1.1373 +  mChildren.asVoid = nullptr;
  1.1374 +
  1.1375 +  if (aDestroyQueueTail) {
  1.1376 +    // Our caller destroys the queue.
  1.1377 +    *aDestroyQueueTail = destroyQueueTail;
  1.1378 +  } else {
  1.1379 +    // We have to do destroy the queue.  When we destroy each node, it
  1.1380 +    // will add its children to the queue.
  1.1381 +    while (destroyQueue) {
  1.1382 +      nsRuleNode *cur = destroyQueue;
  1.1383 +      destroyQueue = destroyQueue->mNextSibling;
  1.1384 +      if (!destroyQueue) {
  1.1385 +        NS_ASSERTION(destroyQueueTail == &cur->mNextSibling, "mangled list");
  1.1386 +        destroyQueueTail = &destroyQueue;
  1.1387 +      }
  1.1388 +      cur->DestroyInternal(&destroyQueueTail);
  1.1389 +    }
  1.1390 +  }
  1.1391 +
  1.1392 +  // Destroy ourselves.
  1.1393 +  this->~nsRuleNode();
  1.1394 +
  1.1395 +  // Don't let the memory be freed, since it will be recycled
  1.1396 +  // instead. Don't call the global operator delete.
  1.1397 +  mPresContext->PresShell()->FreeByObjectID(nsPresArena::nsRuleNode_id, this);
  1.1398 +}
  1.1399 +
  1.1400 +nsRuleNode* nsRuleNode::CreateRootNode(nsPresContext* aPresContext)
  1.1401 +{
  1.1402 +  return new (aPresContext)
  1.1403 +    nsRuleNode(aPresContext, nullptr, nullptr, 0xff, false);
  1.1404 +}
  1.1405 +
  1.1406 +nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
  1.1407 +                       nsIStyleRule* aRule, uint8_t aLevel,
  1.1408 +                       bool aIsImportant)
  1.1409 +  : mPresContext(aContext),
  1.1410 +    mParent(aParent),
  1.1411 +    mRule(aRule),
  1.1412 +    mDependentBits((uint32_t(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
  1.1413 +                   (aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
  1.1414 +    mNoneBits(0),
  1.1415 +    mRefCnt(0)
  1.1416 +{
  1.1417 +  MOZ_ASSERT(aContext);
  1.1418 +  NS_ABORT_IF_FALSE(IsRoot() == !aRule,
  1.1419 +                    "non-root rule nodes must have a rule");
  1.1420 +
  1.1421 +  mChildren.asVoid = nullptr;
  1.1422 +  MOZ_COUNT_CTOR(nsRuleNode);
  1.1423 +
  1.1424 +  if (mRule) {
  1.1425 +    mRule->AddRef();
  1.1426 +  }
  1.1427 +
  1.1428 +  NS_ASSERTION(IsRoot() || GetLevel() == aLevel, "not enough bits");
  1.1429 +  NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes");
  1.1430 +  /* If IsRoot(), then aContext->StyleSet() is typically null at this
  1.1431 +     point.  In any case, we don't want to treat the root rulenode as
  1.1432 +     unused.  */
  1.1433 +  if (!IsRoot()) {
  1.1434 +    mParent->AddRef();
  1.1435 +    aContext->StyleSet()->RuleNodeUnused();
  1.1436 +  }
  1.1437 +
  1.1438 +  // nsStyleSet::GetContext depends on there being only one animation
  1.1439 +  // rule.
  1.1440 +  NS_ABORT_IF_FALSE(IsRoot() || GetLevel() != nsStyleSet::eAnimationSheet ||
  1.1441 +                    mParent->IsRoot() ||
  1.1442 +                    mParent->GetLevel() != nsStyleSet::eAnimationSheet,
  1.1443 +                    "must be only one rule at animation level");
  1.1444 +}
  1.1445 +
  1.1446 +nsRuleNode::~nsRuleNode()
  1.1447 +{
  1.1448 +  MOZ_COUNT_DTOR(nsRuleNode);
  1.1449 +  if (mStyleData.mResetData || mStyleData.mInheritedData)
  1.1450 +    mStyleData.Destroy(mDependentBits, mPresContext);
  1.1451 +  if (mRule) {
  1.1452 +    mRule->Release();
  1.1453 +  }
  1.1454 +}
  1.1455 +
  1.1456 +nsRuleNode*
  1.1457 +nsRuleNode::Transition(nsIStyleRule* aRule, uint8_t aLevel,
  1.1458 +                       bool aIsImportantRule)
  1.1459 +{
  1.1460 +  nsRuleNode* next = nullptr;
  1.1461 +  nsRuleNode::Key key(aRule, aLevel, aIsImportantRule);
  1.1462 +
  1.1463 +  if (HaveChildren() && !ChildrenAreHashed()) {
  1.1464 +    int32_t numKids = 0;
  1.1465 +    nsRuleNode* curr = ChildrenList();
  1.1466 +    while (curr && curr->GetKey() != key) {
  1.1467 +      curr = curr->mNextSibling;
  1.1468 +      ++numKids;
  1.1469 +    }
  1.1470 +    if (curr)
  1.1471 +      next = curr;
  1.1472 +    else if (numKids >= kMaxChildrenInList)
  1.1473 +      ConvertChildrenToHash();
  1.1474 +  }
  1.1475 +
  1.1476 +  if (ChildrenAreHashed()) {
  1.1477 +    ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>
  1.1478 +                                          (PL_DHashTableOperate(ChildrenHash(), &key, PL_DHASH_ADD));
  1.1479 +    if (!entry) {
  1.1480 +      NS_WARNING("out of memory");
  1.1481 +      return this;
  1.1482 +    }
  1.1483 +    if (entry->mRuleNode)
  1.1484 +      next = entry->mRuleNode;
  1.1485 +    else {
  1.1486 +      next = entry->mRuleNode = new (mPresContext)
  1.1487 +        nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
  1.1488 +      if (!next) {
  1.1489 +        PL_DHashTableRawRemove(ChildrenHash(), entry);
  1.1490 +        NS_WARNING("out of memory");
  1.1491 +        return this;
  1.1492 +      }
  1.1493 +    }
  1.1494 +  } else if (!next) {
  1.1495 +    // Create the new entry in our list.
  1.1496 +    next = new (mPresContext)
  1.1497 +      nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
  1.1498 +    if (!next) {
  1.1499 +      NS_WARNING("out of memory");
  1.1500 +      return this;
  1.1501 +    }
  1.1502 +    next->mNextSibling = ChildrenList();
  1.1503 +    SetChildrenList(next);
  1.1504 +  }
  1.1505 +
  1.1506 +  return next;
  1.1507 +}
  1.1508 +
  1.1509 +void nsRuleNode::SetUsedDirectly()
  1.1510 +{
  1.1511 +  mDependentBits |= NS_RULE_NODE_USED_DIRECTLY;
  1.1512 +
  1.1513 +  // Maintain the invariant that any rule node that is used directly has
  1.1514 +  // all structs that live in the rule tree cached (which
  1.1515 +  // nsRuleNode::GetStyleData depends on for speed).
  1.1516 +  if (mDependentBits & NS_STYLE_INHERIT_MASK) {
  1.1517 +    for (nsStyleStructID sid = nsStyleStructID(0); sid < nsStyleStructID_Length;
  1.1518 +         sid = nsStyleStructID(sid + 1)) {
  1.1519 +      uint32_t bit = nsCachedStyleData::GetBitForSID(sid);
  1.1520 +      if (mDependentBits & bit) {
  1.1521 +        nsRuleNode *source = mParent;
  1.1522 +        while ((source->mDependentBits & bit) && !source->IsUsedDirectly()) {
  1.1523 +          source = source->mParent;
  1.1524 +        }
  1.1525 +        void *data = source->mStyleData.GetStyleData(sid);
  1.1526 +        NS_ASSERTION(data, "unexpected null struct");
  1.1527 +        mStyleData.SetStyleData(sid, mPresContext, data);
  1.1528 +      }
  1.1529 +    }
  1.1530 +  }
  1.1531 +}
  1.1532 +
  1.1533 +void
  1.1534 +nsRuleNode::ConvertChildrenToHash()
  1.1535 +{
  1.1536 +  NS_ASSERTION(!ChildrenAreHashed() && HaveChildren(),
  1.1537 +               "must have a non-empty list of children");
  1.1538 +  PLDHashTable *hash = PL_NewDHashTable(&ChildrenHashOps, nullptr,
  1.1539 +                                        sizeof(ChildrenHashEntry),
  1.1540 +                                        kMaxChildrenInList * 4);
  1.1541 +  if (!hash)
  1.1542 +    return;
  1.1543 +  for (nsRuleNode* curr = ChildrenList(); curr; curr = curr->mNextSibling) {
  1.1544 +    // This will never fail because of the initial size we gave the table.
  1.1545 +    ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(
  1.1546 +      PL_DHashTableOperate(hash, curr->mRule, PL_DHASH_ADD));
  1.1547 +    NS_ASSERTION(!entry->mRuleNode, "duplicate entries in list");
  1.1548 +    entry->mRuleNode = curr;
  1.1549 +  }
  1.1550 +  SetChildrenHash(hash);
  1.1551 +}
  1.1552 +
  1.1553 +inline void
  1.1554 +nsRuleNode::PropagateNoneBit(uint32_t aBit, nsRuleNode* aHighestNode)
  1.1555 +{
  1.1556 +  nsRuleNode* curr = this;
  1.1557 +  for (;;) {
  1.1558 +    NS_ASSERTION(!(curr->mNoneBits & aBit), "propagating too far");
  1.1559 +    curr->mNoneBits |= aBit;
  1.1560 +    if (curr == aHighestNode)
  1.1561 +      break;
  1.1562 +    curr = curr->mParent;
  1.1563 +  }
  1.1564 +}
  1.1565 +
  1.1566 +inline void
  1.1567 +nsRuleNode::PropagateDependentBit(nsStyleStructID aSID, nsRuleNode* aHighestNode,
  1.1568 +                                  void* aStruct)
  1.1569 +{
  1.1570 +  NS_ASSERTION(aStruct, "expected struct");
  1.1571 +
  1.1572 +  uint32_t bit = nsCachedStyleData::GetBitForSID(aSID);
  1.1573 +  for (nsRuleNode* curr = this; curr != aHighestNode; curr = curr->mParent) {
  1.1574 +    if (curr->mDependentBits & bit) {
  1.1575 +#ifdef DEBUG
  1.1576 +      while (curr != aHighestNode) {
  1.1577 +        NS_ASSERTION(curr->mDependentBits & bit, "bit not set");
  1.1578 +        curr = curr->mParent;
  1.1579 +      }
  1.1580 +#endif
  1.1581 +      break;
  1.1582 +    }
  1.1583 +
  1.1584 +    curr->mDependentBits |= bit;
  1.1585 +
  1.1586 +    if (curr->IsUsedDirectly()) {
  1.1587 +      curr->mStyleData.SetStyleData(aSID, mPresContext, aStruct);
  1.1588 +    }
  1.1589 +  }
  1.1590 +}
  1.1591 +
  1.1592 +/*
  1.1593 + * The following "Check" functions are used for determining what type of
  1.1594 + * sharing can be used for the data on this rule node.  MORE HERE...
  1.1595 + */
  1.1596 +
  1.1597 +/*
  1.1598 + * a callback function that that can revise the result of
  1.1599 + * CheckSpecifiedProperties before finishing; aResult is the current
  1.1600 + * result, and it returns the revised one.
  1.1601 + */
  1.1602 +typedef nsRuleNode::RuleDetail
  1.1603 +  (* CheckCallbackFn)(const nsRuleData* aRuleData,
  1.1604 +                      nsRuleNode::RuleDetail aResult);
  1.1605 +
  1.1606 +/**
  1.1607 + * @param aValue the value being examined
  1.1608 + * @param aSpecifiedCount to be incremented by one if the value is specified
  1.1609 + * @param aInheritedCount to be incremented by one if the value is set to inherit
  1.1610 + * @param aUnsetCount to be incremented by one if the value is set to unset
  1.1611 + */
  1.1612 +inline void
  1.1613 +ExamineCSSValue(const nsCSSValue& aValue,
  1.1614 +                uint32_t& aSpecifiedCount,
  1.1615 +                uint32_t& aInheritedCount,
  1.1616 +                uint32_t& aUnsetCount)
  1.1617 +{
  1.1618 +  if (aValue.GetUnit() != eCSSUnit_Null) {
  1.1619 +    ++aSpecifiedCount;
  1.1620 +    if (aValue.GetUnit() == eCSSUnit_Inherit) {
  1.1621 +      ++aInheritedCount;
  1.1622 +    } else if (aValue.GetUnit() == eCSSUnit_Unset) {
  1.1623 +      ++aUnsetCount;
  1.1624 +    }
  1.1625 +  }
  1.1626 +}
  1.1627 +
  1.1628 +static nsRuleNode::RuleDetail
  1.1629 +CheckFontCallback(const nsRuleData* aRuleData,
  1.1630 +                  nsRuleNode::RuleDetail aResult)
  1.1631 +{
  1.1632 +  // em, ex, percent, 'larger', and 'smaller' values on font-size depend
  1.1633 +  // on the parent context's font-size
  1.1634 +  // Likewise, 'lighter' and 'bolder' values of 'font-weight', and 'wider'
  1.1635 +  // and 'narrower' values of 'font-stretch' depend on the parent.
  1.1636 +  const nsCSSValue& size = *aRuleData->ValueForFontSize();
  1.1637 +  const nsCSSValue& weight = *aRuleData->ValueForFontWeight();
  1.1638 +  if ((size.IsRelativeLengthUnit() && size.GetUnit() != eCSSUnit_RootEM) ||
  1.1639 +      size.GetUnit() == eCSSUnit_Percent ||
  1.1640 +      (size.GetUnit() == eCSSUnit_Enumerated &&
  1.1641 +       (size.GetIntValue() == NS_STYLE_FONT_SIZE_SMALLER ||
  1.1642 +        size.GetIntValue() == NS_STYLE_FONT_SIZE_LARGER)) ||
  1.1643 +      aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Integer ||
  1.1644 +      (weight.GetUnit() == eCSSUnit_Enumerated &&
  1.1645 +       (weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_BOLDER ||
  1.1646 +        weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_LIGHTER))) {
  1.1647 +    NS_ASSERTION(aResult == nsRuleNode::eRulePartialReset ||
  1.1648 +                 aResult == nsRuleNode::eRuleFullReset ||
  1.1649 +                 aResult == nsRuleNode::eRulePartialMixed ||
  1.1650 +                 aResult == nsRuleNode::eRuleFullMixed,
  1.1651 +                 "we know we already have a reset-counted property");
  1.1652 +    // Promote reset to mixed since we have something that depends on
  1.1653 +    // the parent.  But never promote to inherited since that could
  1.1654 +    // cause inheritance of the exact value.
  1.1655 +    if (aResult == nsRuleNode::eRulePartialReset)
  1.1656 +      aResult = nsRuleNode::eRulePartialMixed;
  1.1657 +    else if (aResult == nsRuleNode::eRuleFullReset)
  1.1658 +      aResult = nsRuleNode::eRuleFullMixed;
  1.1659 +  }
  1.1660 +
  1.1661 +  return aResult;
  1.1662 +}
  1.1663 +
  1.1664 +static nsRuleNode::RuleDetail
  1.1665 +CheckColorCallback(const nsRuleData* aRuleData,
  1.1666 +                   nsRuleNode::RuleDetail aResult)
  1.1667 +{
  1.1668 +  // currentColor values for color require inheritance
  1.1669 +  const nsCSSValue* colorValue = aRuleData->ValueForColor();
  1.1670 +  if (colorValue->GetUnit() == eCSSUnit_EnumColor &&
  1.1671 +      colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
  1.1672 +    NS_ASSERTION(aResult == nsRuleNode::eRuleFullReset,
  1.1673 +                 "we should already be counted as full-reset");
  1.1674 +    aResult = nsRuleNode::eRuleFullInherited;
  1.1675 +  }
  1.1676 +
  1.1677 +  return aResult;
  1.1678 +}
  1.1679 +
  1.1680 +static nsRuleNode::RuleDetail
  1.1681 +CheckTextCallback(const nsRuleData* aRuleData,
  1.1682 +                  nsRuleNode::RuleDetail aResult)
  1.1683 +{
  1.1684 +  const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
  1.1685 +  if (textAlignValue->GetUnit() == eCSSUnit_Enumerated &&
  1.1686 +      textAlignValue->GetIntValue() ==
  1.1687 +        NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT) {
  1.1688 +    // Promote reset to mixed since we have something that depends on
  1.1689 +    // the parent.
  1.1690 +    if (aResult == nsRuleNode::eRulePartialReset)
  1.1691 +      aResult = nsRuleNode::eRulePartialMixed;
  1.1692 +    else if (aResult == nsRuleNode::eRuleFullReset)
  1.1693 +      aResult = nsRuleNode::eRuleFullMixed;
  1.1694 +  }
  1.1695 +
  1.1696 +  return aResult;
  1.1697 +}
  1.1698 +
  1.1699 +static nsRuleNode::RuleDetail
  1.1700 +CheckVariablesCallback(const nsRuleData* aRuleData,
  1.1701 +                       nsRuleNode::RuleDetail aResult)
  1.1702 +{
  1.1703 +  // We don't actually have any properties on nsStyleVariables, so we do
  1.1704 +  // all of the RuleDetail calculation in here.
  1.1705 +  if (aRuleData->mVariables) {
  1.1706 +    return nsRuleNode::eRulePartialMixed;
  1.1707 +  }
  1.1708 +  return nsRuleNode::eRuleNone;
  1.1709 +}
  1.1710 +
  1.1711 +#define FLAG_DATA_FOR_PROPERTY(name_, id_, method_, flags_, pref_,          \
  1.1712 +                               parsevariant_, kwtable_, stylestructoffset_, \
  1.1713 +                               animtype_)                                   \
  1.1714 +  flags_,
  1.1715 +
  1.1716 +// The order here must match the enums in *CheckCounter in nsCSSProps.cpp.
  1.1717 +
  1.1718 +static const uint32_t gFontFlags[] = {
  1.1719 +#define CSS_PROP_FONT FLAG_DATA_FOR_PROPERTY
  1.1720 +#include "nsCSSPropList.h"
  1.1721 +#undef CSS_PROP_FONT
  1.1722 +};
  1.1723 +
  1.1724 +static const uint32_t gDisplayFlags[] = {
  1.1725 +#define CSS_PROP_DISPLAY FLAG_DATA_FOR_PROPERTY
  1.1726 +#include "nsCSSPropList.h"
  1.1727 +#undef CSS_PROP_DISPLAY
  1.1728 +};
  1.1729 +
  1.1730 +static const uint32_t gVisibilityFlags[] = {
  1.1731 +#define CSS_PROP_VISIBILITY FLAG_DATA_FOR_PROPERTY
  1.1732 +#include "nsCSSPropList.h"
  1.1733 +#undef CSS_PROP_VISIBILITY
  1.1734 +};
  1.1735 +
  1.1736 +static const uint32_t gMarginFlags[] = {
  1.1737 +#define CSS_PROP_MARGIN FLAG_DATA_FOR_PROPERTY
  1.1738 +#include "nsCSSPropList.h"
  1.1739 +#undef CSS_PROP_MARGIN
  1.1740 +};
  1.1741 +
  1.1742 +static const uint32_t gBorderFlags[] = {
  1.1743 +#define CSS_PROP_BORDER FLAG_DATA_FOR_PROPERTY
  1.1744 +#include "nsCSSPropList.h"
  1.1745 +#undef CSS_PROP_BORDER
  1.1746 +};
  1.1747 +
  1.1748 +static const uint32_t gPaddingFlags[] = {
  1.1749 +#define CSS_PROP_PADDING FLAG_DATA_FOR_PROPERTY
  1.1750 +#include "nsCSSPropList.h"
  1.1751 +#undef CSS_PROP_PADDING
  1.1752 +};
  1.1753 +
  1.1754 +static const uint32_t gOutlineFlags[] = {
  1.1755 +#define CSS_PROP_OUTLINE FLAG_DATA_FOR_PROPERTY
  1.1756 +#include "nsCSSPropList.h"
  1.1757 +#undef CSS_PROP_OUTLINE
  1.1758 +};
  1.1759 +
  1.1760 +static const uint32_t gListFlags[] = {
  1.1761 +#define CSS_PROP_LIST FLAG_DATA_FOR_PROPERTY
  1.1762 +#include "nsCSSPropList.h"
  1.1763 +#undef CSS_PROP_LIST
  1.1764 +};
  1.1765 +
  1.1766 +static const uint32_t gColorFlags[] = {
  1.1767 +#define CSS_PROP_COLOR FLAG_DATA_FOR_PROPERTY
  1.1768 +#include "nsCSSPropList.h"
  1.1769 +#undef CSS_PROP_COLOR
  1.1770 +};
  1.1771 +
  1.1772 +static const uint32_t gBackgroundFlags[] = {
  1.1773 +#define CSS_PROP_BACKGROUND FLAG_DATA_FOR_PROPERTY
  1.1774 +#include "nsCSSPropList.h"
  1.1775 +#undef CSS_PROP_BACKGROUND
  1.1776 +};
  1.1777 +
  1.1778 +static const uint32_t gPositionFlags[] = {
  1.1779 +#define CSS_PROP_POSITION FLAG_DATA_FOR_PROPERTY
  1.1780 +#include "nsCSSPropList.h"
  1.1781 +#undef CSS_PROP_POSITION
  1.1782 +};
  1.1783 +
  1.1784 +static const uint32_t gTableFlags[] = {
  1.1785 +#define CSS_PROP_TABLE FLAG_DATA_FOR_PROPERTY
  1.1786 +#include "nsCSSPropList.h"
  1.1787 +#undef CSS_PROP_TABLE
  1.1788 +};
  1.1789 +
  1.1790 +static const uint32_t gTableBorderFlags[] = {
  1.1791 +#define CSS_PROP_TABLEBORDER FLAG_DATA_FOR_PROPERTY
  1.1792 +#include "nsCSSPropList.h"
  1.1793 +#undef CSS_PROP_TABLEBORDER
  1.1794 +};
  1.1795 +
  1.1796 +static const uint32_t gContentFlags[] = {
  1.1797 +#define CSS_PROP_CONTENT FLAG_DATA_FOR_PROPERTY
  1.1798 +#include "nsCSSPropList.h"
  1.1799 +#undef CSS_PROP_CONTENT
  1.1800 +};
  1.1801 +
  1.1802 +static const uint32_t gQuotesFlags[] = {
  1.1803 +#define CSS_PROP_QUOTES FLAG_DATA_FOR_PROPERTY
  1.1804 +#include "nsCSSPropList.h"
  1.1805 +#undef CSS_PROP_QUOTES
  1.1806 +};
  1.1807 +
  1.1808 +static const uint32_t gTextFlags[] = {
  1.1809 +#define CSS_PROP_TEXT FLAG_DATA_FOR_PROPERTY
  1.1810 +#include "nsCSSPropList.h"
  1.1811 +#undef CSS_PROP_TEXT
  1.1812 +};
  1.1813 +
  1.1814 +static const uint32_t gTextResetFlags[] = {
  1.1815 +#define CSS_PROP_TEXTRESET FLAG_DATA_FOR_PROPERTY
  1.1816 +#include "nsCSSPropList.h"
  1.1817 +#undef CSS_PROP_TEXTRESET
  1.1818 +};
  1.1819 +
  1.1820 +static const uint32_t gUserInterfaceFlags[] = {
  1.1821 +#define CSS_PROP_USERINTERFACE FLAG_DATA_FOR_PROPERTY
  1.1822 +#include "nsCSSPropList.h"
  1.1823 +#undef CSS_PROP_USERINTERFACE
  1.1824 +};
  1.1825 +
  1.1826 +static const uint32_t gUIResetFlags[] = {
  1.1827 +#define CSS_PROP_UIRESET FLAG_DATA_FOR_PROPERTY
  1.1828 +#include "nsCSSPropList.h"
  1.1829 +#undef CSS_PROP_UIRESET
  1.1830 +};
  1.1831 +
  1.1832 +static const uint32_t gXULFlags[] = {
  1.1833 +#define CSS_PROP_XUL FLAG_DATA_FOR_PROPERTY
  1.1834 +#include "nsCSSPropList.h"
  1.1835 +#undef CSS_PROP_XUL
  1.1836 +};
  1.1837 +
  1.1838 +static const uint32_t gSVGFlags[] = {
  1.1839 +#define CSS_PROP_SVG FLAG_DATA_FOR_PROPERTY
  1.1840 +#include "nsCSSPropList.h"
  1.1841 +#undef CSS_PROP_SVG
  1.1842 +};
  1.1843 +
  1.1844 +static const uint32_t gSVGResetFlags[] = {
  1.1845 +#define CSS_PROP_SVGRESET FLAG_DATA_FOR_PROPERTY
  1.1846 +#include "nsCSSPropList.h"
  1.1847 +#undef CSS_PROP_SVGRESET
  1.1848 +};
  1.1849 +
  1.1850 +static const uint32_t gColumnFlags[] = {
  1.1851 +#define CSS_PROP_COLUMN FLAG_DATA_FOR_PROPERTY
  1.1852 +#include "nsCSSPropList.h"
  1.1853 +#undef CSS_PROP_COLUMN
  1.1854 +};
  1.1855 +
  1.1856 +// There are no properties in nsStyleVariables, but we can't have a
  1.1857 +// zero length array.
  1.1858 +static const uint32_t gVariablesFlags[] = {
  1.1859 +  0,
  1.1860 +#define CSS_PROP_VARIABLES FLAG_DATA_FOR_PROPERTY
  1.1861 +#include "nsCSSPropList.h"
  1.1862 +#undef CSS_PROP_VARIABLES
  1.1863 +};
  1.1864 +static_assert(sizeof(gVariablesFlags) == sizeof(uint32_t),
  1.1865 +              "if nsStyleVariables has properties now you can remove the dummy "
  1.1866 +              "gVariablesFlags entry");
  1.1867 +
  1.1868 +#undef FLAG_DATA_FOR_PROPERTY
  1.1869 +
  1.1870 +static const uint32_t* gFlagsByStruct[] = {
  1.1871 +
  1.1872 +#define STYLE_STRUCT(name, checkdata_cb) \
  1.1873 +  g##name##Flags,
  1.1874 +#include "nsStyleStructList.h"
  1.1875 +#undef STYLE_STRUCT
  1.1876 +
  1.1877 +};
  1.1878 +
  1.1879 +static const CheckCallbackFn gCheckCallbacks[] = {
  1.1880 +
  1.1881 +#define STYLE_STRUCT(name, checkdata_cb) \
  1.1882 +  checkdata_cb,
  1.1883 +#include "nsStyleStructList.h"
  1.1884 +#undef STYLE_STRUCT
  1.1885 +
  1.1886 +};
  1.1887 +
  1.1888 +#ifdef DEBUG
  1.1889 +static bool
  1.1890 +AreAllMathMLPropertiesUndefined(const nsRuleData* aRuleData)
  1.1891 +{
  1.1892 +  return
  1.1893 +    aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Null &&
  1.1894 +    aRuleData->ValueForScriptSizeMultiplier()->GetUnit() == eCSSUnit_Null &&
  1.1895 +    aRuleData->ValueForScriptMinSize()->GetUnit() == eCSSUnit_Null &&
  1.1896 +    aRuleData->ValueForMathVariant()->GetUnit() == eCSSUnit_Null &&
  1.1897 +    aRuleData->ValueForMathDisplay()->GetUnit() == eCSSUnit_Null;
  1.1898 +}
  1.1899 +#endif
  1.1900 +
  1.1901 +inline nsRuleNode::RuleDetail
  1.1902 +nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID,
  1.1903 +                                     const nsRuleData* aRuleData)
  1.1904 +{
  1.1905 +  // Build a count of the:
  1.1906 +  uint32_t total = 0,      // total number of props in the struct
  1.1907 +           specified = 0,  // number that were specified for this node
  1.1908 +           inherited = 0,  // number that were 'inherit' (and not
  1.1909 +                           //   eCSSUnit_Inherit) for this node
  1.1910 +           unset = 0;      // number that were 'unset'
  1.1911 +
  1.1912 +  // See comment in nsRuleData.h above mValueOffsets.
  1.1913 +  NS_ABORT_IF_FALSE(aRuleData->mValueOffsets[aSID] == 0,
  1.1914 +                    "we assume the value offset is zero instead of adding it");
  1.1915 +  for (nsCSSValue *values = aRuleData->mValueStorage,
  1.1916 +              *values_end = values + nsCSSProps::PropertyCountInStruct(aSID);
  1.1917 +       values != values_end; ++values) {
  1.1918 +    ++total;
  1.1919 +    ExamineCSSValue(*values, specified, inherited, unset);
  1.1920 +  }
  1.1921 +
  1.1922 +  if (!nsCachedStyleData::IsReset(aSID)) {
  1.1923 +    // For inherited properties, 'unset' means the same as 'inherit'.
  1.1924 +    inherited += unset;
  1.1925 +    unset = 0;
  1.1926 +  }
  1.1927 +
  1.1928 +#if 0
  1.1929 +  printf("CheckSpecifiedProperties: SID=%d total=%d spec=%d inh=%d.\n",
  1.1930 +         aSID, total, specified, inherited);
  1.1931 +#endif
  1.1932 +
  1.1933 +  NS_ASSERTION(aSID != eStyleStruct_Font ||
  1.1934 +               mPresContext->Document()->GetMathMLEnabled() ||
  1.1935 +               AreAllMathMLPropertiesUndefined(aRuleData),
  1.1936 +               "MathML style property was defined even though MathML is disabled");
  1.1937 +
  1.1938 +  /*
  1.1939 +   * Return the most specific information we can: prefer None or Full
  1.1940 +   * over Partial, and Reset or Inherited over Mixed, since we can
  1.1941 +   * optimize based on the edge cases and not the in-between cases.
  1.1942 +   */
  1.1943 +  nsRuleNode::RuleDetail result;
  1.1944 +  if (inherited == total)
  1.1945 +    result = eRuleFullInherited;
  1.1946 +  else if (specified == total
  1.1947 +           // MathML defines 5 properties in Font that will never be set when
  1.1948 +           // MathML is not in use. Therefore if all but five
  1.1949 +           // properties have been set, and MathML is not enabled, we can treat
  1.1950 +           // this as fully specified. Code in nsMathMLElementFactory will
  1.1951 +           // rebuild the rule tree and style data when MathML is first enabled
  1.1952 +           // (see nsMathMLElement::BindToTree).
  1.1953 +           || (aSID == eStyleStruct_Font && specified + 5 == total &&
  1.1954 +               !mPresContext->Document()->GetMathMLEnabled())
  1.1955 +          ) {
  1.1956 +    if (inherited == 0)
  1.1957 +      result = eRuleFullReset;
  1.1958 +    else
  1.1959 +      result = eRuleFullMixed;
  1.1960 +  } else if (specified == 0)
  1.1961 +    result = eRuleNone;
  1.1962 +  else if (specified == inherited)
  1.1963 +    result = eRulePartialInherited;
  1.1964 +  else if (inherited == 0)
  1.1965 +    result = eRulePartialReset;
  1.1966 +  else
  1.1967 +    result = eRulePartialMixed;
  1.1968 +
  1.1969 +  CheckCallbackFn cb = gCheckCallbacks[aSID];
  1.1970 +  if (cb) {
  1.1971 +    result = (*cb)(aRuleData, result);
  1.1972 +  }
  1.1973 +
  1.1974 +  return result;
  1.1975 +}
  1.1976 +
  1.1977 +// If we need to restrict which properties apply to the style context,
  1.1978 +// return the bit to check in nsCSSProp's flags table.  Otherwise,
  1.1979 +// return 0.
  1.1980 +inline uint32_t
  1.1981 +GetPseudoRestriction(nsStyleContext *aContext)
  1.1982 +{
  1.1983 +  // This needs to match nsStyleSet::WalkRestrictionRule.
  1.1984 +  uint32_t pseudoRestriction = 0;
  1.1985 +  nsIAtom *pseudoType = aContext->GetPseudo();
  1.1986 +  if (pseudoType) {
  1.1987 +    if (pseudoType == nsCSSPseudoElements::firstLetter) {
  1.1988 +      pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LETTER;
  1.1989 +    } else if (pseudoType == nsCSSPseudoElements::firstLine) {
  1.1990 +      pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LINE;
  1.1991 +    } else if (pseudoType == nsCSSPseudoElements::mozPlaceholder) {
  1.1992 +      pseudoRestriction = CSS_PROPERTY_APPLIES_TO_PLACEHOLDER;
  1.1993 +    }
  1.1994 +  }
  1.1995 +  return pseudoRestriction;
  1.1996 +}
  1.1997 +
  1.1998 +static void
  1.1999 +UnsetPropertiesWithoutFlags(const nsStyleStructID aSID,
  1.2000 +                            nsRuleData* aRuleData,
  1.2001 +                            uint32_t aFlags)
  1.2002 +{
  1.2003 +  NS_ASSERTION(aFlags != 0, "aFlags must be nonzero");
  1.2004 +
  1.2005 +  const uint32_t *flagData = gFlagsByStruct[aSID];
  1.2006 +
  1.2007 +  // See comment in nsRuleData.h above mValueOffsets.
  1.2008 +  NS_ABORT_IF_FALSE(aRuleData->mValueOffsets[aSID] == 0,
  1.2009 +                    "we assume the value offset is zero instead of adding it");
  1.2010 +  nsCSSValue *values = aRuleData->mValueStorage;
  1.2011 +
  1.2012 +  for (size_t i = 0, i_end = nsCSSProps::PropertyCountInStruct(aSID);
  1.2013 +       i != i_end; ++i) {
  1.2014 +    if ((flagData[i] & aFlags) != aFlags)
  1.2015 +      values[i].Reset();
  1.2016 +  }
  1.2017 +}
  1.2018 +
  1.2019 +/**
  1.2020 + * We allocate arrays of CSS values with alloca.  (These arrays are a
  1.2021 + * fixed size per style struct, but we don't want to waste the
  1.2022 + * allocation and construction/destruction costs of the big structs when
  1.2023 + * we're handling much smaller ones.)  Since the lifetime of an alloca
  1.2024 + * allocation is the life of the calling function, the caller must call
  1.2025 + * alloca.  However, to ensure that constructors and destructors are
  1.2026 + * balanced, we do the constructor and destructor calling from this RAII
  1.2027 + * class, AutoCSSValueArray.
  1.2028 + */
  1.2029 +struct AutoCSSValueArray {
  1.2030 +  /**
  1.2031 +   * aStorage must be the result of alloca(aCount * sizeof(nsCSSValue))
  1.2032 +   */
  1.2033 +  AutoCSSValueArray(void* aStorage, size_t aCount) {
  1.2034 +    NS_ABORT_IF_FALSE(size_t(aStorage) % NS_ALIGNMENT_OF(nsCSSValue) == 0,
  1.2035 +                      "bad alignment from alloca");
  1.2036 +    mCount = aCount;
  1.2037 +    // Don't use placement new[], since it might store extra data
  1.2038 +    // for the count (on Windows!).
  1.2039 +    mArray = static_cast<nsCSSValue*>(aStorage);
  1.2040 +    for (size_t i = 0; i < mCount; ++i) {
  1.2041 +      new (mArray + i) nsCSSValue();
  1.2042 +    }
  1.2043 +  }
  1.2044 +
  1.2045 +  ~AutoCSSValueArray() {
  1.2046 +    for (size_t i = 0; i < mCount; ++i) {
  1.2047 +      mArray[i].~nsCSSValue();
  1.2048 +    }
  1.2049 +  }
  1.2050 +
  1.2051 +  nsCSSValue* get() { return mArray; }
  1.2052 +
  1.2053 +private:
  1.2054 +  nsCSSValue *mArray;
  1.2055 +  size_t mCount;
  1.2056 +};
  1.2057 +
  1.2058 +/* static */ bool
  1.2059 +nsRuleNode::ResolveVariableReferences(const nsStyleStructID aSID,
  1.2060 +                                      nsRuleData* aRuleData,
  1.2061 +                                      nsStyleContext* aContext)
  1.2062 +{
  1.2063 +  MOZ_ASSERT(aSID != eStyleStruct_Variables);
  1.2064 +  MOZ_ASSERT(aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(aSID));
  1.2065 +  MOZ_ASSERT(aRuleData->mValueOffsets[aSID] == 0);
  1.2066 +
  1.2067 +  nsCSSParser parser;
  1.2068 +  bool anyTokenStreams = false;
  1.2069 +
  1.2070 +  // Look at each property in the nsRuleData for the given style struct.
  1.2071 +  size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
  1.2072 +  for (nsCSSValue* value = aRuleData->mValueStorage,
  1.2073 +                  *values_end = aRuleData->mValueStorage + nprops;
  1.2074 +       value != values_end; value++) {
  1.2075 +    if (value->GetUnit() != eCSSUnit_TokenStream) {
  1.2076 +      continue;
  1.2077 +    }
  1.2078 +
  1.2079 +    const CSSVariableValues* variables =
  1.2080 +      &aContext->StyleVariables()->mVariables;
  1.2081 +    nsCSSValueTokenStream* tokenStream = value->GetTokenStreamValue();
  1.2082 +
  1.2083 +    // Note that ParsePropertyWithVariableReferences relies on the fact
  1.2084 +    // that the nsCSSValue in aRuleData for the property we are re-parsing
  1.2085 +    // is still the token stream value.  When
  1.2086 +    // ParsePropertyWithVariableReferences calls
  1.2087 +    // nsCSSExpandedDataBlock::MapRuleInfoInto, that function will add
  1.2088 +    // the ImageValue that is created into the token stream object's
  1.2089 +    // mImageValues table; see the comment above mImageValues for why.
  1.2090 +
  1.2091 +    // XXX Should pass in sheet here (see bug 952338).
  1.2092 +    parser.ParsePropertyWithVariableReferences(
  1.2093 +        tokenStream->mPropertyID, tokenStream->mShorthandPropertyID,
  1.2094 +        tokenStream->mTokenStream, variables, aRuleData,
  1.2095 +        tokenStream->mSheetURI, tokenStream->mBaseURI,
  1.2096 +        tokenStream->mSheetPrincipal, nullptr,
  1.2097 +        tokenStream->mLineNumber, tokenStream->mLineOffset);
  1.2098 +    aRuleData->mCanStoreInRuleTree = false;
  1.2099 +    anyTokenStreams = true;
  1.2100 +  }
  1.2101 +
  1.2102 +  return anyTokenStreams;
  1.2103 +}
  1.2104 +
  1.2105 +const void*
  1.2106 +nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
  1.2107 +                         nsStyleContext* aContext)
  1.2108 +{
  1.2109 +  // use placement new[] on the result of alloca() to allocate a
  1.2110 +  // variable-sized stack array, including execution of constructors,
  1.2111 +  // and use an RAII class to run the destructors too.
  1.2112 +  size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
  1.2113 +  void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
  1.2114 +  AutoCSSValueArray dataArray(dataStorage, nprops);
  1.2115 +
  1.2116 +  nsRuleData ruleData(nsCachedStyleData::GetBitForSID(aSID),
  1.2117 +                      dataArray.get(), mPresContext, aContext);
  1.2118 +  ruleData.mValueOffsets[aSID] = 0;
  1.2119 +
  1.2120 +  // We start at the most specific rule in the tree.
  1.2121 +  void* startStruct = nullptr;
  1.2122 +
  1.2123 +  nsRuleNode* ruleNode = this;
  1.2124 +  nsRuleNode* highestNode = nullptr; // The highest node in the rule tree
  1.2125 +                                    // that has the same properties
  1.2126 +                                    // specified for struct |aSID| as
  1.2127 +                                    // |this| does.
  1.2128 +  nsRuleNode* rootNode = this; // After the loop below, this will be the
  1.2129 +                               // highest node that we've walked without
  1.2130 +                               // finding cached data on the rule tree.
  1.2131 +                               // If we don't find any cached data, it
  1.2132 +                               // will be the root.  (XXX misnamed)
  1.2133 +  RuleDetail detail = eRuleNone;
  1.2134 +  uint32_t bit = nsCachedStyleData::GetBitForSID(aSID);
  1.2135 +
  1.2136 +  while (ruleNode) {
  1.2137 +    // See if this rule node has cached the fact that the remaining
  1.2138 +    // nodes along this path specify no data whatsoever.
  1.2139 +    if (ruleNode->mNoneBits & bit)
  1.2140 +      break;
  1.2141 +
  1.2142 +    // If the dependent bit is set on a rule node for this struct, that
  1.2143 +    // means its rule won't have any information to add, so skip it.
  1.2144 +    // NOTE: If we exit the loop because of the !IsUsedDirectly() check,
  1.2145 +    // then we're guaranteed to break immediately afterwards due to a
  1.2146 +    // non-null startStruct.
  1.2147 +    while ((ruleNode->mDependentBits & bit) && !ruleNode->IsUsedDirectly()) {
  1.2148 +      NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nullptr,
  1.2149 +                   "dependent bit with cached data makes no sense");
  1.2150 +      // Climb up to the next rule in the tree (a less specific rule).
  1.2151 +      rootNode = ruleNode;
  1.2152 +      ruleNode = ruleNode->mParent;
  1.2153 +      NS_ASSERTION(!(ruleNode->mNoneBits & bit), "can't have both bits set");
  1.2154 +    }
  1.2155 +
  1.2156 +    // Check for cached data after the inner loop above -- otherwise
  1.2157 +    // we'll miss it.
  1.2158 +    startStruct = ruleNode->mStyleData.GetStyleData(aSID);
  1.2159 +    if (startStruct)
  1.2160 +      break; // We found a rule with fully specified data.  We don't
  1.2161 +             // need to go up the tree any further, since the remainder
  1.2162 +             // of this branch has already been computed.
  1.2163 +
  1.2164 +    // Ask the rule to fill in the properties that it specifies.
  1.2165 +    nsIStyleRule *rule = ruleNode->mRule;
  1.2166 +    if (rule) {
  1.2167 +      ruleData.mLevel = ruleNode->GetLevel();
  1.2168 +      ruleData.mIsImportantRule = ruleNode->IsImportantRule();
  1.2169 +      rule->MapRuleInfoInto(&ruleData);
  1.2170 +    }
  1.2171 +
  1.2172 +    // Now we check to see how many properties have been specified by
  1.2173 +    // the rules we've examined so far.
  1.2174 +    RuleDetail oldDetail = detail;
  1.2175 +    detail = CheckSpecifiedProperties(aSID, &ruleData);
  1.2176 +
  1.2177 +    if (oldDetail == eRuleNone && detail != eRuleNone)
  1.2178 +      highestNode = ruleNode;
  1.2179 +
  1.2180 +    if (detail == eRuleFullReset ||
  1.2181 +        detail == eRuleFullMixed ||
  1.2182 +        detail == eRuleFullInherited)
  1.2183 +      break; // We don't need to examine any more rules.  All properties
  1.2184 +             // have been fully specified.
  1.2185 +
  1.2186 +    // Climb up to the next rule in the tree (a less specific rule).
  1.2187 +    rootNode = ruleNode;
  1.2188 +    ruleNode = ruleNode->mParent;
  1.2189 +  }
  1.2190 +
  1.2191 +  bool recomputeDetail = false;
  1.2192 +
  1.2193 +  // If we are computing a style struct other than nsStyleVariables, and
  1.2194 +  // ruleData has any properties with variable references (nsCSSValues of
  1.2195 +  // type eCSSUnit_TokenStream), then we need to resolve these.
  1.2196 +  if (aSID != eStyleStruct_Variables) {
  1.2197 +    // A property's value might have became 'inherit' after resolving
  1.2198 +    // variable references.  (This happens when an inherited property
  1.2199 +    // fails to parse its resolved value.)  We need to recompute
  1.2200 +    // |detail| in case this happened.
  1.2201 +    recomputeDetail = ResolveVariableReferences(aSID, &ruleData, aContext);
  1.2202 +  }
  1.2203 +
  1.2204 +  // If needed, unset the properties that don't have a flag that allows
  1.2205 +  // them to be set for this style context.  (For example, only some
  1.2206 +  // properties apply to :first-line and :first-letter.)
  1.2207 +  uint32_t pseudoRestriction = GetPseudoRestriction(aContext);
  1.2208 +  if (pseudoRestriction) {
  1.2209 +    UnsetPropertiesWithoutFlags(aSID, &ruleData, pseudoRestriction);
  1.2210 +
  1.2211 +    // We need to recompute |detail| based on the restrictions we just applied.
  1.2212 +    // We can adjust |detail| arbitrarily because of the restriction
  1.2213 +    // rule added in nsStyleSet::WalkRestrictionRule.
  1.2214 +    recomputeDetail = true;
  1.2215 +  }
  1.2216 +
  1.2217 +  if (recomputeDetail) {
  1.2218 +    detail = CheckSpecifiedProperties(aSID, &ruleData);
  1.2219 +  }
  1.2220 +
  1.2221 +  NS_ASSERTION(!startStruct || (detail != eRuleFullReset &&
  1.2222 +                                detail != eRuleFullMixed &&
  1.2223 +                                detail != eRuleFullInherited),
  1.2224 +               "can't have start struct and be fully specified");
  1.2225 +
  1.2226 +  bool isReset = nsCachedStyleData::IsReset(aSID);
  1.2227 +  if (!highestNode)
  1.2228 +    highestNode = rootNode;
  1.2229 +
  1.2230 +  if (!ruleData.mCanStoreInRuleTree)
  1.2231 +    detail = eRulePartialMixed; // Treat as though some data is specified to avoid
  1.2232 +                                // the optimizations and force data computation.
  1.2233 +
  1.2234 +  if (detail == eRuleNone && startStruct) {
  1.2235 +    // We specified absolutely no rule information, but a parent rule in the tree
  1.2236 +    // specified all the rule information.  We set a bit along the branch from our
  1.2237 +    // node in the tree to the node that specified the data that tells nodes on that
  1.2238 +    // branch that they never need to examine their rules for this particular struct type
  1.2239 +    // ever again.
  1.2240 +    PropagateDependentBit(aSID, ruleNode, startStruct);
  1.2241 +    return startStruct;
  1.2242 +  }
  1.2243 +  if ((!startStruct && !isReset &&
  1.2244 +       (detail == eRuleNone || detail == eRulePartialInherited)) ||
  1.2245 +      detail == eRuleFullInherited) {
  1.2246 +    // We specified no non-inherited information and neither did any of
  1.2247 +    // our parent rules.
  1.2248 +
  1.2249 +    // We set a bit along the branch from the highest node (ruleNode)
  1.2250 +    // down to our node (this) indicating that no non-inherited data was
  1.2251 +    // specified.  This bit is guaranteed to be set already on the path
  1.2252 +    // from the highest node to the root node in the case where
  1.2253 +    // (detail == eRuleNone), which is the most common case here.
  1.2254 +    // We must check |!isReset| because the Compute*Data functions for
  1.2255 +    // reset structs wouldn't handle none bits correctly.
  1.2256 +    if (highestNode != this && !isReset)
  1.2257 +      PropagateNoneBit(bit, highestNode);
  1.2258 +
  1.2259 +    // All information must necessarily be inherited from our parent style context.
  1.2260 +    // In the absence of any computed data in the rule tree and with
  1.2261 +    // no rules specified that didn't have values of 'inherit', we should check our parent.
  1.2262 +    nsStyleContext* parentContext = aContext->GetParent();
  1.2263 +    if (isReset) {
  1.2264 +      /* Reset structs don't inherit from first-line. */
  1.2265 +      /* See similar code in COMPUTE_START_RESET */
  1.2266 +      while (parentContext &&
  1.2267 +             parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) {
  1.2268 +        parentContext = parentContext->GetParent();
  1.2269 +      }
  1.2270 +    }
  1.2271 +    if (parentContext) {
  1.2272 +      // We have a parent, and so we should just inherit from the parent.
  1.2273 +      // Set the inherit bits on our context.  These bits tell the style context that
  1.2274 +      // it never has to go back to the rule tree for data.  Instead the style context tree
  1.2275 +      // should be walked to find the data.
  1.2276 +      const void* parentStruct = parentContext->StyleData(aSID);
  1.2277 +      aContext->AddStyleBit(bit); // makes const_cast OK.
  1.2278 +      aContext->SetStyle(aSID, const_cast<void*>(parentStruct));
  1.2279 +      return parentStruct;
  1.2280 +    }
  1.2281 +    else
  1.2282 +      // We are the root.  In the case of fonts, the default values just
  1.2283 +      // come from the pres context.
  1.2284 +      return SetDefaultOnRoot(aSID, aContext);
  1.2285 +  }
  1.2286 +
  1.2287 +  // We need to compute the data from the information that the rules specified.
  1.2288 +  const void* res;
  1.2289 +#define STYLE_STRUCT_TEST aSID
  1.2290 +#define STYLE_STRUCT(name, checkdata_cb)                                      \
  1.2291 +  res = Compute##name##Data(startStruct, &ruleData, aContext,                 \
  1.2292 +                            highestNode, detail, ruleData.mCanStoreInRuleTree);
  1.2293 +#include "nsStyleStructList.h"
  1.2294 +#undef STYLE_STRUCT
  1.2295 +#undef STYLE_STRUCT_TEST
  1.2296 +
  1.2297 +  // Now return the result.
  1.2298 +  return res;
  1.2299 +}
  1.2300 +
  1.2301 +const void*
  1.2302 +nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
  1.2303 +{
  1.2304 +  switch (aSID) {
  1.2305 +    case eStyleStruct_Font:
  1.2306 +    {
  1.2307 +      nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
  1.2308 +      nscoord minimumFontSize = mPresContext->MinFontSize(fontData->mLanguage);
  1.2309 +
  1.2310 +      if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
  1.2311 +        fontData->mFont.size = std::max(fontData->mSize, minimumFontSize);
  1.2312 +      }
  1.2313 +      else {
  1.2314 +        fontData->mFont.size = fontData->mSize;
  1.2315 +      }
  1.2316 +      aContext->SetStyle(eStyleStruct_Font, fontData);
  1.2317 +      return fontData;
  1.2318 +    }
  1.2319 +    case eStyleStruct_Display:
  1.2320 +    {
  1.2321 +      nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay();
  1.2322 +      aContext->SetStyle(eStyleStruct_Display, disp);
  1.2323 +      return disp;
  1.2324 +    }
  1.2325 +    case eStyleStruct_Visibility:
  1.2326 +    {
  1.2327 +      nsStyleVisibility* vis = new (mPresContext) nsStyleVisibility(mPresContext);
  1.2328 +      aContext->SetStyle(eStyleStruct_Visibility, vis);
  1.2329 +      return vis;
  1.2330 +    }
  1.2331 +    case eStyleStruct_Text:
  1.2332 +    {
  1.2333 +      nsStyleText* text = new (mPresContext) nsStyleText();
  1.2334 +      aContext->SetStyle(eStyleStruct_Text, text);
  1.2335 +      return text;
  1.2336 +    }
  1.2337 +    case eStyleStruct_TextReset:
  1.2338 +    {
  1.2339 +      nsStyleTextReset* text = new (mPresContext) nsStyleTextReset();
  1.2340 +      aContext->SetStyle(eStyleStruct_TextReset, text);
  1.2341 +      return text;
  1.2342 +    }
  1.2343 +    case eStyleStruct_Color:
  1.2344 +    {
  1.2345 +      nsStyleColor* color = new (mPresContext) nsStyleColor(mPresContext);
  1.2346 +      aContext->SetStyle(eStyleStruct_Color, color);
  1.2347 +      return color;
  1.2348 +    }
  1.2349 +    case eStyleStruct_Background:
  1.2350 +    {
  1.2351 +      nsStyleBackground* bg = new (mPresContext) nsStyleBackground();
  1.2352 +      aContext->SetStyle(eStyleStruct_Background, bg);
  1.2353 +      return bg;
  1.2354 +    }
  1.2355 +    case eStyleStruct_Margin:
  1.2356 +    {
  1.2357 +      nsStyleMargin* margin = new (mPresContext) nsStyleMargin();
  1.2358 +      aContext->SetStyle(eStyleStruct_Margin, margin);
  1.2359 +      return margin;
  1.2360 +    }
  1.2361 +    case eStyleStruct_Border:
  1.2362 +    {
  1.2363 +      nsStyleBorder* border = new (mPresContext) nsStyleBorder(mPresContext);
  1.2364 +      aContext->SetStyle(eStyleStruct_Border, border);
  1.2365 +      return border;
  1.2366 +    }
  1.2367 +    case eStyleStruct_Padding:
  1.2368 +    {
  1.2369 +      nsStylePadding* padding = new (mPresContext) nsStylePadding();
  1.2370 +      aContext->SetStyle(eStyleStruct_Padding, padding);
  1.2371 +      return padding;
  1.2372 +    }
  1.2373 +    case eStyleStruct_Outline:
  1.2374 +    {
  1.2375 +      nsStyleOutline* outline = new (mPresContext) nsStyleOutline(mPresContext);
  1.2376 +      aContext->SetStyle(eStyleStruct_Outline, outline);
  1.2377 +      return outline;
  1.2378 +    }
  1.2379 +    case eStyleStruct_List:
  1.2380 +    {
  1.2381 +      nsStyleList* list = new (mPresContext) nsStyleList();
  1.2382 +      aContext->SetStyle(eStyleStruct_List, list);
  1.2383 +      return list;
  1.2384 +    }
  1.2385 +    case eStyleStruct_Position:
  1.2386 +    {
  1.2387 +      nsStylePosition* pos = new (mPresContext) nsStylePosition();
  1.2388 +      aContext->SetStyle(eStyleStruct_Position, pos);
  1.2389 +      return pos;
  1.2390 +    }
  1.2391 +    case eStyleStruct_Table:
  1.2392 +    {
  1.2393 +      nsStyleTable* table = new (mPresContext) nsStyleTable();
  1.2394 +      aContext->SetStyle(eStyleStruct_Table, table);
  1.2395 +      return table;
  1.2396 +    }
  1.2397 +    case eStyleStruct_TableBorder:
  1.2398 +    {
  1.2399 +      nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder(mPresContext);
  1.2400 +      aContext->SetStyle(eStyleStruct_TableBorder, table);
  1.2401 +      return table;
  1.2402 +    }
  1.2403 +    case eStyleStruct_Content:
  1.2404 +    {
  1.2405 +      nsStyleContent* content = new (mPresContext) nsStyleContent();
  1.2406 +      aContext->SetStyle(eStyleStruct_Content, content);
  1.2407 +      return content;
  1.2408 +    }
  1.2409 +    case eStyleStruct_Quotes:
  1.2410 +    {
  1.2411 +      nsStyleQuotes* quotes = new (mPresContext) nsStyleQuotes();
  1.2412 +      aContext->SetStyle(eStyleStruct_Quotes, quotes);
  1.2413 +      return quotes;
  1.2414 +    }
  1.2415 +    case eStyleStruct_UserInterface:
  1.2416 +    {
  1.2417 +      nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface();
  1.2418 +      aContext->SetStyle(eStyleStruct_UserInterface, ui);
  1.2419 +      return ui;
  1.2420 +    }
  1.2421 +    case eStyleStruct_UIReset:
  1.2422 +    {
  1.2423 +      nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset();
  1.2424 +      aContext->SetStyle(eStyleStruct_UIReset, ui);
  1.2425 +      return ui;
  1.2426 +    }
  1.2427 +    case eStyleStruct_XUL:
  1.2428 +    {
  1.2429 +      nsStyleXUL* xul = new (mPresContext) nsStyleXUL();
  1.2430 +      aContext->SetStyle(eStyleStruct_XUL, xul);
  1.2431 +      return xul;
  1.2432 +    }
  1.2433 +    case eStyleStruct_Column:
  1.2434 +    {
  1.2435 +      nsStyleColumn* column = new (mPresContext) nsStyleColumn(mPresContext);
  1.2436 +      aContext->SetStyle(eStyleStruct_Column, column);
  1.2437 +      return column;
  1.2438 +    }
  1.2439 +    case eStyleStruct_SVG:
  1.2440 +    {
  1.2441 +      nsStyleSVG* svg = new (mPresContext) nsStyleSVG();
  1.2442 +      aContext->SetStyle(eStyleStruct_SVG, svg);
  1.2443 +      return svg;
  1.2444 +    }
  1.2445 +    case eStyleStruct_SVGReset:
  1.2446 +    {
  1.2447 +      nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset();
  1.2448 +      aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
  1.2449 +      return svgReset;
  1.2450 +    }
  1.2451 +    case eStyleStruct_Variables:
  1.2452 +    {
  1.2453 +      nsStyleVariables* vars = new (mPresContext) nsStyleVariables();
  1.2454 +      aContext->SetStyle(eStyleStruct_Variables, vars);
  1.2455 +      return vars;
  1.2456 +    }
  1.2457 +    default:
  1.2458 +      /*
  1.2459 +       * unhandled case: nsStyleStructID_Length.
  1.2460 +       * last item of nsStyleStructID, to know its length.
  1.2461 +       */
  1.2462 +      NS_ABORT_IF_FALSE(false, "unexpected SID");
  1.2463 +      return nullptr;
  1.2464 +  }
  1.2465 +  return nullptr;
  1.2466 +}
  1.2467 +
  1.2468 +/*
  1.2469 + * This function handles cascading of *-left or *-right box properties
  1.2470 + * against *-start (which is L for LTR and R for RTL) or *-end (which is
  1.2471 + * R for LTR and L for RTL).
  1.2472 + *
  1.2473 + * Cascading these properties correctly is hard because we need to
  1.2474 + * cascade two properties as one, but which two properties depends on a
  1.2475 + * third property ('direction').  We solve this by treating each of
  1.2476 + * these properties (say, 'margin-start') as a shorthand that sets a
  1.2477 + * property containing the value of the property specified
  1.2478 + * ('margin-start-value') and sets a pair of properties
  1.2479 + * ('margin-left-ltr-source' and 'margin-right-rtl-source') saying which
  1.2480 + * of the properties we use.  Thus, when we want to compute the value of
  1.2481 + * 'margin-left' when 'direction' is 'ltr', we look at the value of
  1.2482 + * 'margin-left-ltr-source', which tells us whether to use the highest
  1.2483 + * 'margin-left' in the cascade or the highest 'margin-start'.
  1.2484 + *
  1.2485 + * Finally, since we can compute the normal (*-left and *-right)
  1.2486 + * properties in a loop, this function works by modifying the data we
  1.2487 + * will use in that loop (which the caller must copy from the const
  1.2488 + * input).
  1.2489 + */
  1.2490 +void
  1.2491 +nsRuleNode::AdjustLogicalBoxProp(nsStyleContext* aContext,
  1.2492 +                                 const nsCSSValue& aLTRSource,
  1.2493 +                                 const nsCSSValue& aRTLSource,
  1.2494 +                                 const nsCSSValue& aLTRLogicalValue,
  1.2495 +                                 const nsCSSValue& aRTLLogicalValue,
  1.2496 +                                 mozilla::css::Side aSide,
  1.2497 +                                 nsCSSRect& aValueRect,
  1.2498 +                                 bool& aCanStoreInRuleTree)
  1.2499 +{
  1.2500 +  bool LTRlogical = aLTRSource.GetUnit() == eCSSUnit_Enumerated &&
  1.2501 +                      aLTRSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
  1.2502 +  bool RTLlogical = aRTLSource.GetUnit() == eCSSUnit_Enumerated &&
  1.2503 +                      aRTLSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
  1.2504 +  if (LTRlogical || RTLlogical) {
  1.2505 +    // We can't cache anything on the rule tree if we use any data from
  1.2506 +    // the style context, since data cached in the rule tree could be
  1.2507 +    // used with a style context with a different value.
  1.2508 +    aCanStoreInRuleTree = false;
  1.2509 +    uint8_t dir = aContext->StyleVisibility()->mDirection;
  1.2510 +
  1.2511 +    if (dir == NS_STYLE_DIRECTION_LTR) {
  1.2512 +      if (LTRlogical)
  1.2513 +        aValueRect.*(nsCSSRect::sides[aSide]) = aLTRLogicalValue;
  1.2514 +    } else {
  1.2515 +      if (RTLlogical)
  1.2516 +        aValueRect.*(nsCSSRect::sides[aSide]) = aRTLLogicalValue;
  1.2517 +    }
  1.2518 +  } else if (aLTRLogicalValue.GetUnit() == eCSSUnit_Inherit ||
  1.2519 +             aRTLLogicalValue.GetUnit() == eCSSUnit_Inherit) {
  1.2520 +    // It actually is valid to store this in the ruletree, since
  1.2521 +    // LTRlogical and RTLlogical are both false, but doing that will
  1.2522 +    // trigger asserts.  Silence those.
  1.2523 +    aCanStoreInRuleTree = false;
  1.2524 +  }
  1.2525 +}
  1.2526 +
  1.2527 +/**
  1.2528 + * Begin an nsRuleNode::Compute*Data function for an inherited struct.
  1.2529 + *
  1.2530 + * @param type_ The nsStyle* type this function computes.
  1.2531 + * @param ctorargs_ The arguments used for the default nsStyle* constructor.
  1.2532 + * @param data_ Variable (declared here) holding the result of this
  1.2533 + *              function.
  1.2534 + * @param parentdata_ Variable (declared here) holding the parent style
  1.2535 + *                    context's data for this struct.
  1.2536 + */
  1.2537 +#define COMPUTE_START_INHERITED(type_, ctorargs_, data_, parentdata_)         \
  1.2538 +  NS_ASSERTION(aRuleDetail != eRuleFullInherited,                             \
  1.2539 +               "should not have bothered calling Compute*Data");              \
  1.2540 +                                                                              \
  1.2541 +  nsStyleContext* parentContext = aContext->GetParent();                      \
  1.2542 +                                                                              \
  1.2543 +  nsStyle##type_* data_ = nullptr;                                            \
  1.2544 +  mozilla::Maybe<nsStyle##type_> maybeFakeParentData;                         \
  1.2545 +  const nsStyle##type_* parentdata_ = nullptr;                                \
  1.2546 +  bool canStoreInRuleTree = aCanStoreInRuleTree;                              \
  1.2547 +                                                                              \
  1.2548 +  /* If |canStoreInRuleTree| might be true by the time we're done, we */      \
  1.2549 +  /* can't call parentContext->Style##type_() since it could recur into */    \
  1.2550 +  /* setting the same struct on the same rule node, causing a leak. */        \
  1.2551 +  if (aRuleDetail != eRuleFullReset &&                                        \
  1.2552 +      (!aStartStruct || (aRuleDetail != eRulePartialReset &&                  \
  1.2553 +                         aRuleDetail != eRuleNone))) {                        \
  1.2554 +    if (parentContext) {                                                      \
  1.2555 +      parentdata_ = parentContext->Style##type_();                            \
  1.2556 +    } else {                                                                  \
  1.2557 +      maybeFakeParentData.construct ctorargs_;                                \
  1.2558 +      parentdata_ = maybeFakeParentData.addr();                               \
  1.2559 +    }                                                                         \
  1.2560 +  }                                                                           \
  1.2561 +  if (aStartStruct)                                                           \
  1.2562 +    /* We only need to compute the delta between this computed data and */    \
  1.2563 +    /* our computed data. */                                                  \
  1.2564 +    data_ = new (mPresContext)                                                \
  1.2565 +            nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct));      \
  1.2566 +  else {                                                                      \
  1.2567 +    if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) {     \
  1.2568 +      /* No question. We will have to inherit. Go ahead and init */           \
  1.2569 +      /* with inherited vals from parent. */                                  \
  1.2570 +      canStoreInRuleTree = false;                                          \
  1.2571 +      if (parentdata_)                                                        \
  1.2572 +        data_ = new (mPresContext) nsStyle##type_(*parentdata_);              \
  1.2573 +      else                                                                    \
  1.2574 +        data_ = new (mPresContext) nsStyle##type_ ctorargs_;                  \
  1.2575 +    }                                                                         \
  1.2576 +    else                                                                      \
  1.2577 +      data_ = new (mPresContext) nsStyle##type_ ctorargs_;                    \
  1.2578 +  }                                                                           \
  1.2579 +                                                                              \
  1.2580 +  if (!parentdata_)                                                           \
  1.2581 +    parentdata_ = data_;
  1.2582 +
  1.2583 +/**
  1.2584 + * Begin an nsRuleNode::Compute*Data function for a reset struct.
  1.2585 + *
  1.2586 + * @param type_ The nsStyle* type this function computes.
  1.2587 + * @param ctorargs_ The arguments used for the default nsStyle* constructor.
  1.2588 + * @param data_ Variable (declared here) holding the result of this
  1.2589 + *              function.
  1.2590 + * @param parentdata_ Variable (declared here) holding the parent style
  1.2591 + *                    context's data for this struct.
  1.2592 + */
  1.2593 +#define COMPUTE_START_RESET(type_, ctorargs_, data_, parentdata_)             \
  1.2594 +  NS_ASSERTION(aRuleDetail != eRuleFullInherited,                             \
  1.2595 +               "should not have bothered calling Compute*Data");              \
  1.2596 +                                                                              \
  1.2597 +  nsStyleContext* parentContext = aContext->GetParent();                      \
  1.2598 +  /* Reset structs don't inherit from first-line */                           \
  1.2599 +  /* See similar code in WalkRuleTree */                                      \
  1.2600 +  while (parentContext &&                                                     \
  1.2601 +         parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) {      \
  1.2602 +    parentContext = parentContext->GetParent();                               \
  1.2603 +  }                                                                           \
  1.2604 +                                                                              \
  1.2605 +  nsStyle##type_* data_;                                                      \
  1.2606 +  if (aStartStruct)                                                           \
  1.2607 +    /* We only need to compute the delta between this computed data and */    \
  1.2608 +    /* our computed data. */                                                  \
  1.2609 +    data_ = new (mPresContext)                                                \
  1.2610 +            nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct));      \
  1.2611 +  else                                                                        \
  1.2612 +    data_ = new (mPresContext) nsStyle##type_ ctorargs_;                      \
  1.2613 +                                                                              \
  1.2614 +  /* If |canStoreInRuleTree| might be true by the time we're done, we */      \
  1.2615 +  /* can't call parentContext->Style##type_() since it could recur into */    \
  1.2616 +  /* setting the same struct on the same rule node, causing a leak. */        \
  1.2617 +  mozilla::Maybe<nsStyle##type_> maybeFakeParentData;                         \
  1.2618 +  const nsStyle##type_* parentdata_ = data_;                                  \
  1.2619 +  if (aRuleDetail != eRuleFullReset &&                                        \
  1.2620 +      aRuleDetail != eRulePartialReset &&                                     \
  1.2621 +      aRuleDetail != eRuleNone) {                                             \
  1.2622 +    if (parentContext) {                                                      \
  1.2623 +      parentdata_ = parentContext->Style##type_();                            \
  1.2624 +    } else {                                                                  \
  1.2625 +      maybeFakeParentData.construct ctorargs_;                                \
  1.2626 +      parentdata_ = maybeFakeParentData.addr();                               \
  1.2627 +    }                                                                         \
  1.2628 +  }                                                                           \
  1.2629 +  bool canStoreInRuleTree = aCanStoreInRuleTree;
  1.2630 +
  1.2631 +/**
  1.2632 + * End an nsRuleNode::Compute*Data function for an inherited struct.
  1.2633 + *
  1.2634 + * @param type_ The nsStyle* type this function computes.
  1.2635 + * @param data_ Variable holding the result of this function.
  1.2636 + */
  1.2637 +#define COMPUTE_END_INHERITED(type_, data_)                                   \
  1.2638 +  NS_POSTCONDITION(!canStoreInRuleTree || aRuleDetail == eRuleFullReset ||    \
  1.2639 +                   (aStartStruct && aRuleDetail == eRulePartialReset),        \
  1.2640 +                   "canStoreInRuleTree must be false for inherited structs "  \
  1.2641 +                   "unless all properties have been specified with values "   \
  1.2642 +                   "other than inherit");                                     \
  1.2643 +  if (canStoreInRuleTree) {                                                   \
  1.2644 +    /* We were fully specified and can therefore be cached right on the */    \
  1.2645 +    /* rule node. */                                                          \
  1.2646 +    if (!aHighestNode->mStyleData.mInheritedData) {                           \
  1.2647 +      aHighestNode->mStyleData.mInheritedData =                               \
  1.2648 +        new (mPresContext) nsInheritedStyleData;                              \
  1.2649 +    }                                                                         \
  1.2650 +    NS_ASSERTION(!aHighestNode->mStyleData.mInheritedData->                   \
  1.2651 +                   mStyleStructs[eStyleStruct_##type_],                       \
  1.2652 +                 "Going to leak style data");                                 \
  1.2653 +    aHighestNode->mStyleData.mInheritedData->                                 \
  1.2654 +      mStyleStructs[eStyleStruct_##type_] = data_;                            \
  1.2655 +    /* Propagate the bit down. */                                             \
  1.2656 +    PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_);         \
  1.2657 +    /* Tell the style context that it doesn't own the data */                 \
  1.2658 +    aContext->                                                                \
  1.2659 +      AddStyleBit(nsCachedStyleData::GetBitForSID(eStyleStruct_##type_));     \
  1.2660 +  }                                                                           \
  1.2661 +  /* Always cache inherited data on the style context */                      \
  1.2662 +  aContext->SetStyle##type_(data_);                                           \
  1.2663 +                                                                              \
  1.2664 +  return data_;
  1.2665 +
  1.2666 +/**
  1.2667 + * End an nsRuleNode::Compute*Data function for a reset struct.
  1.2668 + *
  1.2669 + * @param type_ The nsStyle* type this function computes.
  1.2670 + * @param data_ Variable holding the result of this function.
  1.2671 + */
  1.2672 +#define COMPUTE_END_RESET(type_, data_)                                       \
  1.2673 +  NS_POSTCONDITION(!canStoreInRuleTree ||                                     \
  1.2674 +                   aRuleDetail == eRuleNone ||                                \
  1.2675 +                   aRuleDetail == eRulePartialReset ||                        \
  1.2676 +                   aRuleDetail == eRuleFullReset,                             \
  1.2677 +                   "canStoreInRuleTree must be false for reset structs "      \
  1.2678 +                   "if any properties were specified as inherit");            \
  1.2679 +  if (!canStoreInRuleTree)                                                    \
  1.2680 +    /* We can't be cached in the rule node.  We have to be put right */       \
  1.2681 +    /* on the style context. */                                               \
  1.2682 +    aContext->SetStyle(eStyleStruct_##type_, data_);                          \
  1.2683 +  else {                                                                      \
  1.2684 +    /* We were fully specified and can therefore be cached right on the */    \
  1.2685 +    /* rule node. */                                                          \
  1.2686 +    if (!aHighestNode->mStyleData.mResetData) {                               \
  1.2687 +      aHighestNode->mStyleData.mResetData =                                   \
  1.2688 +        new (mPresContext) nsResetStyleData;                                  \
  1.2689 +    }                                                                         \
  1.2690 +    NS_ASSERTION(!aHighestNode->mStyleData.mResetData->                       \
  1.2691 +                   mStyleStructs[eStyleStruct_##type_],                       \
  1.2692 +                 "Going to leak style data");                                 \
  1.2693 +    aHighestNode->mStyleData.mResetData->                                     \
  1.2694 +      mStyleStructs[eStyleStruct_##type_] = data_;                            \
  1.2695 +    /* Propagate the bit down. */                                             \
  1.2696 +    PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_);         \
  1.2697 +  }                                                                           \
  1.2698 +                                                                              \
  1.2699 +  return data_;
  1.2700 +
  1.2701 +// This function figures out how much scaling should be suppressed to
  1.2702 +// satisfy scriptminsize. This is our attempt to implement
  1.2703 +// http://www.w3.org/TR/MathML2/chapter3.html#id.3.3.4.2.2
  1.2704 +// This is called after mScriptLevel, mScriptMinSize and mScriptSizeMultiplier
  1.2705 +// have been set in aFont.
  1.2706 +//
  1.2707 +// Here are the invariants we enforce:
  1.2708 +// 1) A decrease in size must not reduce the size below minscriptsize.
  1.2709 +// 2) An increase in size must not increase the size above the size we would
  1.2710 +// have if minscriptsize had not been applied anywhere.
  1.2711 +// 3) The scriptlevel-induced size change must between 1.0 and the parent's
  1.2712 +// scriptsizemultiplier^(new script level - old script level), as close to the
  1.2713 +// latter as possible subject to constraints 1 and 2.
  1.2714 +static nscoord
  1.2715 +ComputeScriptLevelSize(const nsStyleFont* aFont, const nsStyleFont* aParentFont,
  1.2716 +                       nsPresContext* aPresContext, nscoord* aUnconstrainedSize)
  1.2717 +{
  1.2718 +  int32_t scriptLevelChange =
  1.2719 +    aFont->mScriptLevel - aParentFont->mScriptLevel;
  1.2720 +  if (scriptLevelChange == 0) {
  1.2721 +    *aUnconstrainedSize = aParentFont->mScriptUnconstrainedSize;
  1.2722 +    // Constraint #3 says that we cannot change size, and #1 and #2 are always
  1.2723 +    // satisfied with no change. It's important this be fast because it covers
  1.2724 +    // all non-MathML content.
  1.2725 +    return aParentFont->mSize;
  1.2726 +  }
  1.2727 +
  1.2728 +  // Compute actual value of minScriptSize
  1.2729 +  nscoord minScriptSize = aParentFont->mScriptMinSize;
  1.2730 +  if (aFont->mAllowZoom) {
  1.2731 +    minScriptSize = nsStyleFont::ZoomText(aPresContext, minScriptSize);
  1.2732 +  }
  1.2733 +
  1.2734 +  double scriptLevelScale =
  1.2735 +    pow(aParentFont->mScriptSizeMultiplier, scriptLevelChange);
  1.2736 +  // Compute the size we would have had if minscriptsize had never been
  1.2737 +  // applied, also prevent overflow (bug 413274)
  1.2738 +  *aUnconstrainedSize =
  1.2739 +    NSToCoordRound(std::min(aParentFont->mScriptUnconstrainedSize*scriptLevelScale,
  1.2740 +                          double(nscoord_MAX)));
  1.2741 +  // Compute the size we could get via scriptlevel change
  1.2742 +  nscoord scriptLevelSize =
  1.2743 +    NSToCoordRound(std::min(aParentFont->mSize*scriptLevelScale,
  1.2744 +                          double(nscoord_MAX)));
  1.2745 +  if (scriptLevelScale <= 1.0) {
  1.2746 +    if (aParentFont->mSize <= minScriptSize) {
  1.2747 +      // We can't decrease the font size at all, so just stick to no change
  1.2748 +      // (authors are allowed to explicitly set the font size smaller than
  1.2749 +      // minscriptsize)
  1.2750 +      return aParentFont->mSize;
  1.2751 +    }
  1.2752 +    // We can decrease, so apply constraint #1
  1.2753 +    return std::max(minScriptSize, scriptLevelSize);
  1.2754 +  } else {
  1.2755 +    // scriptminsize can only make sizes larger than the unconstrained size
  1.2756 +    NS_ASSERTION(*aUnconstrainedSize <= scriptLevelSize, "How can this ever happen?");
  1.2757 +    // Apply constraint #2
  1.2758 +    return std::min(scriptLevelSize, std::max(*aUnconstrainedSize, minScriptSize));
  1.2759 +  }
  1.2760 +}
  1.2761 +
  1.2762 +
  1.2763 +/* static */ nscoord
  1.2764 +nsRuleNode::CalcFontPointSize(int32_t aHTMLSize, int32_t aBasePointSize,
  1.2765 +                              nsPresContext* aPresContext,
  1.2766 +                              nsFontSizeType aFontSizeType)
  1.2767 +{
  1.2768 +#define sFontSizeTableMin  9 
  1.2769 +#define sFontSizeTableMax 16 
  1.2770 +
  1.2771 +// This table seems to be the one used by MacIE5. We hope its adoption in Mozilla
  1.2772 +// and eventually in WinIE5.5 will help to establish a standard rendering across
  1.2773 +// platforms and browsers. For now, it is used only in Strict mode. More can be read
  1.2774 +// in the document written by Todd Farhner at:
  1.2775 +// http://style.verso.com/font_size_intervals/altintervals.html
  1.2776 +//
  1.2777 +  static int32_t sStrictFontSizeTable[sFontSizeTableMax - sFontSizeTableMin + 1][8] =
  1.2778 +  {
  1.2779 +      { 9,    9,     9,     9,    11,    14,    18,    27},
  1.2780 +      { 9,    9,     9,    10,    12,    15,    20,    30},
  1.2781 +      { 9,    9,    10,    11,    13,    17,    22,    33},
  1.2782 +      { 9,    9,    10,    12,    14,    18,    24,    36},
  1.2783 +      { 9,   10,    12,    13,    16,    20,    26,    39},
  1.2784 +      { 9,   10,    12,    14,    17,    21,    28,    42},
  1.2785 +      { 9,   10,    13,    15,    18,    23,    30,    45},
  1.2786 +      { 9,   10,    13,    16,    18,    24,    32,    48}
  1.2787 +  };
  1.2788 +// HTML       1      2      3      4      5      6      7
  1.2789 +// CSS  xxs   xs     s      m      l     xl     xxl
  1.2790 +//                          |
  1.2791 +//                      user pref
  1.2792 +//
  1.2793 +//------------------------------------------------------------
  1.2794 +//
  1.2795 +// This table gives us compatibility with WinNav4 for the default fonts only.
  1.2796 +// In WinNav4, the default fonts were:
  1.2797 +//
  1.2798 +//     Times/12pt ==   Times/16px at 96ppi
  1.2799 +//   Courier/10pt == Courier/13px at 96ppi
  1.2800 +//
  1.2801 +// The 2 lines below marked "anchored" have the exact pixel sizes used by
  1.2802 +// WinNav4 for Times/12pt and Courier/10pt at 96ppi. As you can see, the
  1.2803 +// HTML size 3 (user pref) for those 2 anchored lines is 13px and 16px.
  1.2804 +//
  1.2805 +// All values other than the anchored values were filled in by hand, never
  1.2806 +// going below 9px, and maintaining a "diagonal" relationship. See for
  1.2807 +// example the 13s -- they follow a diagonal line through the table.
  1.2808 +//
  1.2809 +  static int32_t sQuirksFontSizeTable[sFontSizeTableMax - sFontSizeTableMin + 1][8] =
  1.2810 +  {
  1.2811 +      { 9,    9,     9,     9,    11,    14,    18,    28 },
  1.2812 +      { 9,    9,     9,    10,    12,    15,    20,    31 },
  1.2813 +      { 9,    9,     9,    11,    13,    17,    22,    34 },
  1.2814 +      { 9,    9,    10,    12,    14,    18,    24,    37 },
  1.2815 +      { 9,    9,    10,    13,    16,    20,    26,    40 }, // anchored (13)
  1.2816 +      { 9,    9,    11,    14,    17,    21,    28,    42 },
  1.2817 +      { 9,   10,    12,    15,    17,    23,    30,    45 },
  1.2818 +      { 9,   10,    13,    16,    18,    24,    32,    48 }  // anchored (16)
  1.2819 +  };
  1.2820 +// HTML       1      2      3      4      5      6      7
  1.2821 +// CSS  xxs   xs     s      m      l     xl     xxl
  1.2822 +//                          |
  1.2823 +//                      user pref
  1.2824 +
  1.2825 +#if 0
  1.2826 +//
  1.2827 +// These are the exact pixel values used by WinIE5 at 96ppi.
  1.2828 +//
  1.2829 +      { ?,    8,    11,    12,    13,    16,    21,    32 }, // smallest
  1.2830 +      { ?,    9,    12,    13,    16,    21,    27,    40 }, // smaller
  1.2831 +      { ?,   10,    13,    16,    18,    24,    32,    48 }, // medium
  1.2832 +      { ?,   13,    16,    19,    21,    27,    37,    ?? }, // larger
  1.2833 +      { ?,   16,    19,    21,    24,    32,    43,    ?? }  // largest
  1.2834 +//
  1.2835 +// HTML       1      2      3      4      5      6      7
  1.2836 +// CSS  ?     ?      ?      ?      ?      ?      ?      ?
  1.2837 +//
  1.2838 +// (CSS not tested yet.)
  1.2839 +//
  1.2840 +#endif
  1.2841 +
  1.2842 +  static int32_t sFontSizeFactors[8] = { 60,75,89,100,120,150,200,300 };
  1.2843 +
  1.2844 +  static int32_t sCSSColumns[7]  = {0, 1, 2, 3, 4, 5, 6}; // xxs...xxl
  1.2845 +  static int32_t sHTMLColumns[7] = {1, 2, 3, 4, 5, 6, 7}; // 1...7
  1.2846 +
  1.2847 +  double dFontSize;
  1.2848 +
  1.2849 +  if (aFontSizeType == eFontSize_HTML) {
  1.2850 +    aHTMLSize--;    // input as 1-7
  1.2851 +  }
  1.2852 +
  1.2853 +  if (aHTMLSize < 0)
  1.2854 +    aHTMLSize = 0;
  1.2855 +  else if (aHTMLSize > 6)
  1.2856 +    aHTMLSize = 6;
  1.2857 +
  1.2858 +  int32_t* column;
  1.2859 +  switch (aFontSizeType)
  1.2860 +  {
  1.2861 +    case eFontSize_HTML: column = sHTMLColumns; break;
  1.2862 +    case eFontSize_CSS:  column = sCSSColumns;  break;
  1.2863 +  }
  1.2864 +
  1.2865 +  // Make special call specifically for fonts (needed PrintPreview)
  1.2866 +  int32_t fontSize = nsPresContext::AppUnitsToIntCSSPixels(aBasePointSize);
  1.2867 +
  1.2868 +  if ((fontSize >= sFontSizeTableMin) && (fontSize <= sFontSizeTableMax))
  1.2869 +  {
  1.2870 +    int32_t row = fontSize - sFontSizeTableMin;
  1.2871 +
  1.2872 +    if (aPresContext->CompatibilityMode() == eCompatibility_NavQuirks) {
  1.2873 +      dFontSize = nsPresContext::CSSPixelsToAppUnits(sQuirksFontSizeTable[row][column[aHTMLSize]]);
  1.2874 +    } else {
  1.2875 +      dFontSize = nsPresContext::CSSPixelsToAppUnits(sStrictFontSizeTable[row][column[aHTMLSize]]);
  1.2876 +    }
  1.2877 +  }
  1.2878 +  else
  1.2879 +  {
  1.2880 +    int32_t factor = sFontSizeFactors[column[aHTMLSize]];
  1.2881 +    dFontSize = (factor * aBasePointSize) / 100;
  1.2882 +  }
  1.2883 +
  1.2884 +
  1.2885 +  if (1.0 < dFontSize) {
  1.2886 +    return (nscoord)dFontSize;
  1.2887 +  }
  1.2888 +  return (nscoord)1;
  1.2889 +}
  1.2890 +
  1.2891 +
  1.2892 +//------------------------------------------------------------------------------
  1.2893 +//
  1.2894 +//------------------------------------------------------------------------------
  1.2895 +
  1.2896 +/* static */ nscoord
  1.2897 +nsRuleNode::FindNextSmallerFontSize(nscoord aFontSize, int32_t aBasePointSize, 
  1.2898 +                                    nsPresContext* aPresContext,
  1.2899 +                                    nsFontSizeType aFontSizeType)
  1.2900 +{
  1.2901 +  int32_t index;
  1.2902 +  int32_t indexMin;
  1.2903 +  int32_t indexMax;
  1.2904 +  float relativePosition;
  1.2905 +  nscoord smallerSize;
  1.2906 +  nscoord indexFontSize = aFontSize; // XXX initialize to quell a spurious gcc3.2 warning
  1.2907 +  nscoord smallestIndexFontSize;
  1.2908 +  nscoord largestIndexFontSize;
  1.2909 +  nscoord smallerIndexFontSize;
  1.2910 +  nscoord largerIndexFontSize;
  1.2911 +
  1.2912 +  nscoord onePx = nsPresContext::CSSPixelsToAppUnits(1);
  1.2913 +
  1.2914 +  if (aFontSizeType == eFontSize_HTML) {
  1.2915 +    indexMin = 1;
  1.2916 +    indexMax = 7;
  1.2917 +  } else {
  1.2918 +    indexMin = 0;
  1.2919 +    indexMax = 6;
  1.2920 +  }
  1.2921 +  
  1.2922 +  smallestIndexFontSize = CalcFontPointSize(indexMin, aBasePointSize, aPresContext, aFontSizeType);
  1.2923 +  largestIndexFontSize = CalcFontPointSize(indexMax, aBasePointSize, aPresContext, aFontSizeType); 
  1.2924 +  if (aFontSize > smallestIndexFontSize) {
  1.2925 +    if (aFontSize < NSToCoordRound(float(largestIndexFontSize) * 1.5)) { // smaller will be in HTML table
  1.2926 +      // find largest index smaller than current
  1.2927 +      for (index = indexMax; index >= indexMin; index--) {
  1.2928 +        indexFontSize = CalcFontPointSize(index, aBasePointSize, aPresContext, aFontSizeType);
  1.2929 +        if (indexFontSize < aFontSize)
  1.2930 +          break;
  1.2931 +      } 
  1.2932 +      // set up points beyond table for interpolation purposes
  1.2933 +      if (indexFontSize == smallestIndexFontSize) {
  1.2934 +        smallerIndexFontSize = indexFontSize - onePx;
  1.2935 +        largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
  1.2936 +      } else if (indexFontSize == largestIndexFontSize) {
  1.2937 +        smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
  1.2938 +        largerIndexFontSize = NSToCoordRound(float(largestIndexFontSize) * 1.5);
  1.2939 +      } else {
  1.2940 +        smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
  1.2941 +        largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
  1.2942 +      }
  1.2943 +      // compute the relative position of the parent size between the two closest indexed sizes
  1.2944 +      relativePosition = float(aFontSize - indexFontSize) / float(largerIndexFontSize - indexFontSize);            
  1.2945 +      // set the new size to have the same relative position between the next smallest two indexed sizes
  1.2946 +      smallerSize = smallerIndexFontSize + NSToCoordRound(relativePosition * (indexFontSize - smallerIndexFontSize));      
  1.2947 +    }
  1.2948 +    else {  // larger than HTML table, drop by 33%
  1.2949 +      smallerSize = NSToCoordRound(float(aFontSize) / 1.5);
  1.2950 +    }
  1.2951 +  }
  1.2952 +  else { // smaller than HTML table, drop by 1px
  1.2953 +    smallerSize = std::max(aFontSize - onePx, onePx);
  1.2954 +  }
  1.2955 +  return smallerSize;
  1.2956 +}
  1.2957 +
  1.2958 +//------------------------------------------------------------------------------
  1.2959 +//
  1.2960 +//------------------------------------------------------------------------------
  1.2961 +
  1.2962 +/* static */ nscoord
  1.2963 +nsRuleNode::FindNextLargerFontSize(nscoord aFontSize, int32_t aBasePointSize, 
  1.2964 +                                   nsPresContext* aPresContext,
  1.2965 +                                   nsFontSizeType aFontSizeType)
  1.2966 +{
  1.2967 +  int32_t index;
  1.2968 +  int32_t indexMin;
  1.2969 +  int32_t indexMax;
  1.2970 +  float relativePosition;
  1.2971 +  nscoord adjustment;
  1.2972 +  nscoord largerSize;
  1.2973 +  nscoord indexFontSize = aFontSize; // XXX initialize to quell a spurious gcc3.2 warning
  1.2974 +  nscoord smallestIndexFontSize;
  1.2975 +  nscoord largestIndexFontSize;
  1.2976 +  nscoord smallerIndexFontSize;
  1.2977 +  nscoord largerIndexFontSize;
  1.2978 +
  1.2979 +  nscoord onePx = nsPresContext::CSSPixelsToAppUnits(1);
  1.2980 +
  1.2981 +  if (aFontSizeType == eFontSize_HTML) {
  1.2982 +    indexMin = 1;
  1.2983 +    indexMax = 7;
  1.2984 +  } else {
  1.2985 +    indexMin = 0;
  1.2986 +    indexMax = 6;
  1.2987 +  }
  1.2988 +  
  1.2989 +  smallestIndexFontSize = CalcFontPointSize(indexMin, aBasePointSize, aPresContext, aFontSizeType);
  1.2990 +  largestIndexFontSize = CalcFontPointSize(indexMax, aBasePointSize, aPresContext, aFontSizeType); 
  1.2991 +  if (aFontSize > (smallestIndexFontSize - onePx)) {
  1.2992 +    if (aFontSize < largestIndexFontSize) { // larger will be in HTML table
  1.2993 +      // find smallest index larger than current
  1.2994 +      for (index = indexMin; index <= indexMax; index++) { 
  1.2995 +        indexFontSize = CalcFontPointSize(index, aBasePointSize, aPresContext, aFontSizeType);
  1.2996 +        if (indexFontSize > aFontSize)
  1.2997 +          break;
  1.2998 +      }
  1.2999 +      // set up points beyond table for interpolation purposes
  1.3000 +      if (indexFontSize == smallestIndexFontSize) {
  1.3001 +        smallerIndexFontSize = indexFontSize - onePx;
  1.3002 +        largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
  1.3003 +      } else if (indexFontSize == largestIndexFontSize) {
  1.3004 +        smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
  1.3005 +        largerIndexFontSize = NSCoordSaturatingMultiply(largestIndexFontSize, 1.5);
  1.3006 +      } else {
  1.3007 +        smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
  1.3008 +        largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
  1.3009 +      }
  1.3010 +      // compute the relative position of the parent size between the two closest indexed sizes
  1.3011 +      relativePosition = float(aFontSize - smallerIndexFontSize) / float(indexFontSize - smallerIndexFontSize);
  1.3012 +      // set the new size to have the same relative position between the next largest two indexed sizes
  1.3013 +      adjustment = NSCoordSaturatingNonnegativeMultiply(largerIndexFontSize - indexFontSize, relativePosition);
  1.3014 +      largerSize = NSCoordSaturatingAdd(indexFontSize, adjustment);
  1.3015 +    }
  1.3016 +    else {  // larger than HTML table, increase by 50%
  1.3017 +      largerSize = NSCoordSaturatingMultiply(aFontSize, 1.5);
  1.3018 +    }
  1.3019 +  }
  1.3020 +  else { // smaller than HTML table, increase by 1px
  1.3021 +    largerSize = NSCoordSaturatingAdd(aFontSize, onePx);
  1.3022 +  }
  1.3023 +  return largerSize;
  1.3024 +}
  1.3025 +
  1.3026 +struct SetFontSizeCalcOps : public css::BasicCoordCalcOps,
  1.3027 +                            public css::NumbersAlreadyNormalizedOps
  1.3028 +{
  1.3029 +  // The parameters beyond aValue that we need for CalcLengthWith.
  1.3030 +  const nscoord mParentSize;
  1.3031 +  const nsStyleFont* const mParentFont;
  1.3032 +  nsPresContext* const mPresContext;
  1.3033 +  const bool mAtRoot;
  1.3034 +  bool& mCanStoreInRuleTree;
  1.3035 +
  1.3036 +  SetFontSizeCalcOps(nscoord aParentSize, const nsStyleFont* aParentFont,
  1.3037 +                     nsPresContext* aPresContext, bool aAtRoot,
  1.3038 +                     bool& aCanStoreInRuleTree)
  1.3039 +    : mParentSize(aParentSize),
  1.3040 +      mParentFont(aParentFont),
  1.3041 +      mPresContext(aPresContext),
  1.3042 +      mAtRoot(aAtRoot),
  1.3043 +      mCanStoreInRuleTree(aCanStoreInRuleTree)
  1.3044 +  {
  1.3045 +  }
  1.3046 +
  1.3047 +  result_type ComputeLeafValue(const nsCSSValue& aValue)
  1.3048 +  {
  1.3049 +    nscoord size;
  1.3050 +    if (aValue.IsLengthUnit()) {
  1.3051 +      // Note that font-based length units use the parent's size
  1.3052 +      // unadjusted for scriptlevel changes. A scriptlevel change
  1.3053 +      // between us and the parent is simply ignored.
  1.3054 +      size = CalcLengthWith(aValue, mParentSize,
  1.3055 +                            mParentFont,
  1.3056 +                            nullptr, mPresContext, mAtRoot,
  1.3057 +                            true, mCanStoreInRuleTree);
  1.3058 +      if (!aValue.IsRelativeLengthUnit() && mParentFont->mAllowZoom) {
  1.3059 +        size = nsStyleFont::ZoomText(mPresContext, size);
  1.3060 +      }
  1.3061 +    }
  1.3062 +    else if (eCSSUnit_Percent == aValue.GetUnit()) {
  1.3063 +      mCanStoreInRuleTree = false;
  1.3064 +      // Note that % units use the parent's size unadjusted for scriptlevel
  1.3065 +      // changes. A scriptlevel change between us and the parent is simply
  1.3066 +      // ignored.
  1.3067 +      // aValue.GetPercentValue() may be negative for, e.g., calc(-50%)
  1.3068 +      size = NSCoordSaturatingMultiply(mParentSize, aValue.GetPercentValue());
  1.3069 +    } else {
  1.3070 +      NS_ABORT_IF_FALSE(false, "unexpected value");
  1.3071 +      size = mParentSize;
  1.3072 +    }
  1.3073 +
  1.3074 +    return size;
  1.3075 +  }
  1.3076 +};
  1.3077 +
  1.3078 +/* static */ void
  1.3079 +nsRuleNode::SetFontSize(nsPresContext* aPresContext,
  1.3080 +                        const nsRuleData* aRuleData,
  1.3081 +                        const nsStyleFont* aFont,
  1.3082 +                        const nsStyleFont* aParentFont,
  1.3083 +                        nscoord* aSize,
  1.3084 +                        const nsFont& aSystemFont,
  1.3085 +                        nscoord aParentSize,
  1.3086 +                        nscoord aScriptLevelAdjustedParentSize,
  1.3087 +                        bool aUsedStartStruct,
  1.3088 +                        bool aAtRoot,
  1.3089 +                        bool& aCanStoreInRuleTree)
  1.3090 +{
  1.3091 +  // If false, means that *aSize has not been zoomed.  If true, means that
  1.3092 +  // *aSize has been zoomed iff aParentFont->mAllowZoom is true.
  1.3093 +  bool sizeIsZoomedAccordingToParent = false;
  1.3094 +
  1.3095 +  int32_t baseSize = (int32_t) aPresContext->
  1.3096 +    GetDefaultFont(aFont->mGenericID, aFont->mLanguage)->size;
  1.3097 +  const nsCSSValue* sizeValue = aRuleData->ValueForFontSize();
  1.3098 +  if (eCSSUnit_Enumerated == sizeValue->GetUnit()) {
  1.3099 +    int32_t value = sizeValue->GetIntValue();
  1.3100 +
  1.3101 +    if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) &&
  1.3102 +        (value <= NS_STYLE_FONT_SIZE_XXLARGE)) {
  1.3103 +      *aSize = CalcFontPointSize(value, baseSize,
  1.3104 +                       aPresContext, eFontSize_CSS);
  1.3105 +    }
  1.3106 +    else if (NS_STYLE_FONT_SIZE_XXXLARGE == value) {
  1.3107 +      // <font size="7"> is not specified in CSS, so we don't use eFontSize_CSS.
  1.3108 +      *aSize = CalcFontPointSize(value, baseSize, aPresContext);
  1.3109 +    }
  1.3110 +    else if (NS_STYLE_FONT_SIZE_LARGER  == value ||
  1.3111 +             NS_STYLE_FONT_SIZE_SMALLER == value) {
  1.3112 +      aCanStoreInRuleTree = false;
  1.3113 +
  1.3114 +      // Un-zoom so we use the tables correctly.  We'll then rezoom due
  1.3115 +      // to the |zoom = true| above.
  1.3116 +      // Note that relative units here use the parent's size unadjusted
  1.3117 +      // for scriptlevel changes. A scriptlevel change between us and the parent
  1.3118 +      // is simply ignored.
  1.3119 +      nscoord parentSize = aParentSize;
  1.3120 +      if (aParentFont->mAllowZoom) {
  1.3121 +        parentSize = nsStyleFont::UnZoomText(aPresContext, parentSize);
  1.3122 +      }
  1.3123 +
  1.3124 +      if (NS_STYLE_FONT_SIZE_LARGER == value) {
  1.3125 +        *aSize = FindNextLargerFontSize(parentSize,
  1.3126 +                         baseSize, aPresContext, eFontSize_CSS);
  1.3127 +
  1.3128 +        NS_ASSERTION(*aSize >= parentSize,
  1.3129 +                     "FindNextLargerFontSize failed");
  1.3130 +      }
  1.3131 +      else {
  1.3132 +        *aSize = FindNextSmallerFontSize(parentSize,
  1.3133 +                         baseSize, aPresContext, eFontSize_CSS);
  1.3134 +        NS_ASSERTION(*aSize < parentSize ||
  1.3135 +                     parentSize <= nsPresContext::CSSPixelsToAppUnits(1),
  1.3136 +                     "FindNextSmallerFontSize failed");
  1.3137 +      }
  1.3138 +    } else {
  1.3139 +      NS_NOTREACHED("unexpected value");
  1.3140 +    }
  1.3141 +  }
  1.3142 +  else if (sizeValue->IsLengthUnit() ||
  1.3143 +           sizeValue->GetUnit() == eCSSUnit_Percent ||
  1.3144 +           sizeValue->IsCalcUnit()) {
  1.3145 +    SetFontSizeCalcOps ops(aParentSize, aParentFont,
  1.3146 +                           aPresContext, aAtRoot,
  1.3147 +                           aCanStoreInRuleTree);
  1.3148 +    *aSize = css::ComputeCalc(*sizeValue, ops);
  1.3149 +    if (*aSize < 0) {
  1.3150 +      NS_ABORT_IF_FALSE(sizeValue->IsCalcUnit(),
  1.3151 +                        "negative lengths and percents should be rejected "
  1.3152 +                        "by parser");
  1.3153 +      *aSize = 0;
  1.3154 +    }
  1.3155 +    // The calc ops will always zoom its result according to the value
  1.3156 +    // of aParentFont->mAllowZoom.
  1.3157 +    sizeIsZoomedAccordingToParent = true;
  1.3158 +  }
  1.3159 +  else if (eCSSUnit_System_Font == sizeValue->GetUnit()) {
  1.3160 +    // this becomes our cascading size
  1.3161 +    *aSize = aSystemFont.size;
  1.3162 +  }
  1.3163 +  else if (eCSSUnit_Inherit == sizeValue->GetUnit() ||
  1.3164 +           eCSSUnit_Unset == sizeValue->GetUnit()) {
  1.3165 +    aCanStoreInRuleTree = false;
  1.3166 +    // We apply scriptlevel change for this case, because the default is
  1.3167 +    // to inherit and we don't want explicit "inherit" to differ from the
  1.3168 +    // default.
  1.3169 +    *aSize = aScriptLevelAdjustedParentSize;
  1.3170 +    sizeIsZoomedAccordingToParent = true;
  1.3171 +  }
  1.3172 +  else if (eCSSUnit_Initial == sizeValue->GetUnit()) {
  1.3173 +    // The initial value is 'medium', which has magical sizing based on
  1.3174 +    // the generic font family, so do that here too.
  1.3175 +    *aSize = baseSize;
  1.3176 +  } else {
  1.3177 +    NS_ASSERTION(eCSSUnit_Null == sizeValue->GetUnit(),
  1.3178 +                 "What kind of font-size value is this?");
  1.3179 +    // if aUsedStartStruct is true, then every single property in the
  1.3180 +    // font struct is being set all at once. This means scriptlevel is not
  1.3181 +    // going to have any influence on the font size; there is no need to
  1.3182 +    // do anything here.
  1.3183 +    if (!aUsedStartStruct && aParentSize != aScriptLevelAdjustedParentSize) {
  1.3184 +      // There was no rule affecting the size but the size has been
  1.3185 +      // affected by the parent's size via scriptlevel change. So we cannot
  1.3186 +      // store the data in the rule tree.
  1.3187 +      aCanStoreInRuleTree = false;
  1.3188 +      *aSize = aScriptLevelAdjustedParentSize;
  1.3189 +      sizeIsZoomedAccordingToParent = true;
  1.3190 +    } else {
  1.3191 +      return;
  1.3192 +    }
  1.3193 +  }
  1.3194 +
  1.3195 +  // We want to zoom the cascaded size so that em-based measurements,
  1.3196 +  // line-heights, etc., work.
  1.3197 +  bool currentlyZoomed = sizeIsZoomedAccordingToParent &&
  1.3198 +                         aParentFont->mAllowZoom;
  1.3199 +  if (!currentlyZoomed && aFont->mAllowZoom) {
  1.3200 +    *aSize = nsStyleFont::ZoomText(aPresContext, *aSize);
  1.3201 +  } else if (currentlyZoomed && !aFont->mAllowZoom) {
  1.3202 +    *aSize = nsStyleFont::UnZoomText(aPresContext, *aSize);
  1.3203 +  }
  1.3204 +}
  1.3205 +
  1.3206 +static int8_t ClampTo8Bit(int32_t aValue) {
  1.3207 +  if (aValue < -128)
  1.3208 +    return -128;
  1.3209 +  if (aValue > 127)
  1.3210 +    return 127;
  1.3211 +  return int8_t(aValue);
  1.3212 +}
  1.3213 +
  1.3214 +/* static */ void
  1.3215 +nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
  1.3216 +                    uint8_t aGenericFontID, const nsRuleData* aRuleData,
  1.3217 +                    const nsStyleFont* aParentFont,
  1.3218 +                    nsStyleFont* aFont, bool aUsedStartStruct,
  1.3219 +                    bool& aCanStoreInRuleTree)
  1.3220 +{
  1.3221 +  bool atRoot = !aContext->GetParent();
  1.3222 +
  1.3223 +  // -x-text-zoom: none, inherit, initial
  1.3224 +  bool allowZoom;
  1.3225 +  const nsCSSValue* textZoomValue = aRuleData->ValueForTextZoom();
  1.3226 +  if (eCSSUnit_Null != textZoomValue->GetUnit()) {
  1.3227 +    if (eCSSUnit_Inherit == textZoomValue->GetUnit()) {
  1.3228 +      allowZoom = aParentFont->mAllowZoom;
  1.3229 +    } else if (eCSSUnit_None == textZoomValue->GetUnit()) {
  1.3230 +      allowZoom = false;
  1.3231 +    } else {
  1.3232 +      MOZ_ASSERT(eCSSUnit_Initial == textZoomValue->GetUnit(),
  1.3233 +                 "unexpected unit");
  1.3234 +      allowZoom = true;
  1.3235 +    }
  1.3236 +    aFont->EnableZoom(aPresContext, allowZoom);
  1.3237 +  }
  1.3238 +
  1.3239 +  // mLanguage must be set before before any of the CalcLengthWith calls
  1.3240 +  // (direct calls or calls via SetFontSize) for the cases where |aParentFont|
  1.3241 +  // is the same as |aFont|.
  1.3242 +  //
  1.3243 +  // -x-lang: string, inherit
  1.3244 +  // This is not a real CSS property, it is an HTML attribute mapped to CSS.
  1.3245 +  const nsCSSValue* langValue = aRuleData->ValueForLang();
  1.3246 +  if (eCSSUnit_Ident == langValue->GetUnit()) {
  1.3247 +    nsAutoString lang;
  1.3248 +    langValue->GetStringValue(lang);
  1.3249 +
  1.3250 +    nsContentUtils::ASCIIToLower(lang);
  1.3251 +    aFont->mLanguage = do_GetAtom(lang);
  1.3252 +    aFont->mExplicitLanguage = true;
  1.3253 +  }
  1.3254 +
  1.3255 +  const nsFont* defaultVariableFont =
  1.3256 +    aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
  1.3257 +                                 aFont->mLanguage);
  1.3258 +
  1.3259 +  // XXX: Bleh. Disable these somehow?
  1.3260 +  // -moz-system-font: enum (never inherit!)
  1.3261 +  static_assert(
  1.3262 +    NS_STYLE_FONT_CAPTION        == LookAndFeel::eFont_Caption &&
  1.3263 +    NS_STYLE_FONT_ICON           == LookAndFeel::eFont_Icon &&
  1.3264 +    NS_STYLE_FONT_MENU           == LookAndFeel::eFont_Menu &&
  1.3265 +    NS_STYLE_FONT_MESSAGE_BOX    == LookAndFeel::eFont_MessageBox &&
  1.3266 +    NS_STYLE_FONT_SMALL_CAPTION  == LookAndFeel::eFont_SmallCaption &&
  1.3267 +    NS_STYLE_FONT_STATUS_BAR     == LookAndFeel::eFont_StatusBar &&
  1.3268 +    NS_STYLE_FONT_WINDOW         == LookAndFeel::eFont_Window &&
  1.3269 +    NS_STYLE_FONT_DOCUMENT       == LookAndFeel::eFont_Document &&
  1.3270 +    NS_STYLE_FONT_WORKSPACE      == LookAndFeel::eFont_Workspace &&
  1.3271 +    NS_STYLE_FONT_DESKTOP        == LookAndFeel::eFont_Desktop &&
  1.3272 +    NS_STYLE_FONT_INFO           == LookAndFeel::eFont_Info &&
  1.3273 +    NS_STYLE_FONT_DIALOG         == LookAndFeel::eFont_Dialog &&
  1.3274 +    NS_STYLE_FONT_BUTTON         == LookAndFeel::eFont_Button &&
  1.3275 +    NS_STYLE_FONT_PULL_DOWN_MENU == LookAndFeel::eFont_PullDownMenu &&
  1.3276 +    NS_STYLE_FONT_LIST           == LookAndFeel::eFont_List &&
  1.3277 +    NS_STYLE_FONT_FIELD          == LookAndFeel::eFont_Field,
  1.3278 +    "LookAndFeel.h system-font constants out of sync with nsStyleConsts.h");
  1.3279 +
  1.3280 +  // Fall back to defaultVariableFont.
  1.3281 +  nsFont systemFont = *defaultVariableFont;
  1.3282 +  const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
  1.3283 +  if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
  1.3284 +    gfxFontStyle fontStyle;
  1.3285 +    LookAndFeel::FontID fontID =
  1.3286 +      (LookAndFeel::FontID)systemFontValue->GetIntValue();
  1.3287 +    float devPerCSS =
  1.3288 +      (float)nsPresContext::AppUnitsPerCSSPixel() /
  1.3289 +      aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
  1.3290 +    if (LookAndFeel::GetFont(fontID, systemFont.name, fontStyle, devPerCSS)) {
  1.3291 +      systemFont.style = fontStyle.style;
  1.3292 +      systemFont.systemFont = fontStyle.systemFont;
  1.3293 +      systemFont.variant = NS_FONT_VARIANT_NORMAL;
  1.3294 +      systemFont.weight = fontStyle.weight;
  1.3295 +      systemFont.stretch = fontStyle.stretch;
  1.3296 +      systemFont.decorations = NS_FONT_DECORATION_NONE;
  1.3297 +      systemFont.size = NSFloatPixelsToAppUnits(fontStyle.size,
  1.3298 +                                                aPresContext->DeviceContext()->
  1.3299 +                                                UnscaledAppUnitsPerDevPixel());
  1.3300 +      //systemFont.langGroup = fontStyle.langGroup;
  1.3301 +      systemFont.sizeAdjust = fontStyle.sizeAdjust;
  1.3302 +
  1.3303 +#ifdef XP_WIN
  1.3304 +      // XXXldb This platform-specific stuff should be in the
  1.3305 +      // LookAndFeel implementation, not here.
  1.3306 +      // XXXzw Should we even still *have* this code?  It looks to be making
  1.3307 +      // old, probably obsolete assumptions.
  1.3308 +
  1.3309 +      if (fontID == LookAndFeel::eFont_Field ||
  1.3310 +          fontID == LookAndFeel::eFont_Button ||
  1.3311 +          fontID == LookAndFeel::eFont_List) {
  1.3312 +        // As far as I can tell the system default fonts and sizes
  1.3313 +        // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
  1.3314 +        // all pre-determined and cannot be changed by either the control panel
  1.3315 +        // or programmatically.
  1.3316 +        // Fields (text fields)
  1.3317 +        // Button and Selects (listboxes/comboboxes)
  1.3318 +        //    We use whatever font is defined by the system. Which it appears
  1.3319 +        //    (and the assumption is) it is always a proportional font. Then we
  1.3320 +        //    always use 2 points smaller than what the browser has defined as
  1.3321 +        //    the default proportional font.
  1.3322 +        // Assumption: system defined font is proportional
  1.3323 +        systemFont.size =
  1.3324 +          std::max(defaultVariableFont->size -
  1.3325 +                 nsPresContext::CSSPointsToAppUnits(2), 0);
  1.3326 +      }
  1.3327 +#endif
  1.3328 +    }
  1.3329 +  }
  1.3330 +
  1.3331 +  // font-family: string list, enum, inherit
  1.3332 +  const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
  1.3333 +  NS_ASSERTION(eCSSUnit_Enumerated != familyValue->GetUnit(),
  1.3334 +               "system fonts should not be in mFamily anymore");
  1.3335 +  if (eCSSUnit_Families == familyValue->GetUnit()) {
  1.3336 +    // set the correct font if we are using DocumentFonts OR we are overriding for XUL
  1.3337 +    // MJA: bug 31816
  1.3338 +    if (aGenericFontID == kGenericFont_NONE) {
  1.3339 +      // only bother appending fallback fonts if this isn't a fallback generic font itself
  1.3340 +      if (!aFont->mFont.name.IsEmpty())
  1.3341 +        aFont->mFont.name.Append((char16_t)',');
  1.3342 +      // defaultVariableFont.name should always be "serif" or "sans-serif".
  1.3343 +      aFont->mFont.name.Append(defaultVariableFont->name);
  1.3344 +    }
  1.3345 +    aFont->mFont.systemFont = false;
  1.3346 +    // Technically this is redundant with the code below, but it's good
  1.3347 +    // to have since we'll still want it once we get rid of
  1.3348 +    // SetGenericFont (bug 380915).
  1.3349 +    aFont->mGenericID = aGenericFontID;
  1.3350 +  }
  1.3351 +  else if (eCSSUnit_System_Font == familyValue->GetUnit()) {
  1.3352 +    aFont->mFont.name = systemFont.name;
  1.3353 +    aFont->mFont.systemFont = true;
  1.3354 +    aFont->mGenericID = kGenericFont_NONE;
  1.3355 +  }
  1.3356 +  else if (eCSSUnit_Inherit == familyValue->GetUnit() ||
  1.3357 +           eCSSUnit_Unset == familyValue->GetUnit()) {
  1.3358 +    aCanStoreInRuleTree = false;
  1.3359 +    aFont->mFont.name = aParentFont->mFont.name;
  1.3360 +    aFont->mFont.systemFont = aParentFont->mFont.systemFont;
  1.3361 +    aFont->mGenericID = aParentFont->mGenericID;
  1.3362 +  }
  1.3363 +  else if (eCSSUnit_Initial == familyValue->GetUnit()) {
  1.3364 +    aFont->mFont.name = defaultVariableFont->name;
  1.3365 +    aFont->mFont.systemFont = defaultVariableFont->systemFont;
  1.3366 +    aFont->mGenericID = kGenericFont_NONE;
  1.3367 +  }
  1.3368 +
  1.3369 +  // When we're in the loop in SetGenericFont, we must ensure that we
  1.3370 +  // always keep aFont->mFlags set to the correct generic.  But we have
  1.3371 +  // to be careful not to touch it when we're called directly from
  1.3372 +  // ComputeFontData, because we could have a start struct.
  1.3373 +  if (aGenericFontID != kGenericFont_NONE) {
  1.3374 +    aFont->mGenericID = aGenericFontID;
  1.3375 +  }
  1.3376 +
  1.3377 +  // -moz-math-variant: enum, inherit, initial
  1.3378 +  SetDiscrete(*aRuleData->ValueForMathVariant(), aFont->mMathVariant,
  1.3379 +              aCanStoreInRuleTree,
  1.3380 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.3381 +              aParentFont->mMathVariant, NS_MATHML_MATHVARIANT_NONE,
  1.3382 +              0, 0, 0, 0);
  1.3383 +
  1.3384 +  // -moz-math-display: enum, inherit, initial
  1.3385 +  SetDiscrete(*aRuleData->ValueForMathDisplay(), aFont->mMathDisplay,
  1.3386 +              aCanStoreInRuleTree,
  1.3387 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.3388 +              aParentFont->mMathDisplay, NS_MATHML_DISPLAYSTYLE_INLINE,
  1.3389 +              0, 0, 0, 0);
  1.3390 +
  1.3391 +  // font-smoothing: enum, inherit, initial
  1.3392 +  SetDiscrete(*aRuleData->ValueForOSXFontSmoothing(),
  1.3393 +              aFont->mFont.smoothing, aCanStoreInRuleTree,
  1.3394 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.3395 +              aParentFont->mFont.smoothing,
  1.3396 +              defaultVariableFont->smoothing,
  1.3397 +              0, 0, 0, 0);
  1.3398 +
  1.3399 +  // font-style: enum, inherit, initial, -moz-system-font
  1.3400 +  if (aFont->mMathVariant != NS_MATHML_MATHVARIANT_NONE) {
  1.3401 +    // -moz-math-variant overrides font-style
  1.3402 +    aFont->mFont.style = NS_FONT_STYLE_NORMAL;
  1.3403 +  } else {
  1.3404 +    SetDiscrete(*aRuleData->ValueForFontStyle(),
  1.3405 +                aFont->mFont.style, aCanStoreInRuleTree,
  1.3406 +                SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
  1.3407 +                aParentFont->mFont.style,
  1.3408 +                defaultVariableFont->style,
  1.3409 +                0, 0, 0, systemFont.style);
  1.3410 +  }
  1.3411 +
  1.3412 +  // font-variant: enum, inherit, initial, -moz-system-font
  1.3413 +  SetDiscrete(*aRuleData->ValueForFontVariant(),
  1.3414 +              aFont->mFont.variant, aCanStoreInRuleTree,
  1.3415 +              SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
  1.3416 +              aParentFont->mFont.variant,
  1.3417 +              defaultVariableFont->variant,
  1.3418 +              0, 0, 0, systemFont.variant);
  1.3419 +
  1.3420 +  // font-weight: int, enum, inherit, initial, -moz-system-font
  1.3421 +  // special handling for enum
  1.3422 +  const nsCSSValue* weightValue = aRuleData->ValueForFontWeight();
  1.3423 +  if (aFont->mMathVariant != NS_MATHML_MATHVARIANT_NONE) {
  1.3424 +    // -moz-math-variant overrides font-weight
  1.3425 +    aFont->mFont.weight = NS_FONT_WEIGHT_NORMAL;
  1.3426 +  } else if (eCSSUnit_Enumerated == weightValue->GetUnit()) {
  1.3427 +    int32_t value = weightValue->GetIntValue();
  1.3428 +    switch (value) {
  1.3429 +      case NS_STYLE_FONT_WEIGHT_NORMAL:
  1.3430 +      case NS_STYLE_FONT_WEIGHT_BOLD:
  1.3431 +        aFont->mFont.weight = value;
  1.3432 +        break;
  1.3433 +      case NS_STYLE_FONT_WEIGHT_BOLDER: {
  1.3434 +        aCanStoreInRuleTree = false;
  1.3435 +        int32_t inheritedValue = aParentFont->mFont.weight;
  1.3436 +        if (inheritedValue <= 300) {
  1.3437 +          aFont->mFont.weight = 400;
  1.3438 +        } else if (inheritedValue <= 500) {
  1.3439 +          aFont->mFont.weight = 700;
  1.3440 +        } else {
  1.3441 +          aFont->mFont.weight = 900;
  1.3442 +        }
  1.3443 +        break;
  1.3444 +      }
  1.3445 +      case NS_STYLE_FONT_WEIGHT_LIGHTER: {
  1.3446 +        aCanStoreInRuleTree = false;
  1.3447 +        int32_t inheritedValue = aParentFont->mFont.weight;
  1.3448 +        if (inheritedValue < 600) {
  1.3449 +          aFont->mFont.weight = 100;
  1.3450 +        } else if (inheritedValue < 800) {
  1.3451 +          aFont->mFont.weight = 400;
  1.3452 +        } else {
  1.3453 +          aFont->mFont.weight = 700;
  1.3454 +        }
  1.3455 +        break;
  1.3456 +      }
  1.3457 +    }
  1.3458 +  } else
  1.3459 +    SetDiscrete(*weightValue, aFont->mFont.weight, aCanStoreInRuleTree,
  1.3460 +                SETDSC_INTEGER | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
  1.3461 +                aParentFont->mFont.weight,
  1.3462 +                defaultVariableFont->weight,
  1.3463 +                0, 0, 0, systemFont.weight);
  1.3464 +
  1.3465 +  // font-stretch: enum, inherit, initial, -moz-system-font
  1.3466 +  SetDiscrete(*aRuleData->ValueForFontStretch(),
  1.3467 +              aFont->mFont.stretch, aCanStoreInRuleTree,
  1.3468 +              SETDSC_SYSTEM_FONT | SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.3469 +              aParentFont->mFont.stretch,
  1.3470 +              defaultVariableFont->stretch,
  1.3471 +              0, 0, 0, systemFont.stretch);
  1.3472 +
  1.3473 +  // Compute scriptlevel, scriptminsize and scriptsizemultiplier now so
  1.3474 +  // they're available for font-size computation.
  1.3475 +
  1.3476 +  // -moz-script-min-size: length
  1.3477 +  const nsCSSValue* scriptMinSizeValue = aRuleData->ValueForScriptMinSize();
  1.3478 +  if (scriptMinSizeValue->IsLengthUnit()) {
  1.3479 +    // scriptminsize in font units (em, ex) has to be interpreted relative
  1.3480 +    // to the parent font, or the size definitions are circular and we
  1.3481 +    //
  1.3482 +    aFont->mScriptMinSize =
  1.3483 +      CalcLengthWith(*scriptMinSizeValue, aParentFont->mSize,
  1.3484 +                     aParentFont,
  1.3485 +                     nullptr, aPresContext, atRoot, true,
  1.3486 +                     aCanStoreInRuleTree);
  1.3487 +  }
  1.3488 +
  1.3489 +  // -moz-script-size-multiplier: factor, inherit, initial
  1.3490 +  SetFactor(*aRuleData->ValueForScriptSizeMultiplier(),
  1.3491 +            aFont->mScriptSizeMultiplier,
  1.3492 +            aCanStoreInRuleTree, aParentFont->mScriptSizeMultiplier,
  1.3493 +            NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER,
  1.3494 +            SETFCT_POSITIVE | SETFCT_UNSET_INHERIT);
  1.3495 +
  1.3496 +  // -moz-script-level: integer, number, inherit
  1.3497 +  const nsCSSValue* scriptLevelValue = aRuleData->ValueForScriptLevel();
  1.3498 +  if (eCSSUnit_Integer == scriptLevelValue->GetUnit()) {
  1.3499 +    // "relative"
  1.3500 +    aCanStoreInRuleTree = false;
  1.3501 +    aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel + scriptLevelValue->GetIntValue());
  1.3502 +  }
  1.3503 +  else if (eCSSUnit_Number == scriptLevelValue->GetUnit()) {
  1.3504 +    // "absolute"
  1.3505 +    aFont->mScriptLevel = ClampTo8Bit(int32_t(scriptLevelValue->GetFloatValue()));
  1.3506 +  }
  1.3507 +  else if (eCSSUnit_Auto == scriptLevelValue->GetUnit()) {
  1.3508 +    // auto
  1.3509 +    aCanStoreInRuleTree = false;
  1.3510 +    aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel +
  1.3511 +                                      (aParentFont->mMathDisplay ==
  1.3512 +                                       NS_MATHML_DISPLAYSTYLE_INLINE ? 1 : 0));
  1.3513 +  }
  1.3514 +  else if (eCSSUnit_Inherit == scriptLevelValue->GetUnit() ||
  1.3515 +           eCSSUnit_Unset == scriptLevelValue->GetUnit()) {
  1.3516 +    aCanStoreInRuleTree = false;
  1.3517 +    aFont->mScriptLevel = aParentFont->mScriptLevel;
  1.3518 +  }
  1.3519 +  else if (eCSSUnit_Initial == scriptLevelValue->GetUnit()) {
  1.3520 +    aFont->mScriptLevel = 0;
  1.3521 +  }
  1.3522 +
  1.3523 +  // font-kerning: none, enum, inherit, initial, -moz-system-font
  1.3524 +  SetDiscrete(*aRuleData->ValueForFontKerning(),
  1.3525 +              aFont->mFont.kerning, aCanStoreInRuleTree,
  1.3526 +              SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
  1.3527 +              aParentFont->mFont.kerning,
  1.3528 +              defaultVariableFont->kerning,
  1.3529 +              0, 0, 0, systemFont.kerning);
  1.3530 +
  1.3531 +  // font-synthesis: none, enum (bit field), inherit, initial, -moz-system-font
  1.3532 +  SetDiscrete(*aRuleData->ValueForFontSynthesis(),
  1.3533 +              aFont->mFont.synthesis, aCanStoreInRuleTree,
  1.3534 +              SETDSC_NONE | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  1.3535 +                SETDSC_UNSET_INHERIT,
  1.3536 +              aParentFont->mFont.synthesis,
  1.3537 +              defaultVariableFont->synthesis,
  1.3538 +              0, 0, 0, systemFont.synthesis);
  1.3539 +
  1.3540 +  // font-variant-alternates: normal, enum (bit field) + functions, inherit,
  1.3541 +  //                          initial, -moz-system-font
  1.3542 +  const nsCSSValue* variantAlternatesValue =
  1.3543 +    aRuleData->ValueForFontVariantAlternates();
  1.3544 +  int32_t variantAlternates = 0;
  1.3545 +
  1.3546 +  switch (variantAlternatesValue->GetUnit()) {
  1.3547 +  case eCSSUnit_Inherit:
  1.3548 +  case eCSSUnit_Unset:
  1.3549 +    aFont->mFont.CopyAlternates(aParentFont->mFont);
  1.3550 +    aCanStoreInRuleTree = false;
  1.3551 +    break;
  1.3552 +
  1.3553 +  case eCSSUnit_Initial:
  1.3554 +  case eCSSUnit_Normal:
  1.3555 +    aFont->mFont.variantAlternates = 0;
  1.3556 +    aFont->mFont.alternateValues.Clear();
  1.3557 +    aFont->mFont.featureValueLookup = nullptr;
  1.3558 +    break;
  1.3559 +
  1.3560 +  case eCSSUnit_Pair:
  1.3561 +    NS_ASSERTION(variantAlternatesValue->GetPairValue().mXValue.GetUnit() ==
  1.3562 +                   eCSSUnit_Enumerated, "strange unit for variantAlternates");
  1.3563 +    variantAlternates =
  1.3564 +      variantAlternatesValue->GetPairValue().mXValue.GetIntValue();
  1.3565 +    aFont->mFont.variantAlternates = variantAlternates;
  1.3566 +
  1.3567 +    if (variantAlternates & NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK) {
  1.3568 +      // fetch the feature lookup object from the styleset
  1.3569 +      aFont->mFont.featureValueLookup =
  1.3570 +        aPresContext->StyleSet()->GetFontFeatureValuesLookup();
  1.3571 +
  1.3572 +      NS_ASSERTION(variantAlternatesValue->GetPairValue().mYValue.GetUnit() ==
  1.3573 +                   eCSSUnit_List, "function list not a list value");
  1.3574 +      nsStyleUtil::ComputeFunctionalAlternates(
  1.3575 +        variantAlternatesValue->GetPairValue().mYValue.GetListValue(),
  1.3576 +        aFont->mFont.alternateValues);
  1.3577 +    }
  1.3578 +    break;
  1.3579 +
  1.3580 +  default:
  1.3581 +    break;
  1.3582 +  }
  1.3583 +
  1.3584 +  // font-variant-caps: normal, enum, inherit, initial, -moz-system-font
  1.3585 +  SetDiscrete(*aRuleData->ValueForFontVariantCaps(),
  1.3586 +              aFont->mFont.variantCaps, aCanStoreInRuleTree,
  1.3587 +              SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  1.3588 +                SETDSC_UNSET_INHERIT,
  1.3589 +              aParentFont->mFont.variantCaps,
  1.3590 +              defaultVariableFont->variantCaps,
  1.3591 +              0, 0, 0, systemFont.variantCaps);
  1.3592 +
  1.3593 +  // font-variant-east-asian: normal, enum (bit field), inherit, initial,
  1.3594 +  //                          -moz-system-font
  1.3595 +  SetDiscrete(*aRuleData->ValueForFontVariantEastAsian(),
  1.3596 +              aFont->mFont.variantEastAsian, aCanStoreInRuleTree,
  1.3597 +              SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  1.3598 +                SETDSC_UNSET_INHERIT,
  1.3599 +              aParentFont->mFont.variantEastAsian,
  1.3600 +              defaultVariableFont->variantEastAsian,
  1.3601 +              0, 0, 0, systemFont.variantEastAsian);
  1.3602 +
  1.3603 +  // font-variant-ligatures: normal, enum (bit field), inherit, initial,
  1.3604 +  //                         -moz-system-font
  1.3605 +  SetDiscrete(*aRuleData->ValueForFontVariantLigatures(),
  1.3606 +              aFont->mFont.variantLigatures, aCanStoreInRuleTree,
  1.3607 +              SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  1.3608 +                SETDSC_UNSET_INHERIT,
  1.3609 +              aParentFont->mFont.variantLigatures,
  1.3610 +              defaultVariableFont->variantLigatures,
  1.3611 +              0, 0, 0, systemFont.variantLigatures);
  1.3612 +
  1.3613 +  // font-variant-numeric: normal, enum (bit field), inherit, initial,
  1.3614 +  //                       -moz-system-font
  1.3615 +  SetDiscrete(*aRuleData->ValueForFontVariantNumeric(),
  1.3616 +              aFont->mFont.variantNumeric, aCanStoreInRuleTree,
  1.3617 +              SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  1.3618 +                SETDSC_UNSET_INHERIT,
  1.3619 +              aParentFont->mFont.variantNumeric,
  1.3620 +              defaultVariableFont->variantNumeric,
  1.3621 +              0, 0, 0, systemFont.variantNumeric);
  1.3622 +
  1.3623 +  // font-variant-position: normal, enum, inherit, initial,
  1.3624 +  //                        -moz-system-font
  1.3625 +  SetDiscrete(*aRuleData->ValueForFontVariantPosition(),
  1.3626 +              aFont->mFont.variantPosition, aCanStoreInRuleTree,
  1.3627 +              SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
  1.3628 +                SETDSC_UNSET_INHERIT,
  1.3629 +              aParentFont->mFont.variantPosition,
  1.3630 +              defaultVariableFont->variantPosition,
  1.3631 +              0, 0, 0, systemFont.variantPosition);
  1.3632 +
  1.3633 +  // font-feature-settings
  1.3634 +  const nsCSSValue* featureSettingsValue =
  1.3635 +    aRuleData->ValueForFontFeatureSettings();
  1.3636 +
  1.3637 +  switch (featureSettingsValue->GetUnit()) {
  1.3638 +  case eCSSUnit_Null:
  1.3639 +    break;
  1.3640 +
  1.3641 +  case eCSSUnit_Normal:
  1.3642 +  case eCSSUnit_Initial:
  1.3643 +    aFont->mFont.fontFeatureSettings.Clear();
  1.3644 +    break;
  1.3645 +
  1.3646 +  case eCSSUnit_Inherit:
  1.3647 +  case eCSSUnit_Unset:
  1.3648 +    aCanStoreInRuleTree = false;
  1.3649 +    aFont->mFont.fontFeatureSettings = aParentFont->mFont.fontFeatureSettings;
  1.3650 +    break;
  1.3651 +
  1.3652 +  case eCSSUnit_System_Font:
  1.3653 +    aFont->mFont.fontFeatureSettings = systemFont.fontFeatureSettings;
  1.3654 +    break;
  1.3655 +
  1.3656 +  case eCSSUnit_PairList:
  1.3657 +  case eCSSUnit_PairListDep:
  1.3658 +    ComputeFontFeatures(featureSettingsValue->GetPairListValue(),
  1.3659 +                        aFont->mFont.fontFeatureSettings);
  1.3660 +    break;
  1.3661 +
  1.3662 +  default:
  1.3663 +    NS_ABORT_IF_FALSE(false, "unexpected value unit");
  1.3664 +    break;
  1.3665 +  }
  1.3666 +
  1.3667 +  // font-language-override
  1.3668 +  const nsCSSValue* languageOverrideValue =
  1.3669 +    aRuleData->ValueForFontLanguageOverride();
  1.3670 +  if (eCSSUnit_Inherit == languageOverrideValue->GetUnit() ||
  1.3671 +      eCSSUnit_Unset == languageOverrideValue->GetUnit()) {
  1.3672 +    aCanStoreInRuleTree = false;
  1.3673 +    aFont->mFont.languageOverride = aParentFont->mFont.languageOverride;
  1.3674 +  } else if (eCSSUnit_Normal == languageOverrideValue->GetUnit() ||
  1.3675 +             eCSSUnit_Initial == languageOverrideValue->GetUnit()) {
  1.3676 +    aFont->mFont.languageOverride.Truncate();
  1.3677 +  } else if (eCSSUnit_System_Font == languageOverrideValue->GetUnit()) {
  1.3678 +    aFont->mFont.languageOverride = systemFont.languageOverride;
  1.3679 +  } else if (eCSSUnit_String == languageOverrideValue->GetUnit()) {
  1.3680 +    languageOverrideValue->GetStringValue(aFont->mFont.languageOverride);
  1.3681 +  }
  1.3682 +
  1.3683 +  // font-size: enum, length, percent, inherit
  1.3684 +  nscoord scriptLevelAdjustedParentSize = aParentFont->mSize;
  1.3685 +  nscoord scriptLevelAdjustedUnconstrainedParentSize;
  1.3686 +  scriptLevelAdjustedParentSize =
  1.3687 +    ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
  1.3688 +                           &scriptLevelAdjustedUnconstrainedParentSize);
  1.3689 +  NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
  1.3690 +               "If we have a start struct, we should have reset everything coming in here");
  1.3691 +  SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
  1.3692 +              &aFont->mSize,
  1.3693 +              systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
  1.3694 +              aUsedStartStruct, atRoot, aCanStoreInRuleTree);
  1.3695 +  if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize &&
  1.3696 +      scriptLevelAdjustedParentSize == scriptLevelAdjustedUnconstrainedParentSize) {
  1.3697 +    // Fast path: we have not been affected by scriptminsize so we don't
  1.3698 +    // need to call SetFontSize again to compute the
  1.3699 +    // scriptminsize-unconstrained size. This is OK even if we have a
  1.3700 +    // start struct, because if we have a start struct then 'font-size'
  1.3701 +    // was specified and so scriptminsize has no effect.
  1.3702 +    aFont->mScriptUnconstrainedSize = aFont->mSize;
  1.3703 +  } else {
  1.3704 +    SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
  1.3705 +                &aFont->mScriptUnconstrainedSize,
  1.3706 +                systemFont, aParentFont->mScriptUnconstrainedSize,
  1.3707 +                scriptLevelAdjustedUnconstrainedParentSize,
  1.3708 +                aUsedStartStruct, atRoot, aCanStoreInRuleTree);
  1.3709 +  }
  1.3710 +  NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
  1.3711 +               "scriptminsize should never be making things bigger");
  1.3712 +
  1.3713 +  nscoord fontSize = aFont->mSize;
  1.3714 +
  1.3715 +  // enforce the user' specified minimum font-size on the value that we expose
  1.3716 +  // (but don't change font-size:0, since that would unhide hidden text)
  1.3717 +  if (fontSize > 0) {
  1.3718 +    nscoord minFontSize = aPresContext->MinFontSize(aFont->mLanguage);
  1.3719 +    if (minFontSize < 0) {
  1.3720 +      minFontSize = 0;
  1.3721 +    }
  1.3722 +    if (fontSize < minFontSize && !aPresContext->IsChrome()) {
  1.3723 +      // override the minimum font-size constraint
  1.3724 +      fontSize = minFontSize;
  1.3725 +    }
  1.3726 +  }
  1.3727 +  aFont->mFont.size = fontSize;
  1.3728 +
  1.3729 +  // font-size-adjust: number, none, inherit, initial, -moz-system-font
  1.3730 +  const nsCSSValue* sizeAdjustValue = aRuleData->ValueForFontSizeAdjust();
  1.3731 +  if (eCSSUnit_System_Font == sizeAdjustValue->GetUnit()) {
  1.3732 +    aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
  1.3733 +  } else
  1.3734 +    SetFactor(*sizeAdjustValue, aFont->mFont.sizeAdjust,
  1.3735 +              aCanStoreInRuleTree, aParentFont->mFont.sizeAdjust, 0.0f,
  1.3736 +              SETFCT_NONE | SETFCT_UNSET_INHERIT);
  1.3737 +}
  1.3738 +
  1.3739 +/* static */ void
  1.3740 +nsRuleNode::ComputeFontFeatures(const nsCSSValuePairList *aFeaturesList,
  1.3741 +                                nsTArray<gfxFontFeature>& aFeatureSettings)
  1.3742 +{
  1.3743 +  aFeatureSettings.Clear();
  1.3744 +  for (const nsCSSValuePairList* p = aFeaturesList; p; p = p->mNext) {
  1.3745 +    gfxFontFeature feat = {0, 0};
  1.3746 +
  1.3747 +    NS_ABORT_IF_FALSE(aFeaturesList->mXValue.GetUnit() == eCSSUnit_String,
  1.3748 +                      "unexpected value unit");
  1.3749 +
  1.3750 +    // tag is a 4-byte ASCII sequence
  1.3751 +    nsAutoString tag;
  1.3752 +    p->mXValue.GetStringValue(tag);
  1.3753 +    if (tag.Length() != 4) {
  1.3754 +      continue;
  1.3755 +    }
  1.3756 +    // parsing validates that these are ASCII chars
  1.3757 +    // tags are always big-endian
  1.3758 +    feat.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8)  | tag[3];
  1.3759 +
  1.3760 +    // value
  1.3761 +    NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Integer,
  1.3762 +                 "should have found an integer unit");
  1.3763 +    feat.mValue = p->mYValue.GetIntValue();
  1.3764 +
  1.3765 +    aFeatureSettings.AppendElement(feat);
  1.3766 +  }
  1.3767 +}
  1.3768 +
  1.3769 +// This should die (bug 380915).
  1.3770 +//
  1.3771 +// SetGenericFont:
  1.3772 +//  - backtrack to an ancestor with the same generic font name (possibly
  1.3773 +//    up to the root where default values come from the presentation context)
  1.3774 +//  - re-apply cascading rules from there without caching intermediate values
  1.3775 +/* static */ void
  1.3776 +nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
  1.3777 +                           nsStyleContext* aContext,
  1.3778 +                           uint8_t aGenericFontID,
  1.3779 +                           nsStyleFont* aFont)
  1.3780 +{
  1.3781 +  // walk up the contexts until a context with the desired generic font
  1.3782 +  nsAutoTArray<nsStyleContext*, 8> contextPath;
  1.3783 +  contextPath.AppendElement(aContext);
  1.3784 +  nsStyleContext* higherContext = aContext->GetParent();
  1.3785 +  while (higherContext) {
  1.3786 +    if (higherContext->StyleFont()->mGenericID == aGenericFontID) {
  1.3787 +      // done walking up the higher contexts
  1.3788 +      break;
  1.3789 +    }
  1.3790 +    contextPath.AppendElement(higherContext);
  1.3791 +    higherContext = higherContext->GetParent();
  1.3792 +  }
  1.3793 +
  1.3794 +  // re-apply the cascading rules, starting from the higher context
  1.3795 +
  1.3796 +  // If we stopped earlier because we reached the root of the style tree,
  1.3797 +  // we will start with the default generic font from the presentation
  1.3798 +  // context. Otherwise we start with the higher context.
  1.3799 +  const nsFont* defaultFont =
  1.3800 +    aPresContext->GetDefaultFont(aGenericFontID, aFont->mLanguage);
  1.3801 +  nsStyleFont parentFont(*defaultFont, aPresContext);
  1.3802 +  if (higherContext) {
  1.3803 +    const nsStyleFont* tmpFont = higherContext->StyleFont();
  1.3804 +    parentFont = *tmpFont;
  1.3805 +  }
  1.3806 +  *aFont = parentFont;
  1.3807 +
  1.3808 +  bool dummy;
  1.3809 +  uint32_t fontBit = nsCachedStyleData::GetBitForSID(eStyleStruct_Font);
  1.3810 +
  1.3811 +  // use placement new[] on the result of alloca() to allocate a
  1.3812 +  // variable-sized stack array, including execution of constructors,
  1.3813 +  // and use an RAII class to run the destructors too.
  1.3814 +  size_t nprops = nsCSSProps::PropertyCountInStruct(eStyleStruct_Font);
  1.3815 +  void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
  1.3816 +
  1.3817 +  for (int32_t i = contextPath.Length() - 1; i >= 0; --i) {
  1.3818 +    nsStyleContext* context = contextPath[i];
  1.3819 +    AutoCSSValueArray dataArray(dataStorage, nprops);
  1.3820 +
  1.3821 +    nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), dataArray.get(),
  1.3822 +                        aPresContext, context);
  1.3823 +    ruleData.mValueOffsets[eStyleStruct_Font] = 0;
  1.3824 +
  1.3825 +    // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
  1.3826 +    // Note that we *do* need to do this for our own data, since what is
  1.3827 +    // in |fontData| in ComputeFontData is only for the rules below
  1.3828 +    // aStartStruct.
  1.3829 +    for (nsRuleNode* ruleNode = context->RuleNode(); ruleNode;
  1.3830 +         ruleNode = ruleNode->GetParent()) {
  1.3831 +      if (ruleNode->mNoneBits & fontBit)
  1.3832 +        // no more font rules on this branch, get out
  1.3833 +        break;
  1.3834 +
  1.3835 +      nsIStyleRule *rule = ruleNode->GetRule();
  1.3836 +      if (rule) {
  1.3837 +        ruleData.mLevel = ruleNode->GetLevel();
  1.3838 +        ruleData.mIsImportantRule = ruleNode->IsImportantRule();
  1.3839 +        rule->MapRuleInfoInto(&ruleData);
  1.3840 +      }
  1.3841 +    }
  1.3842 +
  1.3843 +    // Compute the delta from the information that the rules specified
  1.3844 +
  1.3845 +    // Avoid unnecessary operations in SetFont().  But we care if it's
  1.3846 +    // the final value that we're computing.
  1.3847 +    if (i != 0)
  1.3848 +      ruleData.ValueForFontFamily()->Reset();
  1.3849 +
  1.3850 +    ResolveVariableReferences(eStyleStruct_Font, &ruleData, aContext);
  1.3851 +
  1.3852 +    nsRuleNode::SetFont(aPresContext, context,
  1.3853 +                        aGenericFontID, &ruleData, &parentFont, aFont,
  1.3854 +                        false, dummy);
  1.3855 +
  1.3856 +    parentFont = *aFont;
  1.3857 +  }
  1.3858 +}
  1.3859 +
  1.3860 +static bool ExtractGeneric(const nsString& aFamily, bool aGeneric,
  1.3861 +                             void *aData)
  1.3862 +{
  1.3863 +  nsAutoString *data = static_cast<nsAutoString*>(aData);
  1.3864 +
  1.3865 +  if (aGeneric) {
  1.3866 +    *data = aFamily;
  1.3867 +    return false; // stop enumeration
  1.3868 +  }
  1.3869 +  return true;
  1.3870 +}
  1.3871 +
  1.3872 +struct smugglerStruct {
  1.3873 +  nsStyleFont *font;
  1.3874 +  gfxUserFontSet *userFonts;
  1.3875 +};
  1.3876 +
  1.3877 +/* This function forces the use of the first @font-face font we find */
  1.3878 +static bool ForceFirstWebFont(const nsString& aFamily, bool aGeneric,
  1.3879 +                              void *smuggled)
  1.3880 +{
  1.3881 +  smugglerStruct *sm = static_cast<smugglerStruct*>(smuggled);
  1.3882 +    
  1.3883 +  if (aGeneric) {
  1.3884 +    return true;
  1.3885 +  }
  1.3886 +
  1.3887 +  if (sm->userFonts->HasFamily(aFamily)) {
  1.3888 +    // Force use of this exact @font-face font since we have it.
  1.3889 +    sm->font->mFont.name = aFamily;
  1.3890 +
  1.3891 +    return false; // Stop enumeration. 
  1.3892 +  }
  1.3893 +
  1.3894 +  return true;
  1.3895 +}
  1.3896 +
  1.3897 +const void*
  1.3898 +nsRuleNode::ComputeFontData(void* aStartStruct,
  1.3899 +                            const nsRuleData* aRuleData,
  1.3900 +                            nsStyleContext* aContext,
  1.3901 +                            nsRuleNode* aHighestNode,
  1.3902 +                            const RuleDetail aRuleDetail,
  1.3903 +                            const bool aCanStoreInRuleTree)
  1.3904 +{
  1.3905 +  COMPUTE_START_INHERITED(Font, (mPresContext), font, parentFont)
  1.3906 +
  1.3907 +  // NOTE:  The |aRuleDetail| passed in is a little bit conservative due
  1.3908 +  // to the -moz-system-font property.  We really don't need to consider
  1.3909 +  // it here in determining whether to cache in the rule tree.  However,
  1.3910 +  // we do need to consider it in WalkRuleTree when deciding whether to
  1.3911 +  // walk further up the tree.  So this means that when the font struct
  1.3912 +  // is fully specified using *longhand* properties (excluding
  1.3913 +  // -moz-system-font), we won't cache in the rule tree even though we
  1.3914 +  // could.  However, it's pretty unlikely authors will do that
  1.3915 +  // (although there is a pretty good chance they'll fully specify it
  1.3916 +  // using the 'font' shorthand).
  1.3917 +
  1.3918 +  bool useDocumentFonts =
  1.3919 +    mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
  1.3920 +  bool isXUL = PR_FALSE;
  1.3921 +  bool forcedWebFont = false;
  1.3922 +
  1.3923 +  // See if we are in the chrome
  1.3924 +  // We only need to know this to determine if we have to use the
  1.3925 +  // document fonts (overriding the useDocumentFonts flag).
  1.3926 +  if (mPresContext->IsChrome()) {
  1.3927 +    // if we are not using document fonts, but this is a XUL document,
  1.3928 +    // then we use the document fonts anyway
  1.3929 +    isXUL = true;
  1.3930 +  }
  1.3931 +
  1.3932 +  // Figure out if we are a generic font
  1.3933 +  uint8_t generic = kGenericFont_NONE;
  1.3934 +  // XXXldb What if we would have had a string if we hadn't been doing
  1.3935 +  // the optimization with a non-null aStartStruct?
  1.3936 +  const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
  1.3937 +  if (eCSSUnit_Families == familyValue->GetUnit()) {
  1.3938 +    familyValue->GetStringValue(font->mFont.name);
  1.3939 +    // XXXldb Do we want to extract the generic for this if it's not only a
  1.3940 +    // generic?
  1.3941 +    nsFont::GetGenericID(font->mFont.name, &generic);
  1.3942 +
  1.3943 +    if (!isXUL) {
  1.3944 +      gfxUserFontSet *userFonts = mPresContext->GetUserFontSet();
  1.3945 +      if (userFonts) {
  1.3946 +        smugglerStruct sm;
  1.3947 +        sm.userFonts = userFonts;
  1.3948 +        sm.font = font;
  1.3949 +
  1.3950 +        if (!sm.font->mFont.EnumerateFamilies(ForceFirstWebFont, &sm)) {
  1.3951 +          isXUL = true; // Always allow WebFont use.
  1.3952 +          forcedWebFont = true;
  1.3953 +        }
  1.3954 +      }
  1.3955 +    }
  1.3956 +
  1.3957 +    if (!forcedWebFont && generic == kGenericFont_NONE)
  1.3958 +      mPresContext->AddFontAttempt(font->mFont);
  1.3959 +
  1.3960 +    // If we aren't allowed to use document fonts, then we are only entitled
  1.3961 +    // to use the user's default variable-width font and fixed-width font
  1.3962 +    if (!isXUL && (!useDocumentFonts ||
  1.3963 +                    mPresContext->FontAttemptCountReached(font->mFont) ||
  1.3964 +                    mPresContext->FontUseCountReached(font->mFont))) {
  1.3965 +      // Extract the generic from the specified font family...
  1.3966 +      nsAutoString genericName;
  1.3967 +      if (!font->mFont.EnumerateFamilies(ExtractGeneric, &genericName)) {
  1.3968 +        // The specified font had a generic family.
  1.3969 +        font->mFont.name = genericName;
  1.3970 +        nsFont::GetGenericID(genericName, &generic);
  1.3971 +
  1.3972 +        // ... and only use it if it's -moz-fixed or monospace
  1.3973 +        if (generic != kGenericFont_moz_fixed &&
  1.3974 +            generic != kGenericFont_monospace) {
  1.3975 +          font->mFont.name.Truncate();
  1.3976 +          generic = kGenericFont_NONE;
  1.3977 +        }
  1.3978 +      } else {
  1.3979 +        // The specified font did not have a generic family.
  1.3980 +        font->mFont.name.Truncate();
  1.3981 +        generic = kGenericFont_NONE;
  1.3982 +      }
  1.3983 +    }
  1.3984 +  }
  1.3985 +
  1.3986 +  // Now compute our font struct
  1.3987 +  if (generic == kGenericFont_NONE) {
  1.3988 +    // continue the normal processing
  1.3989 +    nsRuleNode::SetFont(mPresContext, aContext, generic,
  1.3990 +                        aRuleData, parentFont, font,
  1.3991 +                        aStartStruct != nullptr, canStoreInRuleTree);
  1.3992 +  }
  1.3993 +  else {
  1.3994 +    // re-calculate the font as a generic font
  1.3995 +    canStoreInRuleTree = false;
  1.3996 +    nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
  1.3997 +                               font);
  1.3998 +  }
  1.3999 +
  1.4000 +  if (!forcedWebFont && font->mGenericID == kGenericFont_NONE)
  1.4001 +    mPresContext->AddFontUse(font->mFont);
  1.4002 +  COMPUTE_END_INHERITED(Font, font)
  1.4003 +}
  1.4004 +
  1.4005 +template <typename T>
  1.4006 +inline uint32_t ListLength(const T* aList)
  1.4007 +{
  1.4008 +  uint32_t len = 0;
  1.4009 +  while (aList) {
  1.4010 +    len++;
  1.4011 +    aList = aList->mNext;
  1.4012 +  }
  1.4013 +  return len;
  1.4014 +}
  1.4015 +
  1.4016 +
  1.4017 +
  1.4018 +already_AddRefed<nsCSSShadowArray>
  1.4019 +nsRuleNode::GetShadowData(const nsCSSValueList* aList,
  1.4020 +                          nsStyleContext* aContext,
  1.4021 +                          bool aIsBoxShadow,
  1.4022 +                          bool& aCanStoreInRuleTree)
  1.4023 +{
  1.4024 +  uint32_t arrayLength = ListLength(aList);
  1.4025 +
  1.4026 +  NS_ABORT_IF_FALSE(arrayLength > 0,
  1.4027 +                    "Non-null text-shadow list, yet we counted 0 items.");
  1.4028 +  nsRefPtr<nsCSSShadowArray> shadowList =
  1.4029 +    new(arrayLength) nsCSSShadowArray(arrayLength);
  1.4030 +
  1.4031 +  if (!shadowList)
  1.4032 +    return nullptr;
  1.4033 +
  1.4034 +  nsStyleCoord tempCoord;
  1.4035 +  DebugOnly<bool> unitOK;
  1.4036 +  for (nsCSSShadowItem* item = shadowList->ShadowAt(0);
  1.4037 +       aList;
  1.4038 +       aList = aList->mNext, ++item) {
  1.4039 +    NS_ABORT_IF_FALSE(aList->mValue.GetUnit() == eCSSUnit_Array,
  1.4040 +                      "expecting a plain array value");
  1.4041 +    nsCSSValue::Array *arr = aList->mValue.GetArrayValue();
  1.4042 +    // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
  1.4043 +    unitOK = SetCoord(arr->Item(0), tempCoord, nsStyleCoord(),
  1.4044 +                      SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
  1.4045 +                      aContext, mPresContext, aCanStoreInRuleTree);
  1.4046 +    NS_ASSERTION(unitOK, "unexpected unit");
  1.4047 +    item->mXOffset = tempCoord.GetCoordValue();
  1.4048 +
  1.4049 +    unitOK = SetCoord(arr->Item(1), tempCoord, nsStyleCoord(),
  1.4050 +                      SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
  1.4051 +                      aContext, mPresContext, aCanStoreInRuleTree);
  1.4052 +    NS_ASSERTION(unitOK, "unexpected unit");
  1.4053 +    item->mYOffset = tempCoord.GetCoordValue();
  1.4054 +
  1.4055 +    // Blur radius is optional in the current box-shadow spec
  1.4056 +    if (arr->Item(2).GetUnit() != eCSSUnit_Null) {
  1.4057 +      unitOK = SetCoord(arr->Item(2), tempCoord, nsStyleCoord(),
  1.4058 +                        SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY |
  1.4059 +                          SETCOORD_CALC_CLAMP_NONNEGATIVE,
  1.4060 +                        aContext, mPresContext, aCanStoreInRuleTree);
  1.4061 +      NS_ASSERTION(unitOK, "unexpected unit");
  1.4062 +      item->mRadius = tempCoord.GetCoordValue();
  1.4063 +    } else {
  1.4064 +      item->mRadius = 0;
  1.4065 +    }
  1.4066 +
  1.4067 +    // Find the spread radius
  1.4068 +    if (aIsBoxShadow && arr->Item(3).GetUnit() != eCSSUnit_Null) {
  1.4069 +      unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(),
  1.4070 +                        SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
  1.4071 +                        aContext, mPresContext, aCanStoreInRuleTree);
  1.4072 +      NS_ASSERTION(unitOK, "unexpected unit");
  1.4073 +      item->mSpread = tempCoord.GetCoordValue();
  1.4074 +    } else {
  1.4075 +      item->mSpread = 0;
  1.4076 +    }
  1.4077 +
  1.4078 +    if (arr->Item(4).GetUnit() != eCSSUnit_Null) {
  1.4079 +      item->mHasColor = true;
  1.4080 +      // 2nd argument can be bogus since inherit is not a valid color
  1.4081 +      unitOK = SetColor(arr->Item(4), 0, mPresContext, aContext, item->mColor,
  1.4082 +                        aCanStoreInRuleTree);
  1.4083 +      NS_ASSERTION(unitOK, "unexpected unit");
  1.4084 +    }
  1.4085 +
  1.4086 +    if (aIsBoxShadow && arr->Item(5).GetUnit() == eCSSUnit_Enumerated) {
  1.4087 +      NS_ASSERTION(arr->Item(5).GetIntValue() == NS_STYLE_BOX_SHADOW_INSET,
  1.4088 +                   "invalid keyword type for box shadow");
  1.4089 +      item->mInset = true;
  1.4090 +    } else {
  1.4091 +      item->mInset = false;
  1.4092 +    }
  1.4093 +  }
  1.4094 +
  1.4095 +  return shadowList.forget();
  1.4096 +}
  1.4097 +
  1.4098 +const void*
  1.4099 +nsRuleNode::ComputeTextData(void* aStartStruct,
  1.4100 +                            const nsRuleData* aRuleData,
  1.4101 +                            nsStyleContext* aContext,
  1.4102 +                            nsRuleNode* aHighestNode,
  1.4103 +                            const RuleDetail aRuleDetail,
  1.4104 +                            const bool aCanStoreInRuleTree)
  1.4105 +{
  1.4106 +  COMPUTE_START_INHERITED(Text, (), text, parentText)
  1.4107 +
  1.4108 +  // tab-size: integer, inherit
  1.4109 +  SetDiscrete(*aRuleData->ValueForTabSize(),
  1.4110 +              text->mTabSize, canStoreInRuleTree,
  1.4111 +              SETDSC_INTEGER | SETDSC_UNSET_INHERIT, parentText->mTabSize,
  1.4112 +              NS_STYLE_TABSIZE_INITIAL, 0, 0, 0, 0);
  1.4113 +
  1.4114 +  // letter-spacing: normal, length, inherit
  1.4115 +  SetCoord(*aRuleData->ValueForLetterSpacing(),
  1.4116 +           text->mLetterSpacing, parentText->mLetterSpacing,
  1.4117 +           SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
  1.4118 +             SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INHERIT,
  1.4119 +           aContext, mPresContext, canStoreInRuleTree);
  1.4120 +
  1.4121 +  // text-shadow: none, list, inherit, initial
  1.4122 +  const nsCSSValue* textShadowValue = aRuleData->ValueForTextShadow();
  1.4123 +  if (textShadowValue->GetUnit() != eCSSUnit_Null) {
  1.4124 +    text->mTextShadow = nullptr;
  1.4125 +
  1.4126 +    // Don't need to handle none/initial explicitly: The above assignment
  1.4127 +    // takes care of that
  1.4128 +    if (textShadowValue->GetUnit() == eCSSUnit_Inherit ||
  1.4129 +        textShadowValue->GetUnit() == eCSSUnit_Unset) {
  1.4130 +      canStoreInRuleTree = false;
  1.4131 +      text->mTextShadow = parentText->mTextShadow;
  1.4132 +    } else if (textShadowValue->GetUnit() == eCSSUnit_List ||
  1.4133 +               textShadowValue->GetUnit() == eCSSUnit_ListDep) {
  1.4134 +      // List of arrays
  1.4135 +      text->mTextShadow = GetShadowData(textShadowValue->GetListValue(),
  1.4136 +                                        aContext, false, canStoreInRuleTree);
  1.4137 +    }
  1.4138 +  }
  1.4139 +
  1.4140 +  // line-height: normal, number, length, percent, inherit
  1.4141 +  const nsCSSValue* lineHeightValue = aRuleData->ValueForLineHeight();
  1.4142 +  if (eCSSUnit_Percent == lineHeightValue->GetUnit()) {
  1.4143 +    canStoreInRuleTree = false;
  1.4144 +    // Use |mFont.size| to pick up minimum font size.
  1.4145 +    text->mLineHeight.SetCoordValue(
  1.4146 +        NSToCoordRound(float(aContext->StyleFont()->mFont.size) *
  1.4147 +                       lineHeightValue->GetPercentValue()));
  1.4148 +  }
  1.4149 +  else if (eCSSUnit_Initial == lineHeightValue->GetUnit() ||
  1.4150 +           eCSSUnit_System_Font == lineHeightValue->GetUnit()) {
  1.4151 +    text->mLineHeight.SetNormalValue();
  1.4152 +  }
  1.4153 +  else {
  1.4154 +    SetCoord(*lineHeightValue, text->mLineHeight, parentText->mLineHeight,
  1.4155 +             SETCOORD_LEH | SETCOORD_FACTOR | SETCOORD_NORMAL |
  1.4156 +               SETCOORD_UNSET_INHERIT,
  1.4157 +             aContext, mPresContext, canStoreInRuleTree);
  1.4158 +    if (lineHeightValue->IsLengthUnit() &&
  1.4159 +        !lineHeightValue->IsRelativeLengthUnit()) {
  1.4160 +      nscoord lh = nsStyleFont::ZoomText(mPresContext,
  1.4161 +                                         text->mLineHeight.GetCoordValue());
  1.4162 +
  1.4163 +      canStoreInRuleTree = false;
  1.4164 +      const nsStyleFont *font = aContext->StyleFont();
  1.4165 +      nscoord minimumFontSize = mPresContext->MinFontSize(font->mLanguage);
  1.4166 +
  1.4167 +      if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
  1.4168 +        if (font->mSize != 0) {
  1.4169 +          lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
  1.4170 +        } else {
  1.4171 +          lh = minimumFontSize;
  1.4172 +        }
  1.4173 +      }
  1.4174 +      text->mLineHeight.SetCoordValue(lh);
  1.4175 +    }
  1.4176 +  }
  1.4177 +
  1.4178 +
  1.4179 +  // text-align: enum, string, pair(enum|string), inherit, initial
  1.4180 +  // NOTE: string is not implemented yet.
  1.4181 +  const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
  1.4182 +  text->mTextAlignTrue = false;
  1.4183 +  if (eCSSUnit_String == textAlignValue->GetUnit()) {
  1.4184 +    NS_NOTYETIMPLEMENTED("align string");
  1.4185 +  } else if (eCSSUnit_Enumerated == textAlignValue->GetUnit() &&
  1.4186 +             NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT ==
  1.4187 +               textAlignValue->GetIntValue()) {
  1.4188 +    canStoreInRuleTree = false;
  1.4189 +    uint8_t parentAlign = parentText->mTextAlign;
  1.4190 +    text->mTextAlign = (NS_STYLE_TEXT_ALIGN_DEFAULT == parentAlign) ?
  1.4191 +      NS_STYLE_TEXT_ALIGN_CENTER : parentAlign;
  1.4192 +  } else {
  1.4193 +    if (eCSSUnit_Pair == textAlignValue->GetUnit()) {
  1.4194 +      // Two values were specified, one must be 'true'.
  1.4195 +      text->mTextAlignTrue = true;
  1.4196 +      const nsCSSValuePair& textAlignValuePair = textAlignValue->GetPairValue();
  1.4197 +      textAlignValue = &textAlignValuePair.mXValue;
  1.4198 +      if (eCSSUnit_Enumerated == textAlignValue->GetUnit()) {
  1.4199 +        if (textAlignValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
  1.4200 +          textAlignValue = &textAlignValuePair.mYValue;
  1.4201 +        }
  1.4202 +      } else if (eCSSUnit_String == textAlignValue->GetUnit()) {
  1.4203 +        NS_NOTYETIMPLEMENTED("align string");
  1.4204 +      }
  1.4205 +    } else if (eCSSUnit_Inherit == textAlignValue->GetUnit() ||
  1.4206 +               eCSSUnit_Unset == textAlignValue->GetUnit()) {
  1.4207 +      text->mTextAlignTrue = parentText->mTextAlignTrue;
  1.4208 +    }
  1.4209 +    SetDiscrete(*textAlignValue, text->mTextAlign, canStoreInRuleTree,
  1.4210 +                SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4211 +                parentText->mTextAlign,
  1.4212 +                NS_STYLE_TEXT_ALIGN_DEFAULT, 0, 0, 0, 0);
  1.4213 +  }
  1.4214 +
  1.4215 +  // text-align-last: enum, pair(enum), inherit, initial
  1.4216 +  const nsCSSValue* textAlignLastValue = aRuleData->ValueForTextAlignLast();
  1.4217 +  text->mTextAlignLastTrue = false;
  1.4218 +  if (eCSSUnit_Pair == textAlignLastValue->GetUnit()) {
  1.4219 +    // Two values were specified, one must be 'true'.
  1.4220 +    text->mTextAlignLastTrue = true;
  1.4221 +    const nsCSSValuePair& textAlignLastValuePair = textAlignLastValue->GetPairValue();
  1.4222 +    textAlignLastValue = &textAlignLastValuePair.mXValue;
  1.4223 +    if (eCSSUnit_Enumerated == textAlignLastValue->GetUnit()) {
  1.4224 +      if (textAlignLastValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
  1.4225 +        textAlignLastValue = &textAlignLastValuePair.mYValue;
  1.4226 +      }
  1.4227 +    }
  1.4228 +  } else if (eCSSUnit_Inherit == textAlignLastValue->GetUnit() ||
  1.4229 +             eCSSUnit_Unset == textAlignLastValue->GetUnit()) {
  1.4230 +    text->mTextAlignLastTrue = parentText->mTextAlignLastTrue;
  1.4231 +  }
  1.4232 +  SetDiscrete(*textAlignLastValue, text->mTextAlignLast,
  1.4233 +              canStoreInRuleTree,
  1.4234 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4235 +              parentText->mTextAlignLast,
  1.4236 +              NS_STYLE_TEXT_ALIGN_AUTO, 0, 0, 0, 0);
  1.4237 +
  1.4238 +  // text-indent: length, percent, calc, inherit, initial
  1.4239 +  SetCoord(*aRuleData->ValueForTextIndent(), text->mTextIndent, parentText->mTextIndent,
  1.4240 +           SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  1.4241 +             SETCOORD_UNSET_INHERIT,
  1.4242 +           aContext, mPresContext, canStoreInRuleTree);
  1.4243 +
  1.4244 +  // text-transform: enum, inherit, initial
  1.4245 +  SetDiscrete(*aRuleData->ValueForTextTransform(), text->mTextTransform, canStoreInRuleTree,
  1.4246 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4247 +              parentText->mTextTransform,
  1.4248 +              NS_STYLE_TEXT_TRANSFORM_NONE, 0, 0, 0, 0);
  1.4249 +
  1.4250 +  // white-space: enum, inherit, initial
  1.4251 +  SetDiscrete(*aRuleData->ValueForWhiteSpace(), text->mWhiteSpace, canStoreInRuleTree,
  1.4252 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4253 +              parentText->mWhiteSpace,
  1.4254 +              NS_STYLE_WHITESPACE_NORMAL, 0, 0, 0, 0);
  1.4255 +
  1.4256 +  // word-break: enum, inherit, initial
  1.4257 +  SetDiscrete(*aRuleData->ValueForWordBreak(), text->mWordBreak, canStoreInRuleTree,
  1.4258 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4259 +              parentText->mWordBreak,
  1.4260 +              NS_STYLE_WORDBREAK_NORMAL, 0, 0, 0, 0);
  1.4261 +
  1.4262 +  // word-spacing: normal, length, inherit
  1.4263 +  nsStyleCoord tempCoord;
  1.4264 +  const nsCSSValue* wordSpacingValue = aRuleData->ValueForWordSpacing();
  1.4265 +  if (SetCoord(*wordSpacingValue, tempCoord,
  1.4266 +               nsStyleCoord(parentText->mWordSpacing,
  1.4267 +                            nsStyleCoord::CoordConstructor),
  1.4268 +               SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
  1.4269 +                 SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INHERIT,
  1.4270 +               aContext, mPresContext, canStoreInRuleTree)) {
  1.4271 +    if (tempCoord.GetUnit() == eStyleUnit_Coord) {
  1.4272 +      text->mWordSpacing = tempCoord.GetCoordValue();
  1.4273 +    } else if (tempCoord.GetUnit() == eStyleUnit_Normal) {
  1.4274 +      text->mWordSpacing = 0;
  1.4275 +    } else {
  1.4276 +      NS_NOTREACHED("unexpected unit");
  1.4277 +    }
  1.4278 +  } else {
  1.4279 +    NS_ASSERTION(wordSpacingValue->GetUnit() == eCSSUnit_Null,
  1.4280 +                 "unexpected unit");
  1.4281 +  }
  1.4282 +
  1.4283 +  // word-wrap: enum, inherit, initial
  1.4284 +  SetDiscrete(*aRuleData->ValueForWordWrap(), text->mWordWrap, canStoreInRuleTree,
  1.4285 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4286 +              parentText->mWordWrap,
  1.4287 +              NS_STYLE_WORDWRAP_NORMAL, 0, 0, 0, 0);
  1.4288 +
  1.4289 +  // hyphens: enum, inherit, initial
  1.4290 +  SetDiscrete(*aRuleData->ValueForHyphens(), text->mHyphens, canStoreInRuleTree,
  1.4291 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4292 +              parentText->mHyphens,
  1.4293 +              NS_STYLE_HYPHENS_MANUAL, 0, 0, 0, 0);
  1.4294 +
  1.4295 +  // text-size-adjust: none, auto, inherit, initial
  1.4296 +  SetDiscrete(*aRuleData->ValueForTextSizeAdjust(), text->mTextSizeAdjust,
  1.4297 +              canStoreInRuleTree,
  1.4298 +              SETDSC_NONE | SETDSC_AUTO | SETDSC_UNSET_INHERIT,
  1.4299 +              parentText->mTextSizeAdjust,
  1.4300 +              NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // initial value
  1.4301 +              NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // auto value
  1.4302 +              NS_STYLE_TEXT_SIZE_ADJUST_NONE, // none value
  1.4303 +              0, 0);
  1.4304 +
  1.4305 +  // -moz-text-discard: enum, inherit, initial
  1.4306 +  SetDiscrete(*aRuleData->ValueForControlCharacterVisibility(),
  1.4307 +              text->mControlCharacterVisibility,
  1.4308 +              canStoreInRuleTree,
  1.4309 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4310 +              parentText->mControlCharacterVisibility,
  1.4311 +              NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN, 0, 0, 0, 0);
  1.4312 +
  1.4313 +  // text-orientation: enum, inherit, initial
  1.4314 +  SetDiscrete(*aRuleData->ValueForTextOrientation(), text->mTextOrientation,
  1.4315 +              canStoreInRuleTree,
  1.4316 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4317 +              parentText->mTextOrientation,
  1.4318 +              NS_STYLE_TEXT_ORIENTATION_AUTO, 0, 0, 0, 0);
  1.4319 +
  1.4320 +  // text-combine-upright: enum, inherit, initial
  1.4321 +  SetDiscrete(*aRuleData->ValueForTextCombineUpright(),
  1.4322 +              text->mTextCombineUpright,
  1.4323 +              canStoreInRuleTree,
  1.4324 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4325 +              parentText->mTextCombineUpright,
  1.4326 +              NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE, 0, 0, 0, 0);
  1.4327 +
  1.4328 +  COMPUTE_END_INHERITED(Text, text)
  1.4329 +}
  1.4330 +
  1.4331 +const void*
  1.4332 +nsRuleNode::ComputeTextResetData(void* aStartStruct,
  1.4333 +                                 const nsRuleData* aRuleData,
  1.4334 +                                 nsStyleContext* aContext,
  1.4335 +                                 nsRuleNode* aHighestNode,
  1.4336 +                                 const RuleDetail aRuleDetail,
  1.4337 +                                 const bool aCanStoreInRuleTree)
  1.4338 +{
  1.4339 +  COMPUTE_START_RESET(TextReset, (), text, parentText)
  1.4340 +
  1.4341 +  // vertical-align: enum, length, percent, calc, inherit
  1.4342 +  const nsCSSValue* verticalAlignValue = aRuleData->ValueForVerticalAlign();
  1.4343 +  if (!SetCoord(*verticalAlignValue, text->mVerticalAlign,
  1.4344 +                parentText->mVerticalAlign,
  1.4345 +                SETCOORD_LPH | SETCOORD_ENUMERATED | SETCOORD_STORE_CALC,
  1.4346 +                aContext, mPresContext, canStoreInRuleTree)) {
  1.4347 +    if (eCSSUnit_Initial == verticalAlignValue->GetUnit() ||
  1.4348 +        eCSSUnit_Unset == verticalAlignValue->GetUnit()) {
  1.4349 +      text->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE,
  1.4350 +                                       eStyleUnit_Enumerated);
  1.4351 +    }
  1.4352 +  }
  1.4353 +
  1.4354 +  // text-decoration-line: enum (bit field), inherit, initial
  1.4355 +  const nsCSSValue* decorationLineValue =
  1.4356 +    aRuleData->ValueForTextDecorationLine();
  1.4357 +  if (eCSSUnit_Enumerated == decorationLineValue->GetUnit()) {
  1.4358 +    int32_t td = decorationLineValue->GetIntValue();
  1.4359 +    text->mTextDecorationLine = td;
  1.4360 +    if (td & NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS) {
  1.4361 +      bool underlineLinks =
  1.4362 +        mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
  1.4363 +      if (underlineLinks) {
  1.4364 +        text->mTextDecorationLine |= NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
  1.4365 +      }
  1.4366 +      else {
  1.4367 +        text->mTextDecorationLine &= ~NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
  1.4368 +      }
  1.4369 +    }
  1.4370 +  } else if (eCSSUnit_Inherit == decorationLineValue->GetUnit()) {
  1.4371 +    canStoreInRuleTree = false;
  1.4372 +    text->mTextDecorationLine = parentText->mTextDecorationLine;
  1.4373 +  } else if (eCSSUnit_Initial == decorationLineValue->GetUnit() ||
  1.4374 +             eCSSUnit_Unset == decorationLineValue->GetUnit()) {
  1.4375 +    text->mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
  1.4376 +  }
  1.4377 +
  1.4378 +  // text-decoration-color: color, string, enum, inherit, initial
  1.4379 +  const nsCSSValue* decorationColorValue =
  1.4380 +    aRuleData->ValueForTextDecorationColor();
  1.4381 +  nscolor decorationColor;
  1.4382 +  if (eCSSUnit_Inherit == decorationColorValue->GetUnit()) {
  1.4383 +    canStoreInRuleTree = false;
  1.4384 +    if (parentContext) {
  1.4385 +      bool isForeground;
  1.4386 +      parentText->GetDecorationColor(decorationColor, isForeground);
  1.4387 +      if (isForeground) {
  1.4388 +        text->SetDecorationColor(parentContext->StyleColor()->mColor);
  1.4389 +      } else {
  1.4390 +        text->SetDecorationColor(decorationColor);
  1.4391 +      }
  1.4392 +    } else {
  1.4393 +      text->SetDecorationColorToForeground();
  1.4394 +    }
  1.4395 +  }
  1.4396 +  else if (eCSSUnit_EnumColor == decorationColorValue->GetUnit() &&
  1.4397 +           decorationColorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
  1.4398 +    text->SetDecorationColorToForeground();
  1.4399 +  }
  1.4400 +  else if (SetColor(*decorationColorValue, 0, mPresContext, aContext,
  1.4401 +                    decorationColor, canStoreInRuleTree)) {
  1.4402 +    text->SetDecorationColor(decorationColor);
  1.4403 +  }
  1.4404 +  else if (eCSSUnit_Initial == decorationColorValue->GetUnit() ||
  1.4405 +           eCSSUnit_Unset == decorationColorValue->GetUnit() ||
  1.4406 +           eCSSUnit_Enumerated == decorationColorValue->GetUnit()) {
  1.4407 +    NS_ABORT_IF_FALSE(eCSSUnit_Enumerated != decorationColorValue->GetUnit() ||
  1.4408 +                      decorationColorValue->GetIntValue() ==
  1.4409 +                        NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,
  1.4410 +                      "unexpected enumerated value");
  1.4411 +    text->SetDecorationColorToForeground();
  1.4412 +  }
  1.4413 +
  1.4414 +  // text-decoration-style: enum, inherit, initial
  1.4415 +  const nsCSSValue* decorationStyleValue =
  1.4416 +    aRuleData->ValueForTextDecorationStyle();
  1.4417 +  if (eCSSUnit_Enumerated == decorationStyleValue->GetUnit()) {
  1.4418 +    text->SetDecorationStyle(decorationStyleValue->GetIntValue());
  1.4419 +  } else if (eCSSUnit_Inherit == decorationStyleValue->GetUnit()) {
  1.4420 +    text->SetDecorationStyle(parentText->GetDecorationStyle());
  1.4421 +    canStoreInRuleTree = false;
  1.4422 +  } else if (eCSSUnit_Initial == decorationStyleValue->GetUnit() ||
  1.4423 +             eCSSUnit_Unset == decorationStyleValue->GetUnit()) {
  1.4424 +    text->SetDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID);
  1.4425 +  }
  1.4426 +
  1.4427 +  // text-overflow: enum, string, pair(enum|string), inherit, initial
  1.4428 +  const nsCSSValue* textOverflowValue =
  1.4429 +    aRuleData->ValueForTextOverflow();
  1.4430 +  if (eCSSUnit_Initial == textOverflowValue->GetUnit() ||
  1.4431 +      eCSSUnit_Unset == textOverflowValue->GetUnit()) {
  1.4432 +    text->mTextOverflow = nsStyleTextOverflow();
  1.4433 +  } else if (eCSSUnit_Inherit == textOverflowValue->GetUnit()) {
  1.4434 +    canStoreInRuleTree = false;
  1.4435 +    text->mTextOverflow = parentText->mTextOverflow;
  1.4436 +  } else if (eCSSUnit_Enumerated == textOverflowValue->GetUnit()) {
  1.4437 +    // A single enumerated value.
  1.4438 +    SetDiscrete(*textOverflowValue, text->mTextOverflow.mRight.mType,
  1.4439 +                canStoreInRuleTree,
  1.4440 +                SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
  1.4441 +                NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
  1.4442 +    text->mTextOverflow.mRight.mString.Truncate();
  1.4443 +    text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
  1.4444 +    text->mTextOverflow.mLeft.mString.Truncate();
  1.4445 +    text->mTextOverflow.mLogicalDirections = true;
  1.4446 +  } else if (eCSSUnit_String == textOverflowValue->GetUnit()) {
  1.4447 +    // A single string value.
  1.4448 +    text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
  1.4449 +    textOverflowValue->GetStringValue(text->mTextOverflow.mRight.mString);
  1.4450 +    text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
  1.4451 +    text->mTextOverflow.mLeft.mString.Truncate();
  1.4452 +    text->mTextOverflow.mLogicalDirections = true;
  1.4453 +  } else if (eCSSUnit_Pair == textOverflowValue->GetUnit()) {
  1.4454 +    // Two values were specified.
  1.4455 +    text->mTextOverflow.mLogicalDirections = false;
  1.4456 +    const nsCSSValuePair& textOverflowValuePair =
  1.4457 +      textOverflowValue->GetPairValue();
  1.4458 +
  1.4459 +    const nsCSSValue *textOverflowLeftValue = &textOverflowValuePair.mXValue;
  1.4460 +    if (eCSSUnit_Enumerated == textOverflowLeftValue->GetUnit()) {
  1.4461 +      SetDiscrete(*textOverflowLeftValue, text->mTextOverflow.mLeft.mType,
  1.4462 +                  canStoreInRuleTree,
  1.4463 +                  SETDSC_ENUMERATED, parentText->mTextOverflow.mLeft.mType,
  1.4464 +                  NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
  1.4465 +      text->mTextOverflow.mLeft.mString.Truncate();
  1.4466 +    } else if (eCSSUnit_String == textOverflowLeftValue->GetUnit()) {
  1.4467 +      textOverflowLeftValue->GetStringValue(text->mTextOverflow.mLeft.mString);
  1.4468 +      text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
  1.4469 +    }
  1.4470 +
  1.4471 +    const nsCSSValue *textOverflowRightValue = &textOverflowValuePair.mYValue;
  1.4472 +    if (eCSSUnit_Enumerated == textOverflowRightValue->GetUnit()) {
  1.4473 +      SetDiscrete(*textOverflowRightValue, text->mTextOverflow.mRight.mType,
  1.4474 +                  canStoreInRuleTree,
  1.4475 +                  SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
  1.4476 +                  NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
  1.4477 +      text->mTextOverflow.mRight.mString.Truncate();
  1.4478 +    } else if (eCSSUnit_String == textOverflowRightValue->GetUnit()) {
  1.4479 +      textOverflowRightValue->GetStringValue(text->mTextOverflow.mRight.mString);
  1.4480 +      text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
  1.4481 +    }
  1.4482 +  }
  1.4483 +
  1.4484 +  // unicode-bidi: enum, inherit, initial
  1.4485 +  SetDiscrete(*aRuleData->ValueForUnicodeBidi(), text->mUnicodeBidi, canStoreInRuleTree,
  1.4486 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.4487 +              parentText->mUnicodeBidi,
  1.4488 +              NS_STYLE_UNICODE_BIDI_NORMAL, 0, 0, 0, 0);
  1.4489 +
  1.4490 +  COMPUTE_END_RESET(TextReset, text)
  1.4491 +}
  1.4492 +
  1.4493 +const void*
  1.4494 +nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
  1.4495 +                                     const nsRuleData* aRuleData,
  1.4496 +                                     nsStyleContext* aContext,
  1.4497 +                                     nsRuleNode* aHighestNode,
  1.4498 +                                     const RuleDetail aRuleDetail,
  1.4499 +                                     const bool aCanStoreInRuleTree)
  1.4500 +{
  1.4501 +  COMPUTE_START_INHERITED(UserInterface, (), ui, parentUI)
  1.4502 +
  1.4503 +  // cursor: enum, url, inherit
  1.4504 +  const nsCSSValue* cursorValue = aRuleData->ValueForCursor();
  1.4505 +  nsCSSUnit cursorUnit = cursorValue->GetUnit();
  1.4506 +  if (cursorUnit != eCSSUnit_Null) {
  1.4507 +    delete [] ui->mCursorArray;
  1.4508 +    ui->mCursorArray = nullptr;
  1.4509 +    ui->mCursorArrayLength = 0;
  1.4510 +
  1.4511 +    if (cursorUnit == eCSSUnit_Inherit ||
  1.4512 +        cursorUnit == eCSSUnit_Unset) {
  1.4513 +      canStoreInRuleTree = false;
  1.4514 +      ui->mCursor = parentUI->mCursor;
  1.4515 +      ui->CopyCursorArrayFrom(*parentUI);
  1.4516 +    }
  1.4517 +    else if (cursorUnit == eCSSUnit_Initial) {
  1.4518 +      ui->mCursor = NS_STYLE_CURSOR_AUTO;
  1.4519 +    }
  1.4520 +    else {
  1.4521 +      // The parser will never create a list that is *all* URL values --
  1.4522 +      // that's invalid.
  1.4523 +      NS_ABORT_IF_FALSE(cursorUnit == eCSSUnit_List ||
  1.4524 +                        cursorUnit == eCSSUnit_ListDep,
  1.4525 +                        nsPrintfCString("unrecognized cursor unit %d",
  1.4526 +                                        cursorUnit).get());
  1.4527 +      const nsCSSValueList* list = cursorValue->GetListValue();
  1.4528 +      const nsCSSValueList* list2 = list;
  1.4529 +      nsIDocument* doc = aContext->PresContext()->Document();
  1.4530 +      uint32_t arrayLength = 0;
  1.4531 +      for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext)
  1.4532 +        if (list->mValue.GetArrayValue()->Item(0).GetImageValue(doc))
  1.4533 +          ++arrayLength;
  1.4534 +
  1.4535 +      if (arrayLength != 0) {
  1.4536 +        ui->mCursorArray = new nsCursorImage[arrayLength];
  1.4537 +        if (ui->mCursorArray) {
  1.4538 +          ui->mCursorArrayLength = arrayLength;
  1.4539 +
  1.4540 +          for (nsCursorImage *item = ui->mCursorArray;
  1.4541 +               list2->mValue.GetUnit() == eCSSUnit_Array;
  1.4542 +               list2 = list2->mNext) {
  1.4543 +            nsCSSValue::Array *arr = list2->mValue.GetArrayValue();
  1.4544 +            imgIRequest *req = arr->Item(0).GetImageValue(doc);
  1.4545 +            if (req) {
  1.4546 +              item->SetImage(req);
  1.4547 +              if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
  1.4548 +                item->mHaveHotspot = true;
  1.4549 +                item->mHotspotX = arr->Item(1).GetFloatValue(),
  1.4550 +                item->mHotspotY = arr->Item(2).GetFloatValue();
  1.4551 +              }
  1.4552 +              ++item;
  1.4553 +            }
  1.4554 +          }
  1.4555 +        }
  1.4556 +      }
  1.4557 +
  1.4558 +      NS_ASSERTION(list, "Must have non-array value at the end");
  1.4559 +      NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated,
  1.4560 +                   "Unexpected fallback value at end of cursor list");
  1.4561 +      ui->mCursor = list->mValue.GetIntValue();
  1.4562 +    }
  1.4563 +  }
  1.4564 +
  1.4565 +  // user-input: enum, inherit, initial
  1.4566 +  SetDiscrete(*aRuleData->ValueForUserInput(),
  1.4567 +              ui->mUserInput, canStoreInRuleTree,
  1.4568 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4569 +              parentUI->mUserInput,
  1.4570 +              NS_STYLE_USER_INPUT_AUTO, 0, 0, 0, 0);
  1.4571 +
  1.4572 +  // user-modify: enum, inherit, initial
  1.4573 +  SetDiscrete(*aRuleData->ValueForUserModify(),
  1.4574 +              ui->mUserModify, canStoreInRuleTree,
  1.4575 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4576 +              parentUI->mUserModify,
  1.4577 +              NS_STYLE_USER_MODIFY_READ_ONLY,
  1.4578 +              0, 0, 0, 0);
  1.4579 +
  1.4580 +  // user-focus: enum, inherit, initial
  1.4581 +  SetDiscrete(*aRuleData->ValueForUserFocus(),
  1.4582 +              ui->mUserFocus, canStoreInRuleTree,
  1.4583 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.4584 +              parentUI->mUserFocus,
  1.4585 +              NS_STYLE_USER_FOCUS_NONE, 0, 0, 0, 0);
  1.4586 +
  1.4587 +  COMPUTE_END_INHERITED(UserInterface, ui)
  1.4588 +}
  1.4589 +
  1.4590 +const void*
  1.4591 +nsRuleNode::ComputeUIResetData(void* aStartStruct,
  1.4592 +                               const nsRuleData* aRuleData,
  1.4593 +                               nsStyleContext* aContext,
  1.4594 +                               nsRuleNode* aHighestNode,
  1.4595 +                               const RuleDetail aRuleDetail,
  1.4596 +                               const bool aCanStoreInRuleTree)
  1.4597 +{
  1.4598 +  COMPUTE_START_RESET(UIReset, (), ui, parentUI)
  1.4599 +
  1.4600 +  // user-select: enum, inherit, initial
  1.4601 +  SetDiscrete(*aRuleData->ValueForUserSelect(),
  1.4602 +              ui->mUserSelect, canStoreInRuleTree,
  1.4603 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.4604 +              parentUI->mUserSelect,
  1.4605 +              NS_STYLE_USER_SELECT_AUTO, 0, 0, 0, 0);
  1.4606 +
  1.4607 +  // ime-mode: enum, inherit, initial
  1.4608 +  SetDiscrete(*aRuleData->ValueForImeMode(),
  1.4609 +              ui->mIMEMode, canStoreInRuleTree,
  1.4610 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.4611 +              parentUI->mIMEMode,
  1.4612 +              NS_STYLE_IME_MODE_AUTO, 0, 0, 0, 0);
  1.4613 +
  1.4614 +  // force-broken-image-icons: integer, inherit, initial
  1.4615 +  SetDiscrete(*aRuleData->ValueForForceBrokenImageIcon(),
  1.4616 +              ui->mForceBrokenImageIcon,
  1.4617 +              canStoreInRuleTree,
  1.4618 +              SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
  1.4619 +              parentUI->mForceBrokenImageIcon,
  1.4620 +              0, 0, 0, 0, 0);
  1.4621 +
  1.4622 +  // -moz-window-shadow: enum, inherit, initial
  1.4623 +  SetDiscrete(*aRuleData->ValueForWindowShadow(),
  1.4624 +              ui->mWindowShadow, canStoreInRuleTree,
  1.4625 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.4626 +              parentUI->mWindowShadow,
  1.4627 +              NS_STYLE_WINDOW_SHADOW_DEFAULT, 0, 0, 0, 0);
  1.4628 +
  1.4629 +  COMPUTE_END_RESET(UIReset, ui)
  1.4630 +}
  1.4631 +
  1.4632 +// Information about each transition or animation property that is
  1.4633 +// constant.
  1.4634 +struct TransitionPropInfo {
  1.4635 +  nsCSSProperty property;
  1.4636 +  // Location of the count of the property's computed value.
  1.4637 +  uint32_t nsStyleDisplay::* sdCount;
  1.4638 +};
  1.4639 +
  1.4640 +// Each property's index in this array must match its index in the
  1.4641 +// mutable array |transitionPropData| below.
  1.4642 +static const TransitionPropInfo transitionPropInfo[4] = {
  1.4643 +  { eCSSProperty_transition_delay,
  1.4644 +    &nsStyleDisplay::mTransitionDelayCount },
  1.4645 +  { eCSSProperty_transition_duration,
  1.4646 +    &nsStyleDisplay::mTransitionDurationCount },
  1.4647 +  { eCSSProperty_transition_property,
  1.4648 +    &nsStyleDisplay::mTransitionPropertyCount },
  1.4649 +  { eCSSProperty_transition_timing_function,
  1.4650 +    &nsStyleDisplay::mTransitionTimingFunctionCount },
  1.4651 +};
  1.4652 +
  1.4653 +// Each property's index in this array must match its index in the
  1.4654 +// mutable array |animationPropData| below.
  1.4655 +static const TransitionPropInfo animationPropInfo[8] = {
  1.4656 +  { eCSSProperty_animation_delay,
  1.4657 +    &nsStyleDisplay::mAnimationDelayCount },
  1.4658 +  { eCSSProperty_animation_duration,
  1.4659 +    &nsStyleDisplay::mAnimationDurationCount },
  1.4660 +  { eCSSProperty_animation_name,
  1.4661 +    &nsStyleDisplay::mAnimationNameCount },
  1.4662 +  { eCSSProperty_animation_timing_function,
  1.4663 +    &nsStyleDisplay::mAnimationTimingFunctionCount },
  1.4664 +  { eCSSProperty_animation_direction,
  1.4665 +    &nsStyleDisplay::mAnimationDirectionCount },
  1.4666 +  { eCSSProperty_animation_fill_mode,
  1.4667 +    &nsStyleDisplay::mAnimationFillModeCount },
  1.4668 +  { eCSSProperty_animation_play_state,
  1.4669 +    &nsStyleDisplay::mAnimationPlayStateCount },
  1.4670 +  { eCSSProperty_animation_iteration_count,
  1.4671 +    &nsStyleDisplay::mAnimationIterationCountCount },
  1.4672 +};
  1.4673 +
  1.4674 +// Information about each transition or animation property that changes
  1.4675 +// during ComputeDisplayData.
  1.4676 +struct TransitionPropData {
  1.4677 +  const nsCSSValueList *list;
  1.4678 +  nsCSSUnit unit;
  1.4679 +  uint32_t num;
  1.4680 +};
  1.4681 +
  1.4682 +static uint32_t
  1.4683 +CountTransitionProps(const TransitionPropInfo* aInfo,
  1.4684 +                     TransitionPropData* aData,
  1.4685 +                     size_t aLength,
  1.4686 +                     nsStyleDisplay* aDisplay,
  1.4687 +                     const nsStyleDisplay* aParentDisplay,
  1.4688 +                     const nsRuleData* aRuleData,
  1.4689 +                     bool& aCanStoreInRuleTree)
  1.4690 +{
  1.4691 +  // The four transition properties or eight animation properties are
  1.4692 +  // stored in nsCSSDisplay in a single array for all properties.  The
  1.4693 +  // number of transitions is equal to the number of items in the
  1.4694 +  // longest property's value.  Properties that have fewer values than
  1.4695 +  // the longest are filled in by repeating the list.  However, this
  1.4696 +  // repetition does not extend the computed value of that particular
  1.4697 +  // property (for purposes of inheritance, or, in our code, for when
  1.4698 +  // other properties are overridden by a more specific rule).
  1.4699 +
  1.4700 +  // But actually, since the spec isn't clear yet, we'll fully compute
  1.4701 +  // all of them (so we can switch easily later), but only care about
  1.4702 +  // the ones up to the number of items for 'transition-property', per
  1.4703 +  // http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html .
  1.4704 +
  1.4705 +  // Transitions are difficult to handle correctly because of this.  For
  1.4706 +  // example, we need to handle scenarios such as:
  1.4707 +  //  * a more general rule specifies transition-property: a, b, c;
  1.4708 +  //  * a more specific rule overrides as transition-property: d;
  1.4709 +  //
  1.4710 +  // If only the general rule applied, we would fill in the extra
  1.4711 +  // properties (duration, delay, etc) with initial values to create 3
  1.4712 +  // fully-specified transitions.  But when the more specific rule
  1.4713 +  // applies, we should only create a single transition.  In order to do
  1.4714 +  // this we need to remember which properties were explicitly specified
  1.4715 +  // and which ones were just filled in with initial values to get a
  1.4716 +  // fully-specified transition, which we do by remembering the number
  1.4717 +  // of values for each property.
  1.4718 +
  1.4719 +  uint32_t numTransitions = 0;
  1.4720 +  for (size_t i = 0; i < aLength; ++i) {
  1.4721 +    const TransitionPropInfo& info = aInfo[i];
  1.4722 +    TransitionPropData& data = aData[i];
  1.4723 +
  1.4724 +    // cache whether any of the properties are specified as 'inherit' so
  1.4725 +    // we can use it below
  1.4726 +
  1.4727 +    const nsCSSValue& value = *aRuleData->ValueFor(info.property);
  1.4728 +    data.unit = value.GetUnit();
  1.4729 +    data.list = (value.GetUnit() == eCSSUnit_List ||
  1.4730 +                 value.GetUnit() == eCSSUnit_ListDep)
  1.4731 +                  ? value.GetListValue() : nullptr;
  1.4732 +
  1.4733 +    // General algorithm to determine how many total transitions we need
  1.4734 +    // to build.  For each property:
  1.4735 +    //  - if there is no value specified in for the property in
  1.4736 +    //    displayData, use the values from the start struct, but only if
  1.4737 +    //    they were explicitly specified
  1.4738 +    //  - if there is a value specified for the property in displayData:
  1.4739 +    //    - if the value is 'inherit', count the number of values for
  1.4740 +    //      that property are specified by the parent, but only those
  1.4741 +    //      that were explicitly specified
  1.4742 +    //    - otherwise, count the number of values specified in displayData
  1.4743 +
  1.4744 +
  1.4745 +    // calculate number of elements
  1.4746 +    if (data.unit == eCSSUnit_Inherit) {
  1.4747 +      data.num = aParentDisplay->*(info.sdCount);
  1.4748 +      aCanStoreInRuleTree = false;
  1.4749 +    } else if (data.list) {
  1.4750 +      data.num = ListLength(data.list);
  1.4751 +    } else {
  1.4752 +      data.num = aDisplay->*(info.sdCount);
  1.4753 +    }
  1.4754 +    if (data.num > numTransitions)
  1.4755 +      numTransitions = data.num;
  1.4756 +  }
  1.4757 +
  1.4758 +  return numTransitions;
  1.4759 +}
  1.4760 +
  1.4761 +static void
  1.4762 +ComputeTimingFunction(const nsCSSValue& aValue, nsTimingFunction& aResult)
  1.4763 +{
  1.4764 +  switch (aValue.GetUnit()) {
  1.4765 +    case eCSSUnit_Enumerated:
  1.4766 +      aResult = nsTimingFunction(aValue.GetIntValue());
  1.4767 +      break;
  1.4768 +    case eCSSUnit_Cubic_Bezier:
  1.4769 +      {
  1.4770 +        nsCSSValue::Array* array = aValue.GetArrayValue();
  1.4771 +        NS_ASSERTION(array && array->Count() == 4,
  1.4772 +                     "Need 4 control points");
  1.4773 +        aResult = nsTimingFunction(array->Item(0).GetFloatValue(),
  1.4774 +                                   array->Item(1).GetFloatValue(),
  1.4775 +                                   array->Item(2).GetFloatValue(),
  1.4776 +                                   array->Item(3).GetFloatValue());
  1.4777 +      }
  1.4778 +      break;
  1.4779 +    case eCSSUnit_Steps:
  1.4780 +      {
  1.4781 +        nsCSSValue::Array* array = aValue.GetArrayValue();
  1.4782 +        NS_ASSERTION(array && array->Count() == 2,
  1.4783 +                     "Need 2 items");
  1.4784 +        NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
  1.4785 +                     "unexpected first value");
  1.4786 +        NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
  1.4787 +                     (array->Item(1).GetIntValue() ==
  1.4788 +                       NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START ||
  1.4789 +                      array->Item(1).GetIntValue() ==
  1.4790 +                       NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END),
  1.4791 +                     "unexpected second value");
  1.4792 +        nsTimingFunction::Type type =
  1.4793 +          (array->Item(1).GetIntValue() ==
  1.4794 +            NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END)
  1.4795 +            ? nsTimingFunction::StepEnd : nsTimingFunction::StepStart;
  1.4796 +        aResult = nsTimingFunction(type, array->Item(0).GetIntValue());
  1.4797 +      }
  1.4798 +      break;
  1.4799 +    default:
  1.4800 +      NS_NOTREACHED("Invalid transition property unit");
  1.4801 +  }
  1.4802 +}
  1.4803 +
  1.4804 +const void*
  1.4805 +nsRuleNode::ComputeDisplayData(void* aStartStruct,
  1.4806 +                               const nsRuleData* aRuleData,
  1.4807 +                               nsStyleContext* aContext,
  1.4808 +                               nsRuleNode* aHighestNode,
  1.4809 +                               const RuleDetail aRuleDetail,
  1.4810 +                               const bool aCanStoreInRuleTree)
  1.4811 +{
  1.4812 +  COMPUTE_START_RESET(Display, (), display, parentDisplay)
  1.4813 +
  1.4814 +  // We may have ended up with aStartStruct's values of mDisplay and
  1.4815 +  // mFloats, but those may not be correct if our style data overrides
  1.4816 +  // its position or float properties.  Reset to mOriginalDisplay and
  1.4817 +  // mOriginalFloats; it if turns out we still need the display/floats
  1.4818 +  // adjustments we'll do them below.
  1.4819 +  display->mDisplay = display->mOriginalDisplay;
  1.4820 +  display->mFloats = display->mOriginalFloats;
  1.4821 +
  1.4822 +  // Each property's index in this array must match its index in the
  1.4823 +  // const array |transitionPropInfo| above.
  1.4824 +  TransitionPropData transitionPropData[4];
  1.4825 +  TransitionPropData& delay = transitionPropData[0];
  1.4826 +  TransitionPropData& duration = transitionPropData[1];
  1.4827 +  TransitionPropData& property = transitionPropData[2];
  1.4828 +  TransitionPropData& timingFunction = transitionPropData[3];
  1.4829 +
  1.4830 +#define FOR_ALL_TRANSITION_PROPS(var_) \
  1.4831 +                                      for (uint32_t var_ = 0; var_ < 4; ++var_)
  1.4832 +
  1.4833 +  // CSS Transitions
  1.4834 +  uint32_t numTransitions =
  1.4835 +    CountTransitionProps(transitionPropInfo, transitionPropData,
  1.4836 +                         ArrayLength(transitionPropData),
  1.4837 +                         display, parentDisplay, aRuleData,
  1.4838 +                         canStoreInRuleTree);
  1.4839 +
  1.4840 +  display->mTransitions.SetLength(numTransitions);
  1.4841 +
  1.4842 +  FOR_ALL_TRANSITION_PROPS(p) {
  1.4843 +    const TransitionPropInfo& i = transitionPropInfo[p];
  1.4844 +    TransitionPropData& d = transitionPropData[p];
  1.4845 +
  1.4846 +    display->*(i.sdCount) = d.num;
  1.4847 +  }
  1.4848 +
  1.4849 +  // Fill in the transitions we just allocated with the appropriate values.
  1.4850 +  for (uint32_t i = 0; i < numTransitions; ++i) {
  1.4851 +    nsTransition *transition = &display->mTransitions[i];
  1.4852 +
  1.4853 +    if (i >= delay.num) {
  1.4854 +      transition->SetDelay(display->mTransitions[i % delay.num].GetDelay());
  1.4855 +    } else if (delay.unit == eCSSUnit_Inherit) {
  1.4856 +      // FIXME (Bug 522599) (for all transition properties): write a test that
  1.4857 +      // detects when this was wrong for i >= delay.num if parent had
  1.4858 +      // count for this property not equal to length
  1.4859 +      NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionDelayCount,
  1.4860 +                        "delay.num computed incorrectly");
  1.4861 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.4862 +                        "should have made canStoreInRuleTree false above");
  1.4863 +      transition->SetDelay(parentDisplay->mTransitions[i].GetDelay());
  1.4864 +    } else if (delay.unit == eCSSUnit_Initial ||
  1.4865 +               delay.unit == eCSSUnit_Unset) {
  1.4866 +      transition->SetDelay(0.0);
  1.4867 +    } else if (delay.list) {
  1.4868 +      switch (delay.list->mValue.GetUnit()) {
  1.4869 +        case eCSSUnit_Seconds:
  1.4870 +          transition->SetDelay(PR_MSEC_PER_SEC *
  1.4871 +                               delay.list->mValue.GetFloatValue());
  1.4872 +          break;
  1.4873 +        case eCSSUnit_Milliseconds:
  1.4874 +          transition->SetDelay(delay.list->mValue.GetFloatValue());
  1.4875 +          break;
  1.4876 +        default:
  1.4877 +          NS_NOTREACHED("Invalid delay unit");
  1.4878 +      }
  1.4879 +    }
  1.4880 +
  1.4881 +    if (i >= duration.num) {
  1.4882 +      transition->SetDuration(
  1.4883 +        display->mTransitions[i % duration.num].GetDuration());
  1.4884 +    } else if (duration.unit == eCSSUnit_Inherit) {
  1.4885 +      NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionDurationCount,
  1.4886 +                        "duration.num computed incorrectly");
  1.4887 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.4888 +                        "should have made canStoreInRuleTree false above");
  1.4889 +      transition->SetDuration(parentDisplay->mTransitions[i].GetDuration());
  1.4890 +    } else if (duration.unit == eCSSUnit_Initial ||
  1.4891 +               duration.unit == eCSSUnit_Unset) {
  1.4892 +      transition->SetDuration(0.0);
  1.4893 +    } else if (duration.list) {
  1.4894 +      switch (duration.list->mValue.GetUnit()) {
  1.4895 +        case eCSSUnit_Seconds:
  1.4896 +          transition->SetDuration(PR_MSEC_PER_SEC *
  1.4897 +                                  duration.list->mValue.GetFloatValue());
  1.4898 +          break;
  1.4899 +        case eCSSUnit_Milliseconds:
  1.4900 +          transition->SetDuration(duration.list->mValue.GetFloatValue());
  1.4901 +          break;
  1.4902 +        default:
  1.4903 +          NS_NOTREACHED("Invalid duration unit");
  1.4904 +      }
  1.4905 +    }
  1.4906 +
  1.4907 +    if (i >= property.num) {
  1.4908 +      transition->CopyPropertyFrom(display->mTransitions[i % property.num]);
  1.4909 +    } else if (property.unit == eCSSUnit_Inherit) {
  1.4910 +      NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionPropertyCount,
  1.4911 +                        "property.num computed incorrectly");
  1.4912 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.4913 +                        "should have made canStoreInRuleTree false above");
  1.4914 +      transition->CopyPropertyFrom(parentDisplay->mTransitions[i]);
  1.4915 +    } else if (property.unit == eCSSUnit_Initial ||
  1.4916 +               property.unit == eCSSUnit_Unset) {
  1.4917 +      transition->SetProperty(eCSSPropertyExtra_all_properties);
  1.4918 +    } else if (property.unit == eCSSUnit_None) {
  1.4919 +      transition->SetProperty(eCSSPropertyExtra_no_properties);
  1.4920 +    } else if (property.list) {
  1.4921 +      const nsCSSValue &val = property.list->mValue;
  1.4922 +
  1.4923 +      if (val.GetUnit() == eCSSUnit_Ident) {
  1.4924 +        nsDependentString
  1.4925 +          propertyStr(property.list->mValue.GetStringBufferValue());
  1.4926 +        nsCSSProperty prop =
  1.4927 +          nsCSSProps::LookupProperty(propertyStr,
  1.4928 +                                     nsCSSProps::eEnabledForAllContent);
  1.4929 +        if (prop == eCSSProperty_UNKNOWN) {
  1.4930 +          transition->SetUnknownProperty(propertyStr);
  1.4931 +        } else {
  1.4932 +          transition->SetProperty(prop);
  1.4933 +        }
  1.4934 +      } else {
  1.4935 +        NS_ABORT_IF_FALSE(val.GetUnit() == eCSSUnit_All,
  1.4936 +                          nsPrintfCString("Invalid transition property unit %d",
  1.4937 +                                          val.GetUnit()).get());
  1.4938 +        transition->SetProperty(eCSSPropertyExtra_all_properties);
  1.4939 +      }
  1.4940 +    }
  1.4941 +
  1.4942 +    if (i >= timingFunction.num) {
  1.4943 +      transition->SetTimingFunction(
  1.4944 +        display->mTransitions[i % timingFunction.num].GetTimingFunction());
  1.4945 +    } else if (timingFunction.unit == eCSSUnit_Inherit) {
  1.4946 +      NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionTimingFunctionCount,
  1.4947 +                        "timingFunction.num computed incorrectly");
  1.4948 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.4949 +                        "should have made canStoreInRuleTree false above");
  1.4950 +      transition->SetTimingFunction(
  1.4951 +        parentDisplay->mTransitions[i].GetTimingFunction());
  1.4952 +    } else if (timingFunction.unit == eCSSUnit_Initial ||
  1.4953 +               timingFunction.unit == eCSSUnit_Unset) {
  1.4954 +      transition->SetTimingFunction(
  1.4955 +        nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
  1.4956 +    } else if (timingFunction.list) {
  1.4957 +      ComputeTimingFunction(timingFunction.list->mValue,
  1.4958 +                            transition->TimingFunctionSlot());
  1.4959 +    }
  1.4960 +
  1.4961 +    FOR_ALL_TRANSITION_PROPS(p) {
  1.4962 +      const TransitionPropInfo& info = transitionPropInfo[p];
  1.4963 +      TransitionPropData& d = transitionPropData[p];
  1.4964 +
  1.4965 +      // if we're at the end of the list, start at the beginning and repeat
  1.4966 +      // until we're out of transitions to populate
  1.4967 +      if (d.list) {
  1.4968 +        d.list = d.list->mNext ? d.list->mNext :
  1.4969 +          aRuleData->ValueFor(info.property)->GetListValue();
  1.4970 +      }
  1.4971 +    }
  1.4972 +  }
  1.4973 +
  1.4974 +  // Each property's index in this array must match its index in the
  1.4975 +  // const array |animationPropInfo| above.
  1.4976 +  TransitionPropData animationPropData[8];
  1.4977 +  TransitionPropData& animDelay = animationPropData[0];
  1.4978 +  TransitionPropData& animDuration = animationPropData[1];
  1.4979 +  TransitionPropData& animName = animationPropData[2];
  1.4980 +  TransitionPropData& animTimingFunction = animationPropData[3];
  1.4981 +  TransitionPropData& animDirection = animationPropData[4];
  1.4982 +  TransitionPropData& animFillMode = animationPropData[5];
  1.4983 +  TransitionPropData& animPlayState = animationPropData[6];
  1.4984 +  TransitionPropData& animIterationCount = animationPropData[7];
  1.4985 +
  1.4986 +#define FOR_ALL_ANIMATION_PROPS(var_) \
  1.4987 +    for (uint32_t var_ = 0; var_ < 8; ++var_)
  1.4988 +
  1.4989 +  // CSS Animations.
  1.4990 +
  1.4991 +  uint32_t numAnimations =
  1.4992 +    CountTransitionProps(animationPropInfo, animationPropData,
  1.4993 +                         ArrayLength(animationPropData),
  1.4994 +                         display, parentDisplay, aRuleData,
  1.4995 +                         canStoreInRuleTree);
  1.4996 +
  1.4997 +  display->mAnimations.SetLength(numAnimations);
  1.4998 +
  1.4999 +  FOR_ALL_ANIMATION_PROPS(p) {
  1.5000 +    const TransitionPropInfo& i = animationPropInfo[p];
  1.5001 +    TransitionPropData& d = animationPropData[p];
  1.5002 +
  1.5003 +    display->*(i.sdCount) = d.num;
  1.5004 +  }
  1.5005 +
  1.5006 +  // Fill in the animations we just allocated with the appropriate values.
  1.5007 +  for (uint32_t i = 0; i < numAnimations; ++i) {
  1.5008 +    nsAnimation *animation = &display->mAnimations[i];
  1.5009 +
  1.5010 +    if (i >= animDelay.num) {
  1.5011 +      animation->SetDelay(display->mAnimations[i % animDelay.num].GetDelay());
  1.5012 +    } else if (animDelay.unit == eCSSUnit_Inherit) {
  1.5013 +      // FIXME (Bug 522599) (for all animation properties): write a test that
  1.5014 +      // detects when this was wrong for i >= animDelay.num if parent had
  1.5015 +      // count for this property not equal to length
  1.5016 +      NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDelayCount,
  1.5017 +                        "animDelay.num computed incorrectly");
  1.5018 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.5019 +                        "should have made canStoreInRuleTree false above");
  1.5020 +      animation->SetDelay(parentDisplay->mAnimations[i].GetDelay());
  1.5021 +    } else if (animDelay.unit == eCSSUnit_Initial ||
  1.5022 +               animDelay.unit == eCSSUnit_Unset) {
  1.5023 +      animation->SetDelay(0.0);
  1.5024 +    } else if (animDelay.list) {
  1.5025 +      switch (animDelay.list->mValue.GetUnit()) {
  1.5026 +        case eCSSUnit_Seconds:
  1.5027 +          animation->SetDelay(PR_MSEC_PER_SEC *
  1.5028 +                              animDelay.list->mValue.GetFloatValue());
  1.5029 +          break;
  1.5030 +        case eCSSUnit_Milliseconds:
  1.5031 +          animation->SetDelay(animDelay.list->mValue.GetFloatValue());
  1.5032 +          break;
  1.5033 +        default:
  1.5034 +          NS_NOTREACHED("Invalid delay unit");
  1.5035 +      }
  1.5036 +    }
  1.5037 +
  1.5038 +    if (i >= animDuration.num) {
  1.5039 +      animation->SetDuration(
  1.5040 +        display->mAnimations[i % animDuration.num].GetDuration());
  1.5041 +    } else if (animDuration.unit == eCSSUnit_Inherit) {
  1.5042 +      NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDurationCount,
  1.5043 +                        "animDuration.num computed incorrectly");
  1.5044 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.5045 +                        "should have made canStoreInRuleTree false above");
  1.5046 +      animation->SetDuration(parentDisplay->mAnimations[i].GetDuration());
  1.5047 +    } else if (animDuration.unit == eCSSUnit_Initial ||
  1.5048 +               animDuration.unit == eCSSUnit_Unset) {
  1.5049 +      animation->SetDuration(0.0);
  1.5050 +    } else if (animDuration.list) {
  1.5051 +      switch (animDuration.list->mValue.GetUnit()) {
  1.5052 +        case eCSSUnit_Seconds:
  1.5053 +          animation->SetDuration(PR_MSEC_PER_SEC *
  1.5054 +                                 animDuration.list->mValue.GetFloatValue());
  1.5055 +          break;
  1.5056 +        case eCSSUnit_Milliseconds:
  1.5057 +          animation->SetDuration(animDuration.list->mValue.GetFloatValue());
  1.5058 +          break;
  1.5059 +        default:
  1.5060 +          NS_NOTREACHED("Invalid duration unit");
  1.5061 +      }
  1.5062 +    }
  1.5063 +
  1.5064 +    if (i >= animName.num) {
  1.5065 +      animation->SetName(display->mAnimations[i % animName.num].GetName());
  1.5066 +    } else if (animName.unit == eCSSUnit_Inherit) {
  1.5067 +      NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationNameCount,
  1.5068 +                        "animName.num computed incorrectly");
  1.5069 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.5070 +                        "should have made canStoreInRuleTree false above");
  1.5071 +      animation->SetName(parentDisplay->mAnimations[i].GetName());
  1.5072 +    } else if (animName.unit == eCSSUnit_Initial ||
  1.5073 +               animName.unit == eCSSUnit_Unset) {
  1.5074 +      animation->SetName(EmptyString());
  1.5075 +    } else if (animName.list) {
  1.5076 +      switch (animName.list->mValue.GetUnit()) {
  1.5077 +        case eCSSUnit_Ident: {
  1.5078 +          nsDependentString
  1.5079 +            nameStr(animName.list->mValue.GetStringBufferValue());
  1.5080 +          animation->SetName(nameStr);
  1.5081 +          break;
  1.5082 +        }
  1.5083 +        case eCSSUnit_None: {
  1.5084 +          animation->SetName(EmptyString());
  1.5085 +          break;
  1.5086 +        }
  1.5087 +        default:
  1.5088 +          NS_ABORT_IF_FALSE(false,
  1.5089 +            nsPrintfCString("Invalid animation-name unit %d",
  1.5090 +                                animName.list->mValue.GetUnit()).get());
  1.5091 +      }
  1.5092 +    }
  1.5093 +
  1.5094 +    if (i >= animTimingFunction.num) {
  1.5095 +      animation->SetTimingFunction(
  1.5096 +        display->mAnimations[i % animTimingFunction.num].GetTimingFunction());
  1.5097 +    } else if (animTimingFunction.unit == eCSSUnit_Inherit) {
  1.5098 +      NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationTimingFunctionCount,
  1.5099 +                        "animTimingFunction.num computed incorrectly");
  1.5100 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.5101 +                        "should have made canStoreInRuleTree false above");
  1.5102 +      animation->SetTimingFunction(
  1.5103 +        parentDisplay->mAnimations[i].GetTimingFunction());
  1.5104 +    } else if (animTimingFunction.unit == eCSSUnit_Initial ||
  1.5105 +               animTimingFunction.unit == eCSSUnit_Unset) {
  1.5106 +      animation->SetTimingFunction(
  1.5107 +        nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
  1.5108 +    } else if (animTimingFunction.list) {
  1.5109 +      ComputeTimingFunction(animTimingFunction.list->mValue,
  1.5110 +                            animation->TimingFunctionSlot());
  1.5111 +    }
  1.5112 +
  1.5113 +    if (i >= animDirection.num) {
  1.5114 +      animation->SetDirection(display->mAnimations[i % animDirection.num].GetDirection());
  1.5115 +    } else if (animDirection.unit == eCSSUnit_Inherit) {
  1.5116 +      NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDirectionCount,
  1.5117 +                        "animDirection.num computed incorrectly");
  1.5118 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.5119 +                        "should have made canStoreInRuleTree false above");
  1.5120 +      animation->SetDirection(parentDisplay->mAnimations[i].GetDirection());
  1.5121 +    } else if (animDirection.unit == eCSSUnit_Initial ||
  1.5122 +               animDirection.unit == eCSSUnit_Unset) {
  1.5123 +      animation->SetDirection(NS_STYLE_ANIMATION_DIRECTION_NORMAL);
  1.5124 +    } else if (animDirection.list) {
  1.5125 +      NS_ABORT_IF_FALSE(animDirection.list->mValue.GetUnit() == eCSSUnit_Enumerated,
  1.5126 +                        nsPrintfCString("Invalid animation-direction unit %d",
  1.5127 +                                        animDirection.list->mValue.GetUnit()).get());
  1.5128 +
  1.5129 +      animation->SetDirection(animDirection.list->mValue.GetIntValue());
  1.5130 +    }
  1.5131 +
  1.5132 +    if (i >= animFillMode.num) {
  1.5133 +      animation->SetFillMode(display->mAnimations[i % animFillMode.num].GetFillMode());
  1.5134 +    } else if (animFillMode.unit == eCSSUnit_Inherit) {
  1.5135 +      NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationFillModeCount,
  1.5136 +                        "animFillMode.num computed incorrectly");
  1.5137 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.5138 +                        "should have made canStoreInRuleTree false above");
  1.5139 +      animation->SetFillMode(parentDisplay->mAnimations[i].GetFillMode());
  1.5140 +    } else if (animFillMode.unit == eCSSUnit_Initial ||
  1.5141 +               animFillMode.unit == eCSSUnit_Unset) {
  1.5142 +      animation->SetFillMode(NS_STYLE_ANIMATION_FILL_MODE_NONE);
  1.5143 +    } else if (animFillMode.list) {
  1.5144 +      NS_ABORT_IF_FALSE(animFillMode.list->mValue.GetUnit() == eCSSUnit_Enumerated,
  1.5145 +                        nsPrintfCString("Invalid animation-fill-mode unit %d",
  1.5146 +                                        animFillMode.list->mValue.GetUnit()).get());
  1.5147 +
  1.5148 +      animation->SetFillMode(animFillMode.list->mValue.GetIntValue());
  1.5149 +    }
  1.5150 +
  1.5151 +    if (i >= animPlayState.num) {
  1.5152 +      animation->SetPlayState(display->mAnimations[i % animPlayState.num].GetPlayState());
  1.5153 +    } else if (animPlayState.unit == eCSSUnit_Inherit) {
  1.5154 +      NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationPlayStateCount,
  1.5155 +                        "animPlayState.num computed incorrectly");
  1.5156 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.5157 +                        "should have made canStoreInRuleTree false above");
  1.5158 +      animation->SetPlayState(parentDisplay->mAnimations[i].GetPlayState());
  1.5159 +    } else if (animPlayState.unit == eCSSUnit_Initial ||
  1.5160 +               animPlayState.unit == eCSSUnit_Unset) {
  1.5161 +      animation->SetPlayState(NS_STYLE_ANIMATION_PLAY_STATE_RUNNING);
  1.5162 +    } else if (animPlayState.list) {
  1.5163 +      NS_ABORT_IF_FALSE(animPlayState.list->mValue.GetUnit() == eCSSUnit_Enumerated,
  1.5164 +                        nsPrintfCString("Invalid animation-play-state unit %d",
  1.5165 +                                        animPlayState.list->mValue.GetUnit()).get());
  1.5166 +
  1.5167 +      animation->SetPlayState(animPlayState.list->mValue.GetIntValue());
  1.5168 +    }
  1.5169 +
  1.5170 +    if (i >= animIterationCount.num) {
  1.5171 +      animation->SetIterationCount(display->mAnimations[i % animIterationCount.num].GetIterationCount());
  1.5172 +    } else if (animIterationCount.unit == eCSSUnit_Inherit) {
  1.5173 +      NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationIterationCountCount,
  1.5174 +                        "animIterationCount.num computed incorrectly");
  1.5175 +      NS_ABORT_IF_FALSE(!canStoreInRuleTree,
  1.5176 +                        "should have made canStoreInRuleTree false above");
  1.5177 +      animation->SetIterationCount(parentDisplay->mAnimations[i].GetIterationCount());
  1.5178 +    } else if (animIterationCount.unit == eCSSUnit_Initial ||
  1.5179 +               animIterationCount.unit == eCSSUnit_Unset) {
  1.5180 +      animation->SetIterationCount(1.0f);
  1.5181 +    } else if (animIterationCount.list) {
  1.5182 +      switch (animIterationCount.list->mValue.GetUnit()) {
  1.5183 +        case eCSSUnit_Enumerated:
  1.5184 +          NS_ABORT_IF_FALSE(animIterationCount.list->mValue.GetIntValue() ==
  1.5185 +                              NS_STYLE_ANIMATION_ITERATION_COUNT_INFINITE,
  1.5186 +                            "unexpected value");
  1.5187 +          animation->SetIterationCount(NS_IEEEPositiveInfinity());
  1.5188 +          break;
  1.5189 +        case eCSSUnit_Number:
  1.5190 +          animation->SetIterationCount(
  1.5191 +            animIterationCount.list->mValue.GetFloatValue());
  1.5192 +          break;
  1.5193 +        default:
  1.5194 +          NS_ABORT_IF_FALSE(false,
  1.5195 +                            "unexpected animation-iteration-count unit");
  1.5196 +      }
  1.5197 +    }
  1.5198 +
  1.5199 +    FOR_ALL_ANIMATION_PROPS(p) {
  1.5200 +      const TransitionPropInfo& info = animationPropInfo[p];
  1.5201 +      TransitionPropData& d = animationPropData[p];
  1.5202 +
  1.5203 +      // if we're at the end of the list, start at the beginning and repeat
  1.5204 +      // until we're out of animations to populate
  1.5205 +      if (d.list) {
  1.5206 +        d.list = d.list->mNext ? d.list->mNext :
  1.5207 +          aRuleData->ValueFor(info.property)->GetListValue();
  1.5208 +      }
  1.5209 +    }
  1.5210 +  }
  1.5211 +
  1.5212 +  // opacity: factor, inherit, initial
  1.5213 +  SetFactor(*aRuleData->ValueForOpacity(), display->mOpacity, canStoreInRuleTree,
  1.5214 +            parentDisplay->mOpacity, 1.0f,
  1.5215 +            SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
  1.5216 +
  1.5217 +  // display: enum, inherit, initial
  1.5218 +  SetDiscrete(*aRuleData->ValueForDisplay(), display->mDisplay, canStoreInRuleTree,
  1.5219 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5220 +              parentDisplay->mDisplay,
  1.5221 +              NS_STYLE_DISPLAY_INLINE, 0, 0, 0, 0);
  1.5222 +
  1.5223 +  // mix-blend-mode: enum, inherit, initial
  1.5224 +  SetDiscrete(*aRuleData->ValueForMixBlendMode(), display->mMixBlendMode,
  1.5225 +              canStoreInRuleTree,
  1.5226 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5227 +              parentDisplay->mMixBlendMode, NS_STYLE_BLEND_NORMAL,
  1.5228 +              0, 0, 0, 0);
  1.5229 +
  1.5230 +  // Backup original display value for calculation of a hypothetical
  1.5231 +  // box (CSS2 10.6.4/10.6.5), in addition to getting our style data right later.
  1.5232 +  // See nsHTMLReflowState::CalculateHypotheticalBox
  1.5233 +  display->mOriginalDisplay = display->mDisplay;
  1.5234 +
  1.5235 +  // appearance: enum, inherit, initial
  1.5236 +  SetDiscrete(*aRuleData->ValueForAppearance(),
  1.5237 +              display->mAppearance, canStoreInRuleTree,
  1.5238 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5239 +              parentDisplay->mAppearance,
  1.5240 +              NS_THEME_NONE, 0, 0, 0, 0);
  1.5241 +
  1.5242 +  // binding: url, none, inherit
  1.5243 +  const nsCSSValue* bindingValue = aRuleData->ValueForBinding();
  1.5244 +  if (eCSSUnit_URL == bindingValue->GetUnit()) {
  1.5245 +    mozilla::css::URLValue* url = bindingValue->GetURLStructValue();
  1.5246 +    NS_ASSERTION(url, "What's going on here?");
  1.5247 +
  1.5248 +    if (MOZ_LIKELY(url->GetURI())) {
  1.5249 +      display->mBinding = url;
  1.5250 +    } else {
  1.5251 +      display->mBinding = nullptr;
  1.5252 +    }
  1.5253 +  }
  1.5254 +  else if (eCSSUnit_None == bindingValue->GetUnit() ||
  1.5255 +           eCSSUnit_Initial == bindingValue->GetUnit() ||
  1.5256 +           eCSSUnit_Unset == bindingValue->GetUnit()) {
  1.5257 +    display->mBinding = nullptr;
  1.5258 +  }
  1.5259 +  else if (eCSSUnit_Inherit == bindingValue->GetUnit()) {
  1.5260 +    canStoreInRuleTree = false;
  1.5261 +    display->mBinding = parentDisplay->mBinding;
  1.5262 +  }
  1.5263 +
  1.5264 +  // position: enum, inherit, initial
  1.5265 +  SetDiscrete(*aRuleData->ValueForPosition(), display->mPosition, canStoreInRuleTree,
  1.5266 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5267 +              parentDisplay->mPosition,
  1.5268 +              NS_STYLE_POSITION_STATIC, 0, 0, 0, 0);
  1.5269 +
  1.5270 +  // clear: enum, inherit, initial
  1.5271 +  SetDiscrete(*aRuleData->ValueForClear(), display->mBreakType, canStoreInRuleTree,
  1.5272 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5273 +              parentDisplay->mBreakType,
  1.5274 +              NS_STYLE_CLEAR_NONE, 0, 0, 0, 0);
  1.5275 +
  1.5276 +  // temp fix for bug 24000
  1.5277 +  // Map 'auto' and 'avoid' to false, and 'always', 'left', and
  1.5278 +  // 'right' to true.
  1.5279 +  // "A conforming user agent may interpret the values 'left' and
  1.5280 +  // 'right' as 'always'." - CSS2.1, section 13.3.1
  1.5281 +  const nsCSSValue* breakBeforeValue = aRuleData->ValueForPageBreakBefore();
  1.5282 +  if (eCSSUnit_Enumerated == breakBeforeValue->GetUnit()) {
  1.5283 +    display->mBreakBefore =
  1.5284 +      (NS_STYLE_PAGE_BREAK_AVOID != breakBeforeValue->GetIntValue() &&
  1.5285 +       NS_STYLE_PAGE_BREAK_AUTO  != breakBeforeValue->GetIntValue());
  1.5286 +  }
  1.5287 +  else if (eCSSUnit_Initial == breakBeforeValue->GetUnit() ||
  1.5288 +           eCSSUnit_Unset == breakBeforeValue->GetUnit()) {
  1.5289 +    display->mBreakBefore = false;
  1.5290 +  }
  1.5291 +  else if (eCSSUnit_Inherit == breakBeforeValue->GetUnit()) {
  1.5292 +    canStoreInRuleTree = false;
  1.5293 +    display->mBreakBefore = parentDisplay->mBreakBefore;
  1.5294 +  }
  1.5295 +
  1.5296 +  const nsCSSValue* breakAfterValue = aRuleData->ValueForPageBreakAfter();
  1.5297 +  if (eCSSUnit_Enumerated == breakAfterValue->GetUnit()) {
  1.5298 +    display->mBreakAfter =
  1.5299 +      (NS_STYLE_PAGE_BREAK_AVOID != breakAfterValue->GetIntValue() &&
  1.5300 +       NS_STYLE_PAGE_BREAK_AUTO  != breakAfterValue->GetIntValue());
  1.5301 +  }
  1.5302 +  else if (eCSSUnit_Initial == breakAfterValue->GetUnit() ||
  1.5303 +           eCSSUnit_Unset == breakAfterValue->GetUnit()) {
  1.5304 +    display->mBreakAfter = false;
  1.5305 +  }
  1.5306 +  else if (eCSSUnit_Inherit == breakAfterValue->GetUnit()) {
  1.5307 +    canStoreInRuleTree = false;
  1.5308 +    display->mBreakAfter = parentDisplay->mBreakAfter;
  1.5309 +  }
  1.5310 +  // end temp fix
  1.5311 +
  1.5312 +  // page-break-inside: enum, inherit, initial
  1.5313 +  SetDiscrete(*aRuleData->ValueForPageBreakInside(),
  1.5314 +              display->mBreakInside, canStoreInRuleTree,
  1.5315 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5316 +              parentDisplay->mBreakInside,
  1.5317 +              NS_STYLE_PAGE_BREAK_AUTO, 0, 0, 0, 0);
  1.5318 +
  1.5319 +  // touch-action: none, auto, enum, inherit, initial
  1.5320 +  SetDiscrete(*aRuleData->ValueForTouchAction(), display->mTouchAction,
  1.5321 +              canStoreInRuleTree,
  1.5322 +              SETDSC_ENUMERATED | SETDSC_AUTO | SETDSC_NONE |
  1.5323 +                SETDSC_UNSET_INITIAL,
  1.5324 +              parentDisplay->mTouchAction,
  1.5325 +              NS_STYLE_TOUCH_ACTION_AUTO,
  1.5326 +              NS_STYLE_TOUCH_ACTION_AUTO,
  1.5327 +              NS_STYLE_TOUCH_ACTION_NONE, 0, 0);
  1.5328 +
  1.5329 +  // float: enum, inherit, initial
  1.5330 +  SetDiscrete(*aRuleData->ValueForFloat(),
  1.5331 +              display->mFloats, canStoreInRuleTree,
  1.5332 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5333 +              parentDisplay->mFloats,
  1.5334 +              NS_STYLE_FLOAT_NONE, 0, 0, 0, 0);
  1.5335 +  // Save mFloats in mOriginalFloats in case we need it later
  1.5336 +  display->mOriginalFloats = display->mFloats;
  1.5337 +
  1.5338 +  // overflow-x: enum, inherit, initial
  1.5339 +  SetDiscrete(*aRuleData->ValueForOverflowX(),
  1.5340 +              display->mOverflowX, canStoreInRuleTree,
  1.5341 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5342 +              parentDisplay->mOverflowX,
  1.5343 +              NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
  1.5344 +
  1.5345 +  // overflow-y: enum, inherit, initial
  1.5346 +  SetDiscrete(*aRuleData->ValueForOverflowY(),
  1.5347 +              display->mOverflowY, canStoreInRuleTree,
  1.5348 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5349 +              parentDisplay->mOverflowY,
  1.5350 +              NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
  1.5351 +
  1.5352 +  // CSS3 overflow-x and overflow-y require some fixup as well in some
  1.5353 +  // cases.  NS_STYLE_OVERFLOW_VISIBLE and NS_STYLE_OVERFLOW_CLIP are
  1.5354 +  // meaningful only when used in both dimensions.
  1.5355 +  if (display->mOverflowX != display->mOverflowY &&
  1.5356 +      (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE ||
  1.5357 +       display->mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
  1.5358 +       display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE ||
  1.5359 +       display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)) {
  1.5360 +    // We can't store in the rule tree since a more specific rule might
  1.5361 +    // change these conditions.
  1.5362 +    canStoreInRuleTree = false;
  1.5363 +
  1.5364 +    // NS_STYLE_OVERFLOW_CLIP is a deprecated value, so if it's specified
  1.5365 +    // in only one dimension, convert it to NS_STYLE_OVERFLOW_HIDDEN.
  1.5366 +    if (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
  1.5367 +      display->mOverflowX = NS_STYLE_OVERFLOW_HIDDEN;
  1.5368 +    if (display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)
  1.5369 +      display->mOverflowY = NS_STYLE_OVERFLOW_HIDDEN;
  1.5370 +
  1.5371 +    // If 'visible' is specified but doesn't match the other dimension, it
  1.5372 +    // turns into 'auto'.
  1.5373 +    if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
  1.5374 +      display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
  1.5375 +    if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
  1.5376 +      display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
  1.5377 +  }
  1.5378 +
  1.5379 +  SetDiscrete(*aRuleData->ValueForOverflowClipBox(), display->mOverflowClipBox,
  1.5380 +              canStoreInRuleTree,
  1.5381 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5382 +              parentDisplay->mOverflowClipBox,
  1.5383 +              NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX, 0, 0, 0, 0);
  1.5384 +
  1.5385 +  SetDiscrete(*aRuleData->ValueForResize(), display->mResize, canStoreInRuleTree,
  1.5386 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5387 +              parentDisplay->mResize,
  1.5388 +              NS_STYLE_RESIZE_NONE, 0, 0, 0, 0);
  1.5389 +
  1.5390 +  // clip property: length, auto, inherit
  1.5391 +  const nsCSSValue* clipValue = aRuleData->ValueForClip();
  1.5392 +  switch (clipValue->GetUnit()) {
  1.5393 +  case eCSSUnit_Inherit:
  1.5394 +    canStoreInRuleTree = false;
  1.5395 +    display->mClipFlags = parentDisplay->mClipFlags;
  1.5396 +    display->mClip = parentDisplay->mClip;
  1.5397 +    break;
  1.5398 +
  1.5399 +  case eCSSUnit_Initial:
  1.5400 +  case eCSSUnit_Unset:
  1.5401 +  case eCSSUnit_Auto:
  1.5402 +    display->mClipFlags = NS_STYLE_CLIP_AUTO;
  1.5403 +    display->mClip.SetRect(0,0,0,0);
  1.5404 +    break;
  1.5405 +
  1.5406 +  case eCSSUnit_Null:
  1.5407 +    break;
  1.5408 +
  1.5409 +  case eCSSUnit_Rect: {
  1.5410 +    const nsCSSRect& clipRect = clipValue->GetRectValue();
  1.5411 +
  1.5412 +    display->mClipFlags = NS_STYLE_CLIP_RECT;
  1.5413 +
  1.5414 +    if (clipRect.mTop.GetUnit() == eCSSUnit_Auto) {
  1.5415 +      display->mClip.y = 0;
  1.5416 +      display->mClipFlags |= NS_STYLE_CLIP_TOP_AUTO;
  1.5417 +    }
  1.5418 +    else if (clipRect.mTop.IsLengthUnit()) {
  1.5419 +      display->mClip.y = CalcLength(clipRect.mTop, aContext,
  1.5420 +                                    mPresContext, canStoreInRuleTree);
  1.5421 +    }
  1.5422 +
  1.5423 +    if (clipRect.mBottom.GetUnit() == eCSSUnit_Auto) {
  1.5424 +      // Setting to NS_MAXSIZE for the 'auto' case ensures that
  1.5425 +      // the clip rect is nonempty. It is important that mClip be
  1.5426 +      // nonempty if the actual clip rect could be nonempty.
  1.5427 +      display->mClip.height = NS_MAXSIZE;
  1.5428 +      display->mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO;
  1.5429 +    }
  1.5430 +    else if (clipRect.mBottom.IsLengthUnit()) {
  1.5431 +      display->mClip.height = CalcLength(clipRect.mBottom, aContext,
  1.5432 +                                         mPresContext, canStoreInRuleTree) -
  1.5433 +                              display->mClip.y;
  1.5434 +    }
  1.5435 +
  1.5436 +    if (clipRect.mLeft.GetUnit() == eCSSUnit_Auto) {
  1.5437 +      display->mClip.x = 0;
  1.5438 +      display->mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO;
  1.5439 +    }
  1.5440 +    else if (clipRect.mLeft.IsLengthUnit()) {
  1.5441 +      display->mClip.x = CalcLength(clipRect.mLeft, aContext,
  1.5442 +                                    mPresContext, canStoreInRuleTree);
  1.5443 +    }
  1.5444 +
  1.5445 +    if (clipRect.mRight.GetUnit() == eCSSUnit_Auto) {
  1.5446 +      // Setting to NS_MAXSIZE for the 'auto' case ensures that
  1.5447 +      // the clip rect is nonempty. It is important that mClip be
  1.5448 +      // nonempty if the actual clip rect could be nonempty.
  1.5449 +      display->mClip.width = NS_MAXSIZE;
  1.5450 +      display->mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO;
  1.5451 +    }
  1.5452 +    else if (clipRect.mRight.IsLengthUnit()) {
  1.5453 +      display->mClip.width = CalcLength(clipRect.mRight, aContext,
  1.5454 +                                        mPresContext, canStoreInRuleTree) -
  1.5455 +                             display->mClip.x;
  1.5456 +    }
  1.5457 +    break;
  1.5458 +  }
  1.5459 +
  1.5460 +  default:
  1.5461 +    NS_ABORT_IF_FALSE(false, "unrecognized clip unit");
  1.5462 +  }
  1.5463 +
  1.5464 +  if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
  1.5465 +    // CSS2 9.7 specifies display type corrections dealing with 'float'
  1.5466 +    // and 'position'.  Since generated content can't be floated or
  1.5467 +    // positioned, we can deal with it here.
  1.5468 +
  1.5469 +    if (nsCSSPseudoElements::firstLetter == aContext->GetPseudo()) {
  1.5470 +      // a non-floating first-letter must be inline
  1.5471 +      // XXX this fix can go away once bug 103189 is fixed correctly
  1.5472 +      // Note that we reset mOriginalDisplay to enforce the invariant that it equals mDisplay if we're not positioned or floating.
  1.5473 +      display->mOriginalDisplay = display->mDisplay = NS_STYLE_DISPLAY_INLINE;
  1.5474 +
  1.5475 +      // We can't cache the data in the rule tree since if a more specific
  1.5476 +      // rule has 'float: left' we'll end up with the wrong 'display'
  1.5477 +      // property.
  1.5478 +      canStoreInRuleTree = false;
  1.5479 +    }
  1.5480 +
  1.5481 +    if (display->IsAbsolutelyPositionedStyle()) {
  1.5482 +      // 1) if position is 'absolute' or 'fixed' then display must be
  1.5483 +      // block-level and float must be 'none'
  1.5484 +      EnsureBlockDisplay(display->mDisplay);
  1.5485 +      display->mFloats = NS_STYLE_FLOAT_NONE;
  1.5486 +
  1.5487 +      // Note that it's OK to cache this struct in the ruletree
  1.5488 +      // because it's fine as-is for any style context that points to
  1.5489 +      // it directly, and any use of it as aStartStruct (e.g. if a
  1.5490 +      // more specific rule sets "position: static") will use
  1.5491 +      // mOriginalDisplay and mOriginalFloats, which we have carefully
  1.5492 +      // not changed.
  1.5493 +    } else if (display->mFloats != NS_STYLE_FLOAT_NONE) {
  1.5494 +      // 2) if float is not none, and display is not none, then we must
  1.5495 +      // set a block-level 'display' type per CSS2.1 section 9.7.
  1.5496 +      EnsureBlockDisplay(display->mDisplay);
  1.5497 +
  1.5498 +      // Note that it's OK to cache this struct in the ruletree
  1.5499 +      // because it's fine as-is for any style context that points to
  1.5500 +      // it directly, and any use of it as aStartStruct (e.g. if a
  1.5501 +      // more specific rule sets "float: none") will use
  1.5502 +      // mOriginalDisplay, which we have carefully not changed.
  1.5503 +    }
  1.5504 +
  1.5505 +  }
  1.5506 +
  1.5507 +  /* Convert the nsCSSValueList into an nsTArray<nsTransformFunction *>. */
  1.5508 +  const nsCSSValue* transformValue = aRuleData->ValueForTransform();
  1.5509 +  switch (transformValue->GetUnit()) {
  1.5510 +  case eCSSUnit_Null:
  1.5511 +    break;
  1.5512 +
  1.5513 +  case eCSSUnit_Initial:
  1.5514 +  case eCSSUnit_Unset:
  1.5515 +  case eCSSUnit_None:
  1.5516 +    display->mSpecifiedTransform = nullptr;
  1.5517 +    break;
  1.5518 +
  1.5519 +  case eCSSUnit_Inherit:
  1.5520 +    display->mSpecifiedTransform = parentDisplay->mSpecifiedTransform;
  1.5521 +    canStoreInRuleTree = false;
  1.5522 +    break;
  1.5523 +
  1.5524 +  case eCSSUnit_SharedList: {
  1.5525 +    nsCSSValueSharedList* list = transformValue->GetSharedListValue();
  1.5526 +    nsCSSValueList* head = list->mHead;
  1.5527 +    MOZ_ASSERT(head, "transform list must have at least one item");
  1.5528 +    // can get a _None in here from transform animation
  1.5529 +    if (head->mValue.GetUnit() == eCSSUnit_None) {
  1.5530 +      NS_ABORT_IF_FALSE(head->mNext == nullptr, "none must be alone");
  1.5531 +      display->mSpecifiedTransform = nullptr;
  1.5532 +    } else {
  1.5533 +      display->mSpecifiedTransform = list;
  1.5534 +    }
  1.5535 +    break;
  1.5536 +  }
  1.5537 +
  1.5538 +  default:
  1.5539 +    NS_ABORT_IF_FALSE(false, "unrecognized transform unit");
  1.5540 +  }
  1.5541 +
  1.5542 +  /* Convert the nsCSSValueList into a will-change bitfield for fast lookup */
  1.5543 +  const nsCSSValue* willChangeValue = aRuleData->ValueForWillChange();
  1.5544 +  switch (willChangeValue->GetUnit()) {
  1.5545 +  case eCSSUnit_Null:
  1.5546 +    break;
  1.5547 +
  1.5548 +  case eCSSUnit_List:
  1.5549 +  case eCSSUnit_ListDep: {
  1.5550 +    display->mWillChange.Clear();
  1.5551 +    display->mWillChangeBitField = 0;
  1.5552 +    for (const nsCSSValueList* item = willChangeValue->GetListValue();
  1.5553 +         item; item = item->mNext)
  1.5554 +    {
  1.5555 +      if (item->mValue.UnitHasStringValue()) {
  1.5556 +        nsAutoString buffer;
  1.5557 +        item->mValue.GetStringValue(buffer);
  1.5558 +        display->mWillChange.AppendElement(buffer);
  1.5559 +
  1.5560 +        if (buffer.EqualsLiteral("transform")) {
  1.5561 +          display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_TRANSFORM;
  1.5562 +        }
  1.5563 +        if (buffer.EqualsLiteral("opacity")) {
  1.5564 +          display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_OPACITY;
  1.5565 +        }
  1.5566 +        if (buffer.EqualsLiteral("scroll-position")) {
  1.5567 +          display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_SCROLL;
  1.5568 +        }
  1.5569 +
  1.5570 +        nsCSSProperty prop =
  1.5571 +          nsCSSProps::LookupProperty(buffer,
  1.5572 +                                     nsCSSProps::eEnabledForAllContent);
  1.5573 +        if (prop != eCSSProperty_UNKNOWN &&
  1.5574 +            nsCSSProps::PropHasFlags(prop,
  1.5575 +                                     CSS_PROPERTY_CREATES_STACKING_CONTEXT))
  1.5576 +        {
  1.5577 +          display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_STACKING_CONTEXT;
  1.5578 +        }
  1.5579 +      }
  1.5580 +    }
  1.5581 +    break;
  1.5582 +  }
  1.5583 +
  1.5584 +  case eCSSUnit_Inherit:
  1.5585 +    display->mWillChange = parentDisplay->mWillChange;
  1.5586 +    display->mWillChangeBitField = parentDisplay->mWillChangeBitField;
  1.5587 +    canStoreInRuleTree = false;
  1.5588 +    break;
  1.5589 +
  1.5590 +  case eCSSUnit_Initial:
  1.5591 +  case eCSSUnit_Unset:
  1.5592 +  case eCSSUnit_Auto:
  1.5593 +    display->mWillChange.Clear();
  1.5594 +    display->mWillChangeBitField = 0;
  1.5595 +    break;
  1.5596 +
  1.5597 +  default:
  1.5598 +    MOZ_ASSERT(false, "unrecognized will-change unit");
  1.5599 +  }
  1.5600 +
  1.5601 +  /* Convert -moz-transform-origin. */
  1.5602 +  const nsCSSValue* transformOriginValue =
  1.5603 +    aRuleData->ValueForTransformOrigin();
  1.5604 +  if (transformOriginValue->GetUnit() != eCSSUnit_Null) {
  1.5605 +    const nsCSSValue& valX =
  1.5606 +      transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
  1.5607 +        transformOriginValue->GetTripletValue().mXValue : *transformOriginValue;
  1.5608 +    const nsCSSValue& valY =
  1.5609 +      transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
  1.5610 +        transformOriginValue->GetTripletValue().mYValue : *transformOriginValue;
  1.5611 +    const nsCSSValue& valZ =
  1.5612 +      transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
  1.5613 +        transformOriginValue->GetTripletValue().mZValue : *transformOriginValue;
  1.5614 +
  1.5615 +    mozilla::DebugOnly<bool> cX =
  1.5616 +       SetCoord(valX, display->mTransformOrigin[0],
  1.5617 +                parentDisplay->mTransformOrigin[0],
  1.5618 +                SETCOORD_LPH | SETCOORD_INITIAL_HALF |
  1.5619 +                  SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
  1.5620 +                  SETCOORD_UNSET_INITIAL,
  1.5621 +                aContext, mPresContext, canStoreInRuleTree);
  1.5622 +
  1.5623 +     mozilla::DebugOnly<bool> cY =
  1.5624 +       SetCoord(valY, display->mTransformOrigin[1],
  1.5625 +                parentDisplay->mTransformOrigin[1],
  1.5626 +                SETCOORD_LPH | SETCOORD_INITIAL_HALF |
  1.5627 +                  SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
  1.5628 +                  SETCOORD_UNSET_INITIAL,
  1.5629 +                aContext, mPresContext, canStoreInRuleTree);
  1.5630 +
  1.5631 +     if (valZ.GetUnit() == eCSSUnit_Null) {
  1.5632 +       // Null for the z component means a 0 translation, not
  1.5633 +       // unspecified, as we have already checked the triplet
  1.5634 +       // value for Null.
  1.5635 +       display->mTransformOrigin[2].SetCoordValue(0);
  1.5636 +     } else {
  1.5637 +       mozilla::DebugOnly<bool> cZ =
  1.5638 +         SetCoord(valZ, display->mTransformOrigin[2],
  1.5639 +                  parentDisplay->mTransformOrigin[2],
  1.5640 +                  SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  1.5641 +                    SETCOORD_UNSET_INITIAL,
  1.5642 +                  aContext, mPresContext, canStoreInRuleTree);
  1.5643 +       NS_ABORT_IF_FALSE(cY == cZ, "changed one but not the other");
  1.5644 +     }
  1.5645 +     NS_ABORT_IF_FALSE(cX == cY, "changed one but not the other");
  1.5646 +     NS_ASSERTION(cX, "Malformed -moz-transform-origin parse!");
  1.5647 +  }
  1.5648 +
  1.5649 +  const nsCSSValue* perspectiveOriginValue =
  1.5650 +    aRuleData->ValueForPerspectiveOrigin();
  1.5651 +  if (perspectiveOriginValue->GetUnit() != eCSSUnit_Null) {
  1.5652 +    mozilla::DebugOnly<bool> result =
  1.5653 +      SetPairCoords(*perspectiveOriginValue,
  1.5654 +                    display->mPerspectiveOrigin[0],
  1.5655 +                    display->mPerspectiveOrigin[1],
  1.5656 +                    parentDisplay->mPerspectiveOrigin[0],
  1.5657 +                    parentDisplay->mPerspectiveOrigin[1],
  1.5658 +                    SETCOORD_LPH | SETCOORD_INITIAL_HALF |
  1.5659 +                      SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
  1.5660 +                      SETCOORD_UNSET_INITIAL,
  1.5661 +                    aContext, mPresContext, canStoreInRuleTree);
  1.5662 +    NS_ASSERTION(result, "Malformed -moz-perspective-origin parse!");
  1.5663 +  }
  1.5664 +
  1.5665 +  SetCoord(*aRuleData->ValueForPerspective(), 
  1.5666 +           display->mChildPerspective, parentDisplay->mChildPerspective,
  1.5667 +           SETCOORD_LAH | SETCOORD_INITIAL_NONE | SETCOORD_NONE |
  1.5668 +             SETCOORD_UNSET_INITIAL,
  1.5669 +           aContext, mPresContext, canStoreInRuleTree);
  1.5670 +
  1.5671 +  SetDiscrete(*aRuleData->ValueForBackfaceVisibility(),
  1.5672 +              display->mBackfaceVisibility, canStoreInRuleTree,
  1.5673 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5674 +              parentDisplay->mBackfaceVisibility,
  1.5675 +              NS_STYLE_BACKFACE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
  1.5676 +
  1.5677 +  // transform-style: enum, inherit, initial
  1.5678 +  SetDiscrete(*aRuleData->ValueForTransformStyle(),
  1.5679 +              display->mTransformStyle, canStoreInRuleTree,
  1.5680 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5681 +              parentDisplay->mTransformStyle,
  1.5682 +              NS_STYLE_TRANSFORM_STYLE_FLAT, 0, 0, 0, 0);
  1.5683 +
  1.5684 +  // orient: enum, inherit, initial
  1.5685 +  SetDiscrete(*aRuleData->ValueForOrient(),
  1.5686 +              display->mOrient, canStoreInRuleTree,
  1.5687 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.5688 +              parentDisplay->mOrient,
  1.5689 +              NS_STYLE_ORIENT_AUTO, 0, 0, 0, 0);
  1.5690 +
  1.5691 +  COMPUTE_END_RESET(Display, display)
  1.5692 +}
  1.5693 +
  1.5694 +const void*
  1.5695 +nsRuleNode::ComputeVisibilityData(void* aStartStruct,
  1.5696 +                                  const nsRuleData* aRuleData,
  1.5697 +                                  nsStyleContext* aContext,
  1.5698 +                                  nsRuleNode* aHighestNode,
  1.5699 +                                  const RuleDetail aRuleDetail,
  1.5700 +                                  const bool aCanStoreInRuleTree)
  1.5701 +{
  1.5702 +  COMPUTE_START_INHERITED(Visibility, (mPresContext),
  1.5703 +                          visibility, parentVisibility)
  1.5704 +
  1.5705 +  // IMPORTANT: No properties in this struct have lengths in them.  We
  1.5706 +  // depend on this since CalcLengthWith can call StyleVisibility()
  1.5707 +  // to get the language for resolving fonts!
  1.5708 +
  1.5709 +  // direction: enum, inherit, initial
  1.5710 +  SetDiscrete(*aRuleData->ValueForDirection(), visibility->mDirection,
  1.5711 +              canStoreInRuleTree,
  1.5712 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.5713 +              parentVisibility->mDirection,
  1.5714 +              (GET_BIDI_OPTION_DIRECTION(mPresContext->GetBidi())
  1.5715 +               == IBMBIDI_TEXTDIRECTION_RTL)
  1.5716 +              ? NS_STYLE_DIRECTION_RTL : NS_STYLE_DIRECTION_LTR,
  1.5717 +              0, 0, 0, 0);
  1.5718 +
  1.5719 +  // visibility: enum, inherit, initial
  1.5720 +  SetDiscrete(*aRuleData->ValueForVisibility(), visibility->mVisible,
  1.5721 +              canStoreInRuleTree,
  1.5722 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.5723 +              parentVisibility->mVisible,
  1.5724 +              NS_STYLE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
  1.5725 +
  1.5726 +  // pointer-events: enum, inherit, initial
  1.5727 +  SetDiscrete(*aRuleData->ValueForPointerEvents(), visibility->mPointerEvents,
  1.5728 +              canStoreInRuleTree,
  1.5729 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.5730 +              parentVisibility->mPointerEvents,
  1.5731 +              NS_STYLE_POINTER_EVENTS_AUTO, 0, 0, 0, 0);
  1.5732 +
  1.5733 +  // writing-mode: enum, inherit, initial
  1.5734 +  SetDiscrete(*aRuleData->ValueForWritingMode(), visibility->mWritingMode,
  1.5735 +              canStoreInRuleTree,
  1.5736 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.5737 +              parentVisibility->mWritingMode,
  1.5738 +              NS_STYLE_WRITING_MODE_HORIZONTAL_TB, 0, 0, 0, 0);
  1.5739 +
  1.5740 +  // image-orientation: enum, inherit, initial
  1.5741 +  const nsCSSValue* orientation = aRuleData->ValueForImageOrientation();
  1.5742 +  if (orientation->GetUnit() == eCSSUnit_Inherit ||
  1.5743 +      orientation->GetUnit() == eCSSUnit_Unset) {
  1.5744 +    canStoreInRuleTree = false;
  1.5745 +    visibility->mImageOrientation = parentVisibility->mImageOrientation;
  1.5746 +  } else if (orientation->GetUnit() == eCSSUnit_Initial) {
  1.5747 +    visibility->mImageOrientation = nsStyleImageOrientation();
  1.5748 +  } else if (orientation->IsAngularUnit()) {
  1.5749 +    double angle = orientation->GetAngleValueInRadians();
  1.5750 +    visibility->mImageOrientation =
  1.5751 +      nsStyleImageOrientation::CreateAsAngleAndFlip(angle, false);
  1.5752 +  } else if (orientation->GetUnit() == eCSSUnit_Array) {
  1.5753 +    const nsCSSValue::Array* array = orientation->GetArrayValue();
  1.5754 +    MOZ_ASSERT(array->Item(0).IsAngularUnit(),
  1.5755 +               "First image-orientation value is not an angle");
  1.5756 +    MOZ_ASSERT(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
  1.5757 +               array->Item(1).GetIntValue() == NS_STYLE_IMAGE_ORIENTATION_FLIP,
  1.5758 +               "Second image-orientation value is not 'flip'");
  1.5759 +    double angle = array->Item(0).GetAngleValueInRadians();
  1.5760 +    visibility->mImageOrientation =
  1.5761 +      nsStyleImageOrientation::CreateAsAngleAndFlip(angle, true);
  1.5762 +    
  1.5763 +  } else if (orientation->GetUnit() == eCSSUnit_Enumerated) {
  1.5764 +    switch (orientation->GetIntValue()) {
  1.5765 +      case NS_STYLE_IMAGE_ORIENTATION_FLIP:
  1.5766 +        visibility->mImageOrientation = nsStyleImageOrientation::CreateAsFlip();
  1.5767 +        break;
  1.5768 +      case NS_STYLE_IMAGE_ORIENTATION_FROM_IMAGE:
  1.5769 +        visibility->mImageOrientation = nsStyleImageOrientation::CreateAsFromImage();
  1.5770 +        break;
  1.5771 +      default:
  1.5772 +        NS_NOTREACHED("Invalid image-orientation enumerated value");
  1.5773 +    }
  1.5774 +  } else {
  1.5775 +    MOZ_ASSERT(orientation->GetUnit() == eCSSUnit_Null, "Should be null unit");
  1.5776 +  }
  1.5777 +
  1.5778 +  COMPUTE_END_INHERITED(Visibility, visibility)
  1.5779 +}
  1.5780 +
  1.5781 +const void*
  1.5782 +nsRuleNode::ComputeColorData(void* aStartStruct,
  1.5783 +                             const nsRuleData* aRuleData,
  1.5784 +                             nsStyleContext* aContext,
  1.5785 +                             nsRuleNode* aHighestNode,
  1.5786 +                             const RuleDetail aRuleDetail,
  1.5787 +                             const bool aCanStoreInRuleTree)
  1.5788 +{
  1.5789 +  COMPUTE_START_INHERITED(Color, (mPresContext), color, parentColor)
  1.5790 +
  1.5791 +  // color: color, string, inherit
  1.5792 +  // Special case for currentColor.  According to CSS3, setting color to 'currentColor'
  1.5793 +  // should behave as if it is inherited
  1.5794 +  const nsCSSValue* colorValue = aRuleData->ValueForColor();
  1.5795 +  if ((colorValue->GetUnit() == eCSSUnit_EnumColor &&
  1.5796 +       colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) ||
  1.5797 +      colorValue->GetUnit() == eCSSUnit_Unset) {
  1.5798 +    color->mColor = parentColor->mColor;
  1.5799 +    canStoreInRuleTree = false;
  1.5800 +  }
  1.5801 +  else if (colorValue->GetUnit() == eCSSUnit_Initial) {
  1.5802 +    color->mColor = mPresContext->DefaultColor();
  1.5803 +  }
  1.5804 +  else {
  1.5805 +    SetColor(*colorValue, parentColor->mColor, mPresContext, aContext,
  1.5806 +             color->mColor, canStoreInRuleTree);
  1.5807 +  }
  1.5808 +
  1.5809 +  COMPUTE_END_INHERITED(Color, color)
  1.5810 +}
  1.5811 +
  1.5812 +// information about how to compute values for background-* properties
  1.5813 +template <class SpecifiedValueItem, class ComputedValueItem>
  1.5814 +struct BackgroundItemComputer {
  1.5815 +};
  1.5816 +
  1.5817 +template <>
  1.5818 +struct BackgroundItemComputer<nsCSSValueList, uint8_t>
  1.5819 +{
  1.5820 +  static void ComputeValue(nsStyleContext* aStyleContext,
  1.5821 +                           const nsCSSValueList* aSpecifiedValue,
  1.5822 +                           uint8_t& aComputedValue,
  1.5823 +                           bool& aCanStoreInRuleTree)
  1.5824 +  {
  1.5825 +    SetDiscrete(aSpecifiedValue->mValue, aComputedValue, aCanStoreInRuleTree,
  1.5826 +                SETDSC_ENUMERATED, uint8_t(0), 0, 0, 0, 0, 0);
  1.5827 +  }
  1.5828 +};
  1.5829 +
  1.5830 +template <>
  1.5831 +struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Repeat>
  1.5832 +{
  1.5833 +  static void ComputeValue(nsStyleContext* aStyleContext,
  1.5834 +                           const nsCSSValuePairList* aSpecifiedValue,
  1.5835 +                           nsStyleBackground::Repeat& aComputedValue,
  1.5836 +                           bool& aCanStoreInRuleTree)
  1.5837 +  {
  1.5838 +    NS_ASSERTION(aSpecifiedValue->mXValue.GetUnit() == eCSSUnit_Enumerated &&
  1.5839 +                 (aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Enumerated ||
  1.5840 +                  aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null),
  1.5841 +                 "Invalid unit");
  1.5842 +    
  1.5843 +    bool hasContraction = true;
  1.5844 +    uint8_t value = aSpecifiedValue->mXValue.GetIntValue();
  1.5845 +    switch (value) {
  1.5846 +    case NS_STYLE_BG_REPEAT_REPEAT_X:
  1.5847 +      aComputedValue.mXRepeat = NS_STYLE_BG_REPEAT_REPEAT;
  1.5848 +      aComputedValue.mYRepeat = NS_STYLE_BG_REPEAT_NO_REPEAT;
  1.5849 +      break;
  1.5850 +    case NS_STYLE_BG_REPEAT_REPEAT_Y:
  1.5851 +      aComputedValue.mXRepeat = NS_STYLE_BG_REPEAT_NO_REPEAT;
  1.5852 +      aComputedValue.mYRepeat = NS_STYLE_BG_REPEAT_REPEAT;
  1.5853 +      break;
  1.5854 +    default:
  1.5855 +      aComputedValue.mXRepeat = value;
  1.5856 +      hasContraction = false;
  1.5857 +      break;
  1.5858 +    }
  1.5859 +    
  1.5860 +    if (hasContraction) {
  1.5861 +      NS_ASSERTION(aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null,
  1.5862 +                   "Invalid unit.");
  1.5863 +      return;
  1.5864 +    }
  1.5865 +    
  1.5866 +    switch (aSpecifiedValue->mYValue.GetUnit()) {
  1.5867 +    case eCSSUnit_Null:
  1.5868 +      aComputedValue.mYRepeat = aComputedValue.mXRepeat;
  1.5869 +      break;
  1.5870 +    case eCSSUnit_Enumerated:
  1.5871 +      value = aSpecifiedValue->mYValue.GetIntValue();
  1.5872 +      NS_ASSERTION(value == NS_STYLE_BG_REPEAT_NO_REPEAT ||
  1.5873 +                   value == NS_STYLE_BG_REPEAT_REPEAT, "Unexpected value");
  1.5874 +      aComputedValue.mYRepeat = value;
  1.5875 +      break;
  1.5876 +    default:
  1.5877 +      NS_NOTREACHED("Unexpected CSS value");
  1.5878 +      break;
  1.5879 +    }
  1.5880 +  }
  1.5881 +};
  1.5882 +
  1.5883 +template <>
  1.5884 +struct BackgroundItemComputer<nsCSSValueList, nsStyleImage>
  1.5885 +{
  1.5886 +  static void ComputeValue(nsStyleContext* aStyleContext,
  1.5887 +                           const nsCSSValueList* aSpecifiedValue,
  1.5888 +                           nsStyleImage& aComputedValue,
  1.5889 +                           bool& aCanStoreInRuleTree)
  1.5890 +  {
  1.5891 +    SetStyleImage(aStyleContext, aSpecifiedValue->mValue, aComputedValue,
  1.5892 +                  aCanStoreInRuleTree);
  1.5893 +  }
  1.5894 +};
  1.5895 +
  1.5896 +/* Helper function for
  1.5897 + * BackgroundItemComputer<nsCSSValue, nsStyleBackground::Position>
  1.5898 + * It computes a single PositionCoord from an nsCSSValue object
  1.5899 + * (contained in a list).
  1.5900 + */
  1.5901 +typedef nsStyleBackground::Position::PositionCoord PositionCoord;
  1.5902 +static void
  1.5903 +ComputeBackgroundPositionCoord(nsStyleContext* aStyleContext,
  1.5904 +                               const nsCSSValue& aEdge,
  1.5905 +                               const nsCSSValue& aOffset,
  1.5906 +                               PositionCoord* aResult,
  1.5907 +                               bool& aCanStoreInRuleTree)
  1.5908 +{
  1.5909 +  if (eCSSUnit_Percent == aOffset.GetUnit()) {
  1.5910 +    aResult->mLength = 0;
  1.5911 +    aResult->mPercent = aOffset.GetPercentValue();
  1.5912 +    aResult->mHasPercent = true;
  1.5913 +  } else if (aOffset.IsLengthUnit()) {
  1.5914 +    aResult->mLength = CalcLength(aOffset, aStyleContext,
  1.5915 +                                  aStyleContext->PresContext(),
  1.5916 +                                  aCanStoreInRuleTree);
  1.5917 +    aResult->mPercent = 0.0f;
  1.5918 +    aResult->mHasPercent = false;
  1.5919 +  } else if (aOffset.IsCalcUnit()) {
  1.5920 +    LengthPercentPairCalcOps ops(aStyleContext,
  1.5921 +                                 aStyleContext->PresContext(),
  1.5922 +                                 aCanStoreInRuleTree);
  1.5923 +    nsRuleNode::ComputedCalc vals = ComputeCalc(aOffset, ops);
  1.5924 +    aResult->mLength = vals.mLength;
  1.5925 +    aResult->mPercent = vals.mPercent;
  1.5926 +    aResult->mHasPercent = ops.mHasPercent;
  1.5927 +  } else {
  1.5928 +    aResult->mLength = 0;
  1.5929 +    aResult->mPercent = 0.0f;
  1.5930 +    aResult->mHasPercent = false;
  1.5931 +    NS_ASSERTION(aOffset.GetUnit() == eCSSUnit_Null, "unexpected unit");
  1.5932 +  }
  1.5933 +
  1.5934 +  if (eCSSUnit_Enumerated == aEdge.GetUnit()) {
  1.5935 +    int sign;
  1.5936 +    if (aEdge.GetIntValue() & (NS_STYLE_BG_POSITION_BOTTOM |
  1.5937 +                               NS_STYLE_BG_POSITION_RIGHT)) {
  1.5938 +      sign = -1;
  1.5939 +    } else {
  1.5940 +      sign = 1;
  1.5941 +    }
  1.5942 +    aResult->mPercent = GetFloatFromBoxPosition(aEdge.GetIntValue()) +
  1.5943 +                        sign * aResult->mPercent;
  1.5944 +    aResult->mLength = sign * aResult->mLength;
  1.5945 +    aResult->mHasPercent = true;
  1.5946 +  } else {
  1.5947 +    NS_ASSERTION(eCSSUnit_Null == aEdge.GetUnit(), "unexpected unit");
  1.5948 +  }
  1.5949 +}
  1.5950 +
  1.5951 +template <>
  1.5952 +struct BackgroundItemComputer<nsCSSValueList, nsStyleBackground::Position>
  1.5953 +{
  1.5954 +  static void ComputeValue(nsStyleContext* aStyleContext,
  1.5955 +                           const nsCSSValueList* aSpecifiedValue,
  1.5956 +                           nsStyleBackground::Position& aComputedValue,
  1.5957 +                           bool& aCanStoreInRuleTree)
  1.5958 +  {
  1.5959 +    NS_ASSERTION(aSpecifiedValue->mValue.GetUnit() == eCSSUnit_Array, "bg-position not an array");
  1.5960 +
  1.5961 +    nsRefPtr<nsCSSValue::Array> bgPositionArray =
  1.5962 +                                  aSpecifiedValue->mValue.GetArrayValue();
  1.5963 +    const nsCSSValue &xEdge   = bgPositionArray->Item(0);
  1.5964 +    const nsCSSValue &xOffset = bgPositionArray->Item(1);
  1.5965 +    const nsCSSValue &yEdge   = bgPositionArray->Item(2);
  1.5966 +    const nsCSSValue &yOffset = bgPositionArray->Item(3);
  1.5967 +
  1.5968 +    NS_ASSERTION((eCSSUnit_Enumerated == xEdge.GetUnit()  ||
  1.5969 +                  eCSSUnit_Null       == xEdge.GetUnit()) &&
  1.5970 +                 (eCSSUnit_Enumerated == yEdge.GetUnit()  ||
  1.5971 +                  eCSSUnit_Null       == yEdge.GetUnit()) &&
  1.5972 +                  eCSSUnit_Enumerated != xOffset.GetUnit()  &&
  1.5973 +                  eCSSUnit_Enumerated != yOffset.GetUnit(),
  1.5974 +                  "Invalid background position");
  1.5975 +
  1.5976 +    ComputeBackgroundPositionCoord(aStyleContext, xEdge, xOffset,
  1.5977 +                                   &aComputedValue.mXPosition,
  1.5978 +                                   aCanStoreInRuleTree);
  1.5979 +
  1.5980 +    ComputeBackgroundPositionCoord(aStyleContext, yEdge, yOffset,
  1.5981 +                                   &aComputedValue.mYPosition,
  1.5982 +                                   aCanStoreInRuleTree);
  1.5983 +  }
  1.5984 +};
  1.5985 +
  1.5986 +
  1.5987 +struct BackgroundSizeAxis {
  1.5988 +  nsCSSValue nsCSSValuePairList::* specified;
  1.5989 +  nsStyleBackground::Size::Dimension nsStyleBackground::Size::* result;
  1.5990 +  uint8_t nsStyleBackground::Size::* type;
  1.5991 +};
  1.5992 +
  1.5993 +static const BackgroundSizeAxis gBGSizeAxes[] = {
  1.5994 +  { &nsCSSValuePairList::mXValue,
  1.5995 +    &nsStyleBackground::Size::mWidth,
  1.5996 +    &nsStyleBackground::Size::mWidthType },
  1.5997 +  { &nsCSSValuePairList::mYValue,
  1.5998 +    &nsStyleBackground::Size::mHeight,
  1.5999 +    &nsStyleBackground::Size::mHeightType }
  1.6000 +};
  1.6001 +
  1.6002 +template <>
  1.6003 +struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Size>
  1.6004 +{
  1.6005 +  static void ComputeValue(nsStyleContext* aStyleContext,
  1.6006 +                           const nsCSSValuePairList* aSpecifiedValue,
  1.6007 +                           nsStyleBackground::Size& aComputedValue,
  1.6008 +                           bool& aCanStoreInRuleTree)
  1.6009 +  {
  1.6010 +    nsStyleBackground::Size &size = aComputedValue;
  1.6011 +    for (const BackgroundSizeAxis *axis = gBGSizeAxes,
  1.6012 +                        *axis_end = ArrayEnd(gBGSizeAxes);
  1.6013 +         axis < axis_end; ++axis) {
  1.6014 +      const nsCSSValue &specified = aSpecifiedValue->*(axis->specified);
  1.6015 +      if (eCSSUnit_Auto == specified.GetUnit()) {
  1.6016 +        size.*(axis->type) = nsStyleBackground::Size::eAuto;
  1.6017 +      }
  1.6018 +      else if (eCSSUnit_Enumerated == specified.GetUnit()) {
  1.6019 +        static_assert(nsStyleBackground::Size::eContain ==
  1.6020 +                      NS_STYLE_BG_SIZE_CONTAIN &&
  1.6021 +                      nsStyleBackground::Size::eCover ==
  1.6022 +                      NS_STYLE_BG_SIZE_COVER,
  1.6023 +                      "background size constants out of sync");
  1.6024 +        NS_ABORT_IF_FALSE(specified.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
  1.6025 +                          specified.GetIntValue() == NS_STYLE_BG_SIZE_COVER,
  1.6026 +                          "invalid enumerated value for size coordinate");
  1.6027 +        size.*(axis->type) = specified.GetIntValue();
  1.6028 +      }
  1.6029 +      else if (eCSSUnit_Null == specified.GetUnit()) {
  1.6030 +        NS_ABORT_IF_FALSE(axis == gBGSizeAxes + 1,
  1.6031 +                          "null allowed only as height value, and only "
  1.6032 +                          "for contain/cover/initial/inherit");
  1.6033 +#ifdef DEBUG
  1.6034 +        {
  1.6035 +          const nsCSSValue &widthValue = aSpecifiedValue->mXValue;
  1.6036 +          NS_ABORT_IF_FALSE(widthValue.GetUnit() != eCSSUnit_Inherit &&
  1.6037 +                            widthValue.GetUnit() != eCSSUnit_Initial &&
  1.6038 +                            widthValue.GetUnit() != eCSSUnit_Unset,
  1.6039 +                            "initial/inherit/unset should already have been handled");
  1.6040 +          NS_ABORT_IF_FALSE(widthValue.GetUnit() == eCSSUnit_Enumerated &&
  1.6041 +                            (widthValue.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
  1.6042 +                             widthValue.GetIntValue() == NS_STYLE_BG_SIZE_COVER),
  1.6043 +                            "null height value not corresponding to allowable "
  1.6044 +                            "non-null width value");
  1.6045 +        }
  1.6046 +#endif
  1.6047 +        size.*(axis->type) = size.mWidthType;
  1.6048 +      }
  1.6049 +      else if (eCSSUnit_Percent == specified.GetUnit()) {
  1.6050 +        (size.*(axis->result)).mLength = 0;
  1.6051 +        (size.*(axis->result)).mPercent = specified.GetPercentValue();
  1.6052 +        (size.*(axis->result)).mHasPercent = true;
  1.6053 +        size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
  1.6054 +      }
  1.6055 +      else if (specified.IsLengthUnit()) {
  1.6056 +        (size.*(axis->result)).mLength =
  1.6057 +          CalcLength(specified, aStyleContext, aStyleContext->PresContext(),
  1.6058 +                     aCanStoreInRuleTree);
  1.6059 +        (size.*(axis->result)).mPercent = 0.0f;
  1.6060 +        (size.*(axis->result)).mHasPercent = false;
  1.6061 +        size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
  1.6062 +      } else {
  1.6063 +        NS_ABORT_IF_FALSE(specified.IsCalcUnit(), "unexpected unit");
  1.6064 +        LengthPercentPairCalcOps ops(aStyleContext,
  1.6065 +                                     aStyleContext->PresContext(),
  1.6066 +                                     aCanStoreInRuleTree);
  1.6067 +        nsRuleNode::ComputedCalc vals = ComputeCalc(specified, ops);
  1.6068 +        (size.*(axis->result)).mLength = vals.mLength;
  1.6069 +        (size.*(axis->result)).mPercent = vals.mPercent;
  1.6070 +        (size.*(axis->result)).mHasPercent = ops.mHasPercent;
  1.6071 +        size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
  1.6072 +      }
  1.6073 +    }
  1.6074 +
  1.6075 +    NS_ABORT_IF_FALSE(size.mWidthType < nsStyleBackground::Size::eDimensionType_COUNT,
  1.6076 +                      "bad width type");
  1.6077 +    NS_ABORT_IF_FALSE(size.mHeightType < nsStyleBackground::Size::eDimensionType_COUNT,
  1.6078 +                      "bad height type");
  1.6079 +    NS_ABORT_IF_FALSE((size.mWidthType != nsStyleBackground::Size::eContain &&
  1.6080 +                       size.mWidthType != nsStyleBackground::Size::eCover) ||
  1.6081 +                      size.mWidthType == size.mHeightType,
  1.6082 +                      "contain/cover apply to both dimensions or to neither");
  1.6083 +  }
  1.6084 +};
  1.6085 +
  1.6086 +template <class ComputedValueItem>
  1.6087 +static void
  1.6088 +SetBackgroundList(nsStyleContext* aStyleContext,
  1.6089 +                  const nsCSSValue& aValue,
  1.6090 +                  nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
  1.6091 +                  const nsAutoTArray<nsStyleBackground::Layer, 1> &aParentLayers,
  1.6092 +                  ComputedValueItem nsStyleBackground::Layer::* aResultLocation,
  1.6093 +                  ComputedValueItem aInitialValue,
  1.6094 +                  uint32_t aParentItemCount,
  1.6095 +                  uint32_t& aItemCount,
  1.6096 +                  uint32_t& aMaxItemCount,
  1.6097 +                  bool& aRebuild,
  1.6098 +                  bool& aCanStoreInRuleTree)
  1.6099 +{
  1.6100 +  switch (aValue.GetUnit()) {
  1.6101 +  case eCSSUnit_Null:
  1.6102 +    break;
  1.6103 +
  1.6104 +  case eCSSUnit_Inherit:
  1.6105 +    aRebuild = true;
  1.6106 +    aCanStoreInRuleTree = false;
  1.6107 +    aLayers.EnsureLengthAtLeast(aParentItemCount);
  1.6108 +    aItemCount = aParentItemCount;
  1.6109 +    for (uint32_t i = 0; i < aParentItemCount; ++i) {
  1.6110 +      aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
  1.6111 +    }
  1.6112 +    break;
  1.6113 +
  1.6114 +  case eCSSUnit_Initial:
  1.6115 +  case eCSSUnit_Unset:
  1.6116 +    aRebuild = true;
  1.6117 +    aItemCount = 1;
  1.6118 +    aLayers[0].*aResultLocation = aInitialValue;
  1.6119 +    break;
  1.6120 +
  1.6121 +  case eCSSUnit_List:
  1.6122 +  case eCSSUnit_ListDep: {
  1.6123 +    aRebuild = true;
  1.6124 +    aItemCount = 0;
  1.6125 +    const nsCSSValueList* item = aValue.GetListValue();
  1.6126 +    do {
  1.6127 +      NS_ASSERTION(item->mValue.GetUnit() != eCSSUnit_Null &&
  1.6128 +                   item->mValue.GetUnit() != eCSSUnit_Inherit &&
  1.6129 +                   item->mValue.GetUnit() != eCSSUnit_Initial &&
  1.6130 +                   item->mValue.GetUnit() != eCSSUnit_Unset,
  1.6131 +                   "unexpected unit");
  1.6132 +      ++aItemCount;
  1.6133 +      aLayers.EnsureLengthAtLeast(aItemCount);
  1.6134 +      BackgroundItemComputer<nsCSSValueList, ComputedValueItem>
  1.6135 +        ::ComputeValue(aStyleContext, item,
  1.6136 +                       aLayers[aItemCount-1].*aResultLocation,
  1.6137 +                       aCanStoreInRuleTree);
  1.6138 +      item = item->mNext;
  1.6139 +    } while (item);
  1.6140 +    break;
  1.6141 +  }
  1.6142 +
  1.6143 +  default:
  1.6144 +    NS_ABORT_IF_FALSE(false,
  1.6145 +                      nsPrintfCString("unexpected unit %d",
  1.6146 +                                      aValue.GetUnit()).get());
  1.6147 +  }
  1.6148 +
  1.6149 +  if (aItemCount > aMaxItemCount)
  1.6150 +    aMaxItemCount = aItemCount;
  1.6151 +}
  1.6152 +
  1.6153 +template <class ComputedValueItem>
  1.6154 +static void
  1.6155 +SetBackgroundPairList(nsStyleContext* aStyleContext,
  1.6156 +                      const nsCSSValue& aValue,
  1.6157 +                      nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
  1.6158 +                      const nsAutoTArray<nsStyleBackground::Layer, 1>
  1.6159 +                                                                 &aParentLayers,
  1.6160 +                      ComputedValueItem nsStyleBackground::Layer::*
  1.6161 +                                                                aResultLocation,
  1.6162 +                      ComputedValueItem aInitialValue,
  1.6163 +                      uint32_t aParentItemCount,
  1.6164 +                      uint32_t& aItemCount,
  1.6165 +                      uint32_t& aMaxItemCount,
  1.6166 +                      bool& aRebuild,
  1.6167 +                      bool& aCanStoreInRuleTree)
  1.6168 +{
  1.6169 +  switch (aValue.GetUnit()) {
  1.6170 +  case eCSSUnit_Null:
  1.6171 +    break;
  1.6172 +
  1.6173 +  case eCSSUnit_Inherit:
  1.6174 +    aRebuild = true;
  1.6175 +    aCanStoreInRuleTree = false;
  1.6176 +    aLayers.EnsureLengthAtLeast(aParentItemCount);
  1.6177 +    aItemCount = aParentItemCount;
  1.6178 +    for (uint32_t i = 0; i < aParentItemCount; ++i) {
  1.6179 +      aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
  1.6180 +    }
  1.6181 +    break;
  1.6182 +
  1.6183 +  case eCSSUnit_Initial:
  1.6184 +  case eCSSUnit_Unset:
  1.6185 +    aRebuild = true;
  1.6186 +    aItemCount = 1;
  1.6187 +    aLayers[0].*aResultLocation = aInitialValue;
  1.6188 +    break;
  1.6189 +
  1.6190 +  case eCSSUnit_PairList:
  1.6191 +  case eCSSUnit_PairListDep: {
  1.6192 +    aRebuild = true;
  1.6193 +    aItemCount = 0;
  1.6194 +    const nsCSSValuePairList* item = aValue.GetPairListValue();
  1.6195 +    do {
  1.6196 +      NS_ASSERTION(item->mXValue.GetUnit() != eCSSUnit_Inherit &&
  1.6197 +                   item->mXValue.GetUnit() != eCSSUnit_Initial &&
  1.6198 +                   item->mXValue.GetUnit() != eCSSUnit_Unset &&
  1.6199 +                   item->mYValue.GetUnit() != eCSSUnit_Inherit &&
  1.6200 +                   item->mYValue.GetUnit() != eCSSUnit_Initial &&
  1.6201 +                   item->mYValue.GetUnit() != eCSSUnit_Unset,
  1.6202 +                   "unexpected unit");
  1.6203 +      ++aItemCount;
  1.6204 +      aLayers.EnsureLengthAtLeast(aItemCount);
  1.6205 +      BackgroundItemComputer<nsCSSValuePairList, ComputedValueItem>
  1.6206 +        ::ComputeValue(aStyleContext, item,
  1.6207 +                       aLayers[aItemCount-1].*aResultLocation,
  1.6208 +                       aCanStoreInRuleTree);
  1.6209 +      item = item->mNext;
  1.6210 +    } while (item);
  1.6211 +    break;
  1.6212 +  }
  1.6213 +
  1.6214 +  default:
  1.6215 +    NS_ABORT_IF_FALSE(false,
  1.6216 +                      nsPrintfCString("unexpected unit %d",
  1.6217 +                                      aValue.GetUnit()).get());
  1.6218 +  }
  1.6219 +
  1.6220 +  if (aItemCount > aMaxItemCount)
  1.6221 +    aMaxItemCount = aItemCount;
  1.6222 +}
  1.6223 +
  1.6224 +template <class ComputedValueItem>
  1.6225 +static void
  1.6226 +FillBackgroundList(nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
  1.6227 +    ComputedValueItem nsStyleBackground::Layer::* aResultLocation,
  1.6228 +    uint32_t aItemCount, uint32_t aFillCount)
  1.6229 +{
  1.6230 +  NS_PRECONDITION(aFillCount <= aLayers.Length(), "unexpected array length");
  1.6231 +  for (uint32_t sourceLayer = 0, destLayer = aItemCount;
  1.6232 +       destLayer < aFillCount;
  1.6233 +       ++sourceLayer, ++destLayer) {
  1.6234 +    aLayers[destLayer].*aResultLocation =
  1.6235 +      aLayers[sourceLayer].*aResultLocation;
  1.6236 +  }
  1.6237 +}
  1.6238 +
  1.6239 +const void*
  1.6240 +nsRuleNode::ComputeBackgroundData(void* aStartStruct,
  1.6241 +                                  const nsRuleData* aRuleData,
  1.6242 +                                  nsStyleContext* aContext,
  1.6243 +                                  nsRuleNode* aHighestNode,
  1.6244 +                                  const RuleDetail aRuleDetail,
  1.6245 +                                  const bool aCanStoreInRuleTree)
  1.6246 +{
  1.6247 +  COMPUTE_START_RESET(Background, (), bg, parentBG)
  1.6248 +
  1.6249 +  // background-color: color, string, inherit
  1.6250 +  const nsCSSValue* backColorValue = aRuleData->ValueForBackgroundColor();
  1.6251 +  if (eCSSUnit_Initial == backColorValue->GetUnit() ||
  1.6252 +      eCSSUnit_Unset == backColorValue->GetUnit()) {
  1.6253 +    bg->mBackgroundColor = NS_RGBA(0, 0, 0, 0);
  1.6254 +  } else if (!SetColor(*backColorValue, parentBG->mBackgroundColor,
  1.6255 +                       mPresContext, aContext, bg->mBackgroundColor,
  1.6256 +                       canStoreInRuleTree)) {
  1.6257 +    NS_ASSERTION(eCSSUnit_Null == backColorValue->GetUnit(),
  1.6258 +                 "unexpected color unit");
  1.6259 +  }
  1.6260 +
  1.6261 +  uint32_t maxItemCount = 1;
  1.6262 +  bool rebuild = false;
  1.6263 +
  1.6264 +  // background-image: url (stored as image), none, inherit [list]
  1.6265 +  nsStyleImage initialImage;
  1.6266 +  SetBackgroundList(aContext, *aRuleData->ValueForBackgroundImage(),
  1.6267 +                    bg->mLayers,
  1.6268 +                    parentBG->mLayers, &nsStyleBackground::Layer::mImage,
  1.6269 +                    initialImage, parentBG->mImageCount, bg->mImageCount,
  1.6270 +                    maxItemCount, rebuild, canStoreInRuleTree);
  1.6271 +
  1.6272 +  // background-repeat: enum, inherit, initial [pair list]
  1.6273 +  nsStyleBackground::Repeat initialRepeat;
  1.6274 +  initialRepeat.SetInitialValues();
  1.6275 +  SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundRepeat(),
  1.6276 +                        bg->mLayers,
  1.6277 +                        parentBG->mLayers, &nsStyleBackground::Layer::mRepeat,
  1.6278 +                        initialRepeat, parentBG->mRepeatCount,
  1.6279 +                        bg->mRepeatCount, maxItemCount, rebuild, 
  1.6280 +                        canStoreInRuleTree);
  1.6281 +
  1.6282 +  // background-attachment: enum, inherit, initial [list]
  1.6283 +  SetBackgroundList(aContext, *aRuleData->ValueForBackgroundAttachment(),
  1.6284 +                    bg->mLayers, parentBG->mLayers,
  1.6285 +                    &nsStyleBackground::Layer::mAttachment,
  1.6286 +                    uint8_t(NS_STYLE_BG_ATTACHMENT_SCROLL),
  1.6287 +                    parentBG->mAttachmentCount,
  1.6288 +                    bg->mAttachmentCount, maxItemCount, rebuild,
  1.6289 +                    canStoreInRuleTree);
  1.6290 +
  1.6291 +  // background-clip: enum, inherit, initial [list]
  1.6292 +  SetBackgroundList(aContext, *aRuleData->ValueForBackgroundClip(),
  1.6293 +                    bg->mLayers,
  1.6294 +                    parentBG->mLayers, &nsStyleBackground::Layer::mClip,
  1.6295 +                    uint8_t(NS_STYLE_BG_CLIP_BORDER), parentBG->mClipCount,
  1.6296 +                    bg->mClipCount, maxItemCount, rebuild, canStoreInRuleTree);
  1.6297 +
  1.6298 +  // background-inline-policy: enum, inherit, initial
  1.6299 +  SetDiscrete(*aRuleData->ValueForBackgroundInlinePolicy(),
  1.6300 +              bg->mBackgroundInlinePolicy,
  1.6301 +              canStoreInRuleTree,
  1.6302 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.6303 +              parentBG->mBackgroundInlinePolicy,
  1.6304 +              NS_STYLE_BG_INLINE_POLICY_CONTINUOUS, 0, 0, 0, 0);
  1.6305 +
  1.6306 +  // background-blend-mode: enum, inherit, initial [list]
  1.6307 +  SetBackgroundList(aContext, *aRuleData->ValueForBackgroundBlendMode(),
  1.6308 +                    bg->mLayers,
  1.6309 +                    parentBG->mLayers, &nsStyleBackground::Layer::mBlendMode,
  1.6310 +                    uint8_t(NS_STYLE_BLEND_NORMAL), parentBG->mBlendModeCount,
  1.6311 +                    bg->mBlendModeCount, maxItemCount, rebuild,
  1.6312 +                    canStoreInRuleTree);
  1.6313 +
  1.6314 +  // background-origin: enum, inherit, initial [list]
  1.6315 +  SetBackgroundList(aContext, *aRuleData->ValueForBackgroundOrigin(),
  1.6316 +                    bg->mLayers,
  1.6317 +                    parentBG->mLayers, &nsStyleBackground::Layer::mOrigin,
  1.6318 +                    uint8_t(NS_STYLE_BG_ORIGIN_PADDING), parentBG->mOriginCount,
  1.6319 +                    bg->mOriginCount, maxItemCount, rebuild,
  1.6320 +                    canStoreInRuleTree);
  1.6321 +
  1.6322 +  // background-position: enum, length, percent (flags), inherit [pair list]
  1.6323 +  nsStyleBackground::Position initialPosition;
  1.6324 +  initialPosition.SetInitialValues();
  1.6325 +  SetBackgroundList(aContext, *aRuleData->ValueForBackgroundPosition(),
  1.6326 +                    bg->mLayers,
  1.6327 +                    parentBG->mLayers, &nsStyleBackground::Layer::mPosition,
  1.6328 +                    initialPosition, parentBG->mPositionCount,
  1.6329 +                    bg->mPositionCount, maxItemCount, rebuild,
  1.6330 +                    canStoreInRuleTree);
  1.6331 +
  1.6332 +  // background-size: enum, length, auto, inherit, initial [pair list]
  1.6333 +  nsStyleBackground::Size initialSize;
  1.6334 +  initialSize.SetInitialValues();
  1.6335 +  SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundSize(),
  1.6336 +                        bg->mLayers,
  1.6337 +                        parentBG->mLayers, &nsStyleBackground::Layer::mSize,
  1.6338 +                        initialSize, parentBG->mSizeCount,
  1.6339 +                        bg->mSizeCount, maxItemCount, rebuild,
  1.6340 +                        canStoreInRuleTree);
  1.6341 +
  1.6342 +  if (rebuild) {
  1.6343 +    // Delete any extra items.  We need to keep layers in which any
  1.6344 +    // property was specified.
  1.6345 +    bg->mLayers.TruncateLength(maxItemCount);
  1.6346 +
  1.6347 +    uint32_t fillCount = bg->mImageCount;
  1.6348 +    FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mImage,
  1.6349 +                       bg->mImageCount, fillCount);
  1.6350 +    FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mRepeat,
  1.6351 +                       bg->mRepeatCount, fillCount);
  1.6352 +    FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mAttachment,
  1.6353 +                       bg->mAttachmentCount, fillCount);
  1.6354 +    FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mClip,
  1.6355 +                       bg->mClipCount, fillCount);
  1.6356 +    FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mBlendMode,
  1.6357 +                       bg->mBlendModeCount, fillCount);
  1.6358 +    FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mOrigin,
  1.6359 +                       bg->mOriginCount, fillCount);
  1.6360 +    FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mPosition,
  1.6361 +                       bg->mPositionCount, fillCount);
  1.6362 +    FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mSize,
  1.6363 +                       bg->mSizeCount, fillCount);
  1.6364 +  }
  1.6365 +
  1.6366 +  // Now that the dust has settled, register the images with the document
  1.6367 +  for (uint32_t i = 0; i < bg->mImageCount; ++i)
  1.6368 +    bg->mLayers[i].TrackImages(aContext->PresContext());
  1.6369 +
  1.6370 +  COMPUTE_END_RESET(Background, bg)
  1.6371 +}
  1.6372 +
  1.6373 +const void*
  1.6374 +nsRuleNode::ComputeMarginData(void* aStartStruct,
  1.6375 +                              const nsRuleData* aRuleData,
  1.6376 +                              nsStyleContext* aContext,
  1.6377 +                              nsRuleNode* aHighestNode,
  1.6378 +                              const RuleDetail aRuleDetail,
  1.6379 +                              const bool aCanStoreInRuleTree)
  1.6380 +{
  1.6381 +  COMPUTE_START_RESET(Margin, (), margin, parentMargin)
  1.6382 +
  1.6383 +  // margin: length, percent, auto, inherit
  1.6384 +  nsStyleCoord  coord;
  1.6385 +  nsCSSRect ourMargin;
  1.6386 +  ourMargin.mTop = *aRuleData->ValueForMarginTop();
  1.6387 +  ourMargin.mRight = *aRuleData->ValueForMarginRightValue();
  1.6388 +  ourMargin.mBottom = *aRuleData->ValueForMarginBottom();
  1.6389 +  ourMargin.mLeft = *aRuleData->ValueForMarginLeftValue();
  1.6390 +  AdjustLogicalBoxProp(aContext,
  1.6391 +                       *aRuleData->ValueForMarginLeftLTRSource(),
  1.6392 +                       *aRuleData->ValueForMarginLeftRTLSource(),
  1.6393 +                       *aRuleData->ValueForMarginStartValue(),
  1.6394 +                       *aRuleData->ValueForMarginEndValue(),
  1.6395 +                       NS_SIDE_LEFT, ourMargin, canStoreInRuleTree);
  1.6396 +  AdjustLogicalBoxProp(aContext,
  1.6397 +                       *aRuleData->ValueForMarginRightLTRSource(),
  1.6398 +                       *aRuleData->ValueForMarginRightRTLSource(),
  1.6399 +                       *aRuleData->ValueForMarginEndValue(),
  1.6400 +                       *aRuleData->ValueForMarginStartValue(),
  1.6401 +                       NS_SIDE_RIGHT, ourMargin, canStoreInRuleTree);
  1.6402 +  NS_FOR_CSS_SIDES(side) {
  1.6403 +    nsStyleCoord parentCoord = parentMargin->mMargin.Get(side);
  1.6404 +    if (SetCoord(ourMargin.*(nsCSSRect::sides[side]),
  1.6405 +                 coord, parentCoord,
  1.6406 +                 SETCOORD_LPAH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  1.6407 +                   SETCOORD_UNSET_INITIAL,
  1.6408 +                 aContext, mPresContext, canStoreInRuleTree)) {
  1.6409 +      margin->mMargin.Set(side, coord);
  1.6410 +    }
  1.6411 +  }
  1.6412 +
  1.6413 +  margin->RecalcData();
  1.6414 +  COMPUTE_END_RESET(Margin, margin)
  1.6415 +}
  1.6416 +
  1.6417 +static void
  1.6418 +SetBorderImageRect(const nsCSSValue& aValue,
  1.6419 +                   /** outparam */ nsCSSRect& aRect)
  1.6420 +{
  1.6421 +  switch (aValue.GetUnit()) {
  1.6422 +  case eCSSUnit_Null:
  1.6423 +    aRect.Reset();
  1.6424 +    break;
  1.6425 +  case eCSSUnit_Rect:
  1.6426 +    aRect = aValue.GetRectValue();
  1.6427 +    break;
  1.6428 +  case eCSSUnit_Inherit:
  1.6429 +  case eCSSUnit_Initial:
  1.6430 +  case eCSSUnit_Unset:
  1.6431 +    aRect.SetAllSidesTo(aValue);
  1.6432 +    break;
  1.6433 +  default:
  1.6434 +    NS_ASSERTION(false, "Unexpected border image value for rect.");
  1.6435 +  }
  1.6436 +}
  1.6437 +
  1.6438 +static void
  1.6439 +SetBorderImagePair(const nsCSSValue& aValue,
  1.6440 +                   /** outparam */ nsCSSValuePair& aPair)
  1.6441 +{
  1.6442 +  switch (aValue.GetUnit()) {
  1.6443 +  case eCSSUnit_Null:
  1.6444 +    aPair.Reset();
  1.6445 +    break;
  1.6446 +  case eCSSUnit_Pair:
  1.6447 +    aPair = aValue.GetPairValue();
  1.6448 +    break;
  1.6449 +  case eCSSUnit_Inherit:
  1.6450 +  case eCSSUnit_Initial:
  1.6451 +  case eCSSUnit_Unset:
  1.6452 +    aPair.SetBothValuesTo(aValue);
  1.6453 +    break;
  1.6454 +  default:
  1.6455 +    NS_ASSERTION(false, "Unexpected border image value for pair.");
  1.6456 +  }
  1.6457 +}
  1.6458 +
  1.6459 +static void
  1.6460 +SetBorderImageSlice(const nsCSSValue& aValue,
  1.6461 +                    /** outparam */ nsCSSValue& aSlice,
  1.6462 +                    /** outparam */ nsCSSValue& aFill)
  1.6463 +{
  1.6464 +  const nsCSSValueList* valueList;
  1.6465 +  switch (aValue.GetUnit()) {
  1.6466 +  case eCSSUnit_Null:
  1.6467 +    aSlice.Reset();
  1.6468 +    aFill.Reset();
  1.6469 +    break;
  1.6470 +  case eCSSUnit_List:
  1.6471 +    // Get slice dimensions.
  1.6472 +    valueList = aValue.GetListValue();
  1.6473 +    aSlice = valueList->mValue;
  1.6474 +
  1.6475 +    // Get "fill" keyword.
  1.6476 +    valueList = valueList->mNext;
  1.6477 +    if (valueList) {
  1.6478 +      aFill = valueList->mValue;
  1.6479 +    } else {
  1.6480 +      aFill.SetInitialValue();
  1.6481 +    }
  1.6482 +    break;
  1.6483 +  case eCSSUnit_Inherit:
  1.6484 +  case eCSSUnit_Initial:
  1.6485 +  case eCSSUnit_Unset:
  1.6486 +    aSlice = aValue;
  1.6487 +    aFill = aValue;
  1.6488 +    break;
  1.6489 +  default:
  1.6490 +    NS_ASSERTION(false, "Unexpected border image value for pair.");
  1.6491 +  }
  1.6492 +}
  1.6493 +
  1.6494 +const void*
  1.6495 +nsRuleNode::ComputeBorderData(void* aStartStruct,
  1.6496 +                              const nsRuleData* aRuleData,
  1.6497 +                              nsStyleContext* aContext,
  1.6498 +                              nsRuleNode* aHighestNode,
  1.6499 +                              const RuleDetail aRuleDetail,
  1.6500 +                              const bool aCanStoreInRuleTree)
  1.6501 +{
  1.6502 +  COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder)
  1.6503 +
  1.6504 +  // box-shadow: none, list, inherit, initial
  1.6505 +  const nsCSSValue* boxShadowValue = aRuleData->ValueForBoxShadow();
  1.6506 +  switch (boxShadowValue->GetUnit()) {
  1.6507 +  case eCSSUnit_Null:
  1.6508 +    break;
  1.6509 +
  1.6510 +  case eCSSUnit_Initial:
  1.6511 +  case eCSSUnit_Unset:
  1.6512 +  case eCSSUnit_None:
  1.6513 +    border->mBoxShadow = nullptr;
  1.6514 +    break;
  1.6515 +
  1.6516 +  case eCSSUnit_Inherit:
  1.6517 +    border->mBoxShadow = parentBorder->mBoxShadow;
  1.6518 +    canStoreInRuleTree = false;
  1.6519 +    break;
  1.6520 +
  1.6521 +  case eCSSUnit_List:
  1.6522 +  case eCSSUnit_ListDep:
  1.6523 +    border->mBoxShadow = GetShadowData(boxShadowValue->GetListValue(),
  1.6524 +                                       aContext, true, canStoreInRuleTree);
  1.6525 +    break;
  1.6526 +
  1.6527 +  default:
  1.6528 +    NS_ABORT_IF_FALSE(false,
  1.6529 +                      nsPrintfCString("unrecognized shadow unit %d",
  1.6530 +                                      boxShadowValue->GetUnit()).get());
  1.6531 +  }
  1.6532 +
  1.6533 +  // border-width, border-*-width: length, enum, inherit
  1.6534 +  nsStyleCoord  coord;
  1.6535 +  nsCSSRect ourBorderWidth;
  1.6536 +  ourBorderWidth.mTop = *aRuleData->ValueForBorderTopWidth();
  1.6537 +  ourBorderWidth.mRight = *aRuleData->ValueForBorderRightWidthValue();
  1.6538 +  ourBorderWidth.mBottom = *aRuleData->ValueForBorderBottomWidth();
  1.6539 +  ourBorderWidth.mLeft = *aRuleData->ValueForBorderLeftWidthValue();
  1.6540 +  AdjustLogicalBoxProp(aContext,
  1.6541 +                       *aRuleData->ValueForBorderLeftWidthLTRSource(),
  1.6542 +                       *aRuleData->ValueForBorderLeftWidthRTLSource(),
  1.6543 +                       *aRuleData->ValueForBorderStartWidthValue(),
  1.6544 +                       *aRuleData->ValueForBorderEndWidthValue(),
  1.6545 +                       NS_SIDE_LEFT, ourBorderWidth, canStoreInRuleTree);
  1.6546 +  AdjustLogicalBoxProp(aContext,
  1.6547 +                       *aRuleData->ValueForBorderRightWidthLTRSource(),
  1.6548 +                       *aRuleData->ValueForBorderRightWidthRTLSource(),
  1.6549 +                       *aRuleData->ValueForBorderEndWidthValue(),
  1.6550 +                       *aRuleData->ValueForBorderStartWidthValue(),
  1.6551 +                       NS_SIDE_RIGHT, ourBorderWidth, canStoreInRuleTree);
  1.6552 +  { // scope for compilers with broken |for| loop scoping
  1.6553 +    NS_FOR_CSS_SIDES(side) {
  1.6554 +      const nsCSSValue &value = ourBorderWidth.*(nsCSSRect::sides[side]);
  1.6555 +      NS_ASSERTION(eCSSUnit_Percent != value.GetUnit(),
  1.6556 +                   "Percentage borders not implemented yet "
  1.6557 +                   "If implementing, make sure to fix all consumers of "
  1.6558 +                   "nsStyleBorder, the IsPercentageAwareChild method, "
  1.6559 +                   "the nsAbsoluteContainingBlock::FrameDependsOnContainer "
  1.6560 +                   "method, the "
  1.6561 +                   "nsLineLayout::IsPercentageAwareReplacedElement method "
  1.6562 +                   "and probably some other places");
  1.6563 +      if (eCSSUnit_Enumerated == value.GetUnit()) {
  1.6564 +        NS_ASSERTION(value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
  1.6565 +                     value.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
  1.6566 +                     value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
  1.6567 +                     "Unexpected enum value");
  1.6568 +        border->SetBorderWidth(side,
  1.6569 +                               (mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
  1.6570 +      }
  1.6571 +      // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
  1.6572 +      else if (SetCoord(value, coord, nsStyleCoord(),
  1.6573 +                        SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
  1.6574 +                        aContext, mPresContext, canStoreInRuleTree)) {
  1.6575 +        NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
  1.6576 +        // clamp negative calc() to 0.
  1.6577 +        border->SetBorderWidth(side, std::max(coord.GetCoordValue(), 0));
  1.6578 +      }
  1.6579 +      else if (eCSSUnit_Inherit == value.GetUnit()) {
  1.6580 +        canStoreInRuleTree = false;
  1.6581 +        border->SetBorderWidth(side,
  1.6582 +                               parentBorder->GetComputedBorder().Side(side));
  1.6583 +      }
  1.6584 +      else if (eCSSUnit_Initial == value.GetUnit() ||
  1.6585 +               eCSSUnit_Unset == value.GetUnit()) {
  1.6586 +        border->SetBorderWidth(side,
  1.6587 +          (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
  1.6588 +      }
  1.6589 +      else {
  1.6590 +        NS_ASSERTION(eCSSUnit_Null == value.GetUnit(),
  1.6591 +                     "missing case handling border width");
  1.6592 +      }
  1.6593 +    }
  1.6594 +  }
  1.6595 +
  1.6596 +  // border-style, border-*-style: enum, inherit
  1.6597 +  nsCSSRect ourBorderStyle;
  1.6598 +  ourBorderStyle.mTop = *aRuleData->ValueForBorderTopStyle();
  1.6599 +  ourBorderStyle.mRight = *aRuleData->ValueForBorderRightStyleValue();
  1.6600 +  ourBorderStyle.mBottom = *aRuleData->ValueForBorderBottomStyle();
  1.6601 +  ourBorderStyle.mLeft = *aRuleData->ValueForBorderLeftStyleValue();
  1.6602 +  AdjustLogicalBoxProp(aContext,
  1.6603 +                       *aRuleData->ValueForBorderLeftStyleLTRSource(),
  1.6604 +                       *aRuleData->ValueForBorderLeftStyleRTLSource(),
  1.6605 +                       *aRuleData->ValueForBorderStartStyleValue(),
  1.6606 +                       *aRuleData->ValueForBorderEndStyleValue(),
  1.6607 +                       NS_SIDE_LEFT, ourBorderStyle, canStoreInRuleTree);
  1.6608 +  AdjustLogicalBoxProp(aContext,
  1.6609 +                       *aRuleData->ValueForBorderRightStyleLTRSource(),
  1.6610 +                       *aRuleData->ValueForBorderRightStyleRTLSource(),
  1.6611 +                       *aRuleData->ValueForBorderEndStyleValue(),
  1.6612 +                       *aRuleData->ValueForBorderStartStyleValue(),
  1.6613 +                       NS_SIDE_RIGHT, ourBorderStyle, canStoreInRuleTree);
  1.6614 +  { // scope for compilers with broken |for| loop scoping
  1.6615 +    NS_FOR_CSS_SIDES(side) {
  1.6616 +      const nsCSSValue &value = ourBorderStyle.*(nsCSSRect::sides[side]);
  1.6617 +      nsCSSUnit unit = value.GetUnit();
  1.6618 +      NS_ABORT_IF_FALSE(eCSSUnit_None != unit,
  1.6619 +                        "'none' should be handled as enumerated value");
  1.6620 +      if (eCSSUnit_Enumerated == unit) {
  1.6621 +        border->SetBorderStyle(side, value.GetIntValue());
  1.6622 +      }
  1.6623 +      else if (eCSSUnit_Initial == unit ||
  1.6624 +               eCSSUnit_Unset == unit) {
  1.6625 +        border->SetBorderStyle(side, NS_STYLE_BORDER_STYLE_NONE);
  1.6626 +      }
  1.6627 +      else if (eCSSUnit_Inherit == unit) {
  1.6628 +        canStoreInRuleTree = false;
  1.6629 +        border->SetBorderStyle(side, parentBorder->GetBorderStyle(side));
  1.6630 +      }
  1.6631 +    }
  1.6632 +  }
  1.6633 +
  1.6634 +  // -moz-border-*-colors: color, string, enum, none, inherit/initial
  1.6635 +  nscolor borderColor;
  1.6636 +  nscolor unused = NS_RGB(0,0,0);
  1.6637 +
  1.6638 +  static const nsCSSProperty borderColorsProps[] = {
  1.6639 +    eCSSProperty_border_top_colors,
  1.6640 +    eCSSProperty_border_right_colors,
  1.6641 +    eCSSProperty_border_bottom_colors,
  1.6642 +    eCSSProperty_border_left_colors
  1.6643 +  };
  1.6644 +
  1.6645 +  NS_FOR_CSS_SIDES(side) {
  1.6646 +    const nsCSSValue& value = *aRuleData->ValueFor(borderColorsProps[side]);
  1.6647 +    switch (value.GetUnit()) {
  1.6648 +    case eCSSUnit_Null:
  1.6649 +      break;
  1.6650 +
  1.6651 +    case eCSSUnit_Initial:
  1.6652 +    case eCSSUnit_Unset:
  1.6653 +    case eCSSUnit_None:
  1.6654 +      border->ClearBorderColors(side);
  1.6655 +      break;
  1.6656 +
  1.6657 +    case eCSSUnit_Inherit: {
  1.6658 +      canStoreInRuleTree = false;
  1.6659 +      border->ClearBorderColors(side);
  1.6660 +      if (parentContext) {
  1.6661 +        nsBorderColors *parentColors;
  1.6662 +        parentBorder->GetCompositeColors(side, &parentColors);
  1.6663 +        if (parentColors) {
  1.6664 +          border->EnsureBorderColors();
  1.6665 +          border->mBorderColors[side] = parentColors->Clone();
  1.6666 +        }
  1.6667 +      }
  1.6668 +      break;
  1.6669 +    }
  1.6670 +
  1.6671 +    case eCSSUnit_List:
  1.6672 +    case eCSSUnit_ListDep: {
  1.6673 +      // Some composite border color information has been specified for this
  1.6674 +      // border side.
  1.6675 +      border->EnsureBorderColors();
  1.6676 +      border->ClearBorderColors(side);
  1.6677 +      const nsCSSValueList* list = value.GetListValue();
  1.6678 +      while (list) {
  1.6679 +        if (SetColor(list->mValue, unused, mPresContext,
  1.6680 +                     aContext, borderColor, canStoreInRuleTree))
  1.6681 +          border->AppendBorderColor(side, borderColor);
  1.6682 +        else {
  1.6683 +          NS_NOTREACHED("unexpected item in -moz-border-*-colors list");
  1.6684 +        }
  1.6685 +        list = list->mNext;
  1.6686 +      }
  1.6687 +      break;
  1.6688 +    }
  1.6689 +
  1.6690 +    default:
  1.6691 +      NS_ABORT_IF_FALSE(false, "unrecognized border color unit");
  1.6692 +    }
  1.6693 +  }
  1.6694 +
  1.6695 +  // border-color, border-*-color: color, string, enum, inherit
  1.6696 +  bool foreground;
  1.6697 +  nsCSSRect ourBorderColor;
  1.6698 +  ourBorderColor.mTop = *aRuleData->ValueForBorderTopColor();
  1.6699 +  ourBorderColor.mRight = *aRuleData->ValueForBorderRightColorValue();
  1.6700 +  ourBorderColor.mBottom = *aRuleData->ValueForBorderBottomColor();
  1.6701 +  ourBorderColor.mLeft = *aRuleData->ValueForBorderLeftColorValue();
  1.6702 +  AdjustLogicalBoxProp(aContext,
  1.6703 +                       *aRuleData->ValueForBorderLeftColorLTRSource(),
  1.6704 +                       *aRuleData->ValueForBorderLeftColorRTLSource(),
  1.6705 +                       *aRuleData->ValueForBorderStartColorValue(),
  1.6706 +                       *aRuleData->ValueForBorderEndColorValue(),
  1.6707 +                       NS_SIDE_LEFT, ourBorderColor, canStoreInRuleTree);
  1.6708 +  AdjustLogicalBoxProp(aContext,
  1.6709 +                       *aRuleData->ValueForBorderRightColorLTRSource(),
  1.6710 +                       *aRuleData->ValueForBorderRightColorRTLSource(),
  1.6711 +                       *aRuleData->ValueForBorderEndColorValue(),
  1.6712 +                       *aRuleData->ValueForBorderStartColorValue(),
  1.6713 +                       NS_SIDE_RIGHT, ourBorderColor, canStoreInRuleTree);
  1.6714 +  { // scope for compilers with broken |for| loop scoping
  1.6715 +    NS_FOR_CSS_SIDES(side) {
  1.6716 +      const nsCSSValue &value = ourBorderColor.*(nsCSSRect::sides[side]);
  1.6717 +      if (eCSSUnit_Inherit == value.GetUnit()) {
  1.6718 +        canStoreInRuleTree = false;
  1.6719 +        if (parentContext) {
  1.6720 +          parentBorder->GetBorderColor(side, borderColor, foreground);
  1.6721 +          if (foreground) {
  1.6722 +            // We want to inherit the color from the parent, not use the
  1.6723 +            // color on the element where this chunk of style data will be
  1.6724 +            // used.  We can ensure that the data for the parent are fully
  1.6725 +            // computed (unlike for the element where this will be used, for
  1.6726 +            // which the color could be specified on a more specific rule).
  1.6727 +            border->SetBorderColor(side, parentContext->StyleColor()->mColor);
  1.6728 +          } else
  1.6729 +            border->SetBorderColor(side, borderColor);
  1.6730 +        } else {
  1.6731 +          // We're the root
  1.6732 +          border->SetBorderToForeground(side);
  1.6733 +        }
  1.6734 +      }
  1.6735 +      else if (SetColor(value, unused, mPresContext, aContext, borderColor,
  1.6736 +                        canStoreInRuleTree)) {
  1.6737 +        border->SetBorderColor(side, borderColor);
  1.6738 +      }
  1.6739 +      else if (eCSSUnit_Enumerated == value.GetUnit()) {
  1.6740 +        switch (value.GetIntValue()) {
  1.6741 +          case NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR:
  1.6742 +            border->SetBorderToForeground(side);
  1.6743 +            break;
  1.6744 +          default:
  1.6745 +            NS_NOTREACHED("Unexpected enumerated color");
  1.6746 +            break;
  1.6747 +        }
  1.6748 +      }
  1.6749 +      else if (eCSSUnit_Initial == value.GetUnit() ||
  1.6750 +               eCSSUnit_Unset == value.GetUnit()) {
  1.6751 +        border->SetBorderToForeground(side);
  1.6752 +      }
  1.6753 +    }
  1.6754 +  }
  1.6755 +
  1.6756 +  // border-radius: length, percent, inherit
  1.6757 +  {
  1.6758 +    const nsCSSProperty* subprops =
  1.6759 +      nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius);
  1.6760 +    NS_FOR_CSS_FULL_CORNERS(corner) {
  1.6761 +      int cx = NS_FULL_TO_HALF_CORNER(corner, false);
  1.6762 +      int cy = NS_FULL_TO_HALF_CORNER(corner, true);
  1.6763 +      const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
  1.6764 +      nsStyleCoord parentX = parentBorder->mBorderRadius.Get(cx);
  1.6765 +      nsStyleCoord parentY = parentBorder->mBorderRadius.Get(cy);
  1.6766 +      nsStyleCoord coordX, coordY;
  1.6767 +
  1.6768 +      if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
  1.6769 +                        SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
  1.6770 +                          SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
  1.6771 +                        aContext, mPresContext, canStoreInRuleTree)) {
  1.6772 +        border->mBorderRadius.Set(cx, coordX);
  1.6773 +        border->mBorderRadius.Set(cy, coordY);
  1.6774 +      }
  1.6775 +    }
  1.6776 +  }
  1.6777 +
  1.6778 +  // float-edge: enum, inherit, initial
  1.6779 +  SetDiscrete(*aRuleData->ValueForFloatEdge(),
  1.6780 +              border->mFloatEdge, canStoreInRuleTree,
  1.6781 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.6782 +              parentBorder->mFloatEdge,
  1.6783 +              NS_STYLE_FLOAT_EDGE_CONTENT, 0, 0, 0, 0);
  1.6784 +
  1.6785 +  // border-image-source
  1.6786 +  const nsCSSValue* borderImageSource = aRuleData->ValueForBorderImageSource();
  1.6787 +  if (borderImageSource->GetUnit() == eCSSUnit_Inherit) {
  1.6788 +    canStoreInRuleTree = false;
  1.6789 +    border->mBorderImageSource = parentBorder->mBorderImageSource;
  1.6790 +  } else {
  1.6791 +    SetStyleImage(aContext,
  1.6792 +                  *borderImageSource,
  1.6793 +                  border->mBorderImageSource,
  1.6794 +                  canStoreInRuleTree);
  1.6795 +  }
  1.6796 +
  1.6797 +  nsCSSValue borderImageSliceValue;
  1.6798 +  nsCSSValue borderImageSliceFill;
  1.6799 +  SetBorderImageSlice(*aRuleData->ValueForBorderImageSlice(),
  1.6800 +                      borderImageSliceValue, borderImageSliceFill);
  1.6801 +
  1.6802 +  // border-image-slice: fill
  1.6803 +  SetDiscrete(borderImageSliceFill,
  1.6804 +              border->mBorderImageFill,
  1.6805 +              canStoreInRuleTree,
  1.6806 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.6807 +              parentBorder->mBorderImageFill,
  1.6808 +              NS_STYLE_BORDER_IMAGE_SLICE_NOFILL, 0, 0, 0, 0);
  1.6809 +
  1.6810 +  nsCSSRect borderImageSlice;
  1.6811 +  SetBorderImageRect(borderImageSliceValue, borderImageSlice);
  1.6812 +
  1.6813 +  nsCSSRect borderImageWidth;
  1.6814 +  SetBorderImageRect(*aRuleData->ValueForBorderImageWidth(),
  1.6815 +                     borderImageWidth);
  1.6816 +
  1.6817 +  nsCSSRect borderImageOutset;
  1.6818 +  SetBorderImageRect(*aRuleData->ValueForBorderImageOutset(),
  1.6819 +                     borderImageOutset);
  1.6820 +
  1.6821 +  NS_FOR_CSS_SIDES (side) {
  1.6822 +    // border-image-slice
  1.6823 +    if (SetCoord(borderImageSlice.*(nsCSSRect::sides[side]), coord,
  1.6824 +                 parentBorder->mBorderImageSlice.Get(side),
  1.6825 +                 SETCOORD_FACTOR | SETCOORD_PERCENT |
  1.6826 +                   SETCOORD_INHERIT | SETCOORD_INITIAL_HUNDRED_PCT |
  1.6827 +                   SETCOORD_UNSET_INITIAL,
  1.6828 +                 aContext, mPresContext, canStoreInRuleTree)) {
  1.6829 +      border->mBorderImageSlice.Set(side, coord);
  1.6830 +    }
  1.6831 +
  1.6832 +    // border-image-width
  1.6833 +    // 'auto' here means "same as slice"
  1.6834 +    if (SetCoord(borderImageWidth.*(nsCSSRect::sides[side]), coord,
  1.6835 +                 parentBorder->mBorderImageWidth.Get(side),
  1.6836 +                 SETCOORD_LPAH | SETCOORD_FACTOR | SETCOORD_INITIAL_FACTOR_ONE |
  1.6837 +                   SETCOORD_UNSET_INITIAL,
  1.6838 +                 aContext, mPresContext, canStoreInRuleTree)) {
  1.6839 +      border->mBorderImageWidth.Set(side, coord);
  1.6840 +    }
  1.6841 +
  1.6842 +    // border-image-outset
  1.6843 +    if (SetCoord(borderImageOutset.*(nsCSSRect::sides[side]), coord,
  1.6844 +                 parentBorder->mBorderImageOutset.Get(side),
  1.6845 +                 SETCOORD_LENGTH | SETCOORD_FACTOR |
  1.6846 +                   SETCOORD_INHERIT | SETCOORD_INITIAL_FACTOR_ZERO |
  1.6847 +                   SETCOORD_UNSET_INITIAL,
  1.6848 +                 aContext, mPresContext, canStoreInRuleTree)) {
  1.6849 +      border->mBorderImageOutset.Set(side, coord);
  1.6850 +    }
  1.6851 +  }
  1.6852 +
  1.6853 +  // border-image-repeat
  1.6854 +  nsCSSValuePair borderImageRepeat;
  1.6855 +  SetBorderImagePair(*aRuleData->ValueForBorderImageRepeat(),
  1.6856 +                     borderImageRepeat);
  1.6857 +
  1.6858 +  SetDiscrete(borderImageRepeat.mXValue,
  1.6859 +              border->mBorderImageRepeatH,
  1.6860 +              canStoreInRuleTree,
  1.6861 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.6862 +              parentBorder->mBorderImageRepeatH,
  1.6863 +              NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
  1.6864 +
  1.6865 +  SetDiscrete(borderImageRepeat.mYValue,
  1.6866 +              border->mBorderImageRepeatV,
  1.6867 +              canStoreInRuleTree,
  1.6868 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.6869 +              parentBorder->mBorderImageRepeatV,
  1.6870 +              NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
  1.6871 +
  1.6872 +  border->TrackImage(aContext->PresContext());
  1.6873 +
  1.6874 +  COMPUTE_END_RESET(Border, border)
  1.6875 +}
  1.6876 +
  1.6877 +const void*
  1.6878 +nsRuleNode::ComputePaddingData(void* aStartStruct,
  1.6879 +                               const nsRuleData* aRuleData,
  1.6880 +                               nsStyleContext* aContext,
  1.6881 +                               nsRuleNode* aHighestNode,
  1.6882 +                               const RuleDetail aRuleDetail,
  1.6883 +                               const bool aCanStoreInRuleTree)
  1.6884 +{
  1.6885 +  COMPUTE_START_RESET(Padding, (), padding, parentPadding)
  1.6886 +
  1.6887 +  // padding: length, percent, inherit
  1.6888 +  nsStyleCoord  coord;
  1.6889 +  nsCSSRect ourPadding;
  1.6890 +  ourPadding.mTop = *aRuleData->ValueForPaddingTop();
  1.6891 +  ourPadding.mRight = *aRuleData->ValueForPaddingRightValue();
  1.6892 +  ourPadding.mBottom = *aRuleData->ValueForPaddingBottom();
  1.6893 +  ourPadding.mLeft = *aRuleData->ValueForPaddingLeftValue();
  1.6894 +  AdjustLogicalBoxProp(aContext,
  1.6895 +                       *aRuleData->ValueForPaddingLeftLTRSource(),
  1.6896 +                       *aRuleData->ValueForPaddingLeftRTLSource(),
  1.6897 +                       *aRuleData->ValueForPaddingStartValue(),
  1.6898 +                       *aRuleData->ValueForPaddingEndValue(),
  1.6899 +                       NS_SIDE_LEFT, ourPadding, canStoreInRuleTree);
  1.6900 +  AdjustLogicalBoxProp(aContext,
  1.6901 +                       *aRuleData->ValueForPaddingRightLTRSource(),
  1.6902 +                       *aRuleData->ValueForPaddingRightRTLSource(),
  1.6903 +                       *aRuleData->ValueForPaddingEndValue(),
  1.6904 +                       *aRuleData->ValueForPaddingStartValue(),
  1.6905 +                       NS_SIDE_RIGHT, ourPadding, canStoreInRuleTree);
  1.6906 +  NS_FOR_CSS_SIDES(side) {
  1.6907 +    nsStyleCoord parentCoord = parentPadding->mPadding.Get(side);
  1.6908 +    if (SetCoord(ourPadding.*(nsCSSRect::sides[side]),
  1.6909 +                 coord, parentCoord,
  1.6910 +                 SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  1.6911 +                   SETCOORD_UNSET_INITIAL,
  1.6912 +                 aContext, mPresContext, canStoreInRuleTree)) {
  1.6913 +      padding->mPadding.Set(side, coord);
  1.6914 +    }
  1.6915 +  }
  1.6916 +
  1.6917 +  padding->RecalcData();
  1.6918 +  COMPUTE_END_RESET(Padding, padding)
  1.6919 +}
  1.6920 +
  1.6921 +const void*
  1.6922 +nsRuleNode::ComputeOutlineData(void* aStartStruct,
  1.6923 +                               const nsRuleData* aRuleData,
  1.6924 +                               nsStyleContext* aContext,
  1.6925 +                               nsRuleNode* aHighestNode,
  1.6926 +                               const RuleDetail aRuleDetail,
  1.6927 +                               const bool aCanStoreInRuleTree)
  1.6928 +{
  1.6929 +  COMPUTE_START_RESET(Outline, (mPresContext), outline, parentOutline)
  1.6930 +
  1.6931 +  // outline-width: length, enum, inherit
  1.6932 +  const nsCSSValue* outlineWidthValue = aRuleData->ValueForOutlineWidth();
  1.6933 +  if (eCSSUnit_Initial == outlineWidthValue->GetUnit() ||
  1.6934 +      eCSSUnit_Unset == outlineWidthValue->GetUnit()) {
  1.6935 +    outline->mOutlineWidth =
  1.6936 +      nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
  1.6937 +  }
  1.6938 +  else {
  1.6939 +    SetCoord(*outlineWidthValue, outline->mOutlineWidth,
  1.6940 +             parentOutline->mOutlineWidth,
  1.6941 +             SETCOORD_LEH | SETCOORD_CALC_LENGTH_ONLY, aContext,
  1.6942 +             mPresContext, canStoreInRuleTree);
  1.6943 +  }
  1.6944 +
  1.6945 +  // outline-offset: length, inherit
  1.6946 +  nsStyleCoord tempCoord;
  1.6947 +  const nsCSSValue* outlineOffsetValue = aRuleData->ValueForOutlineOffset();
  1.6948 +  if (SetCoord(*outlineOffsetValue, tempCoord,
  1.6949 +               nsStyleCoord(parentOutline->mOutlineOffset,
  1.6950 +                            nsStyleCoord::CoordConstructor),
  1.6951 +               SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
  1.6952 +                 SETCOORD_UNSET_INITIAL,
  1.6953 +               aContext, mPresContext, canStoreInRuleTree)) {
  1.6954 +    outline->mOutlineOffset = tempCoord.GetCoordValue();
  1.6955 +  } else {
  1.6956 +    NS_ASSERTION(outlineOffsetValue->GetUnit() == eCSSUnit_Null,
  1.6957 +                 "unexpected unit");
  1.6958 +  }
  1.6959 +
  1.6960 +  // outline-color: color, string, enum, inherit
  1.6961 +  nscolor outlineColor;
  1.6962 +  nscolor unused = NS_RGB(0,0,0);
  1.6963 +  const nsCSSValue* outlineColorValue = aRuleData->ValueForOutlineColor();
  1.6964 +  if (eCSSUnit_Inherit == outlineColorValue->GetUnit()) {
  1.6965 +    canStoreInRuleTree = false;
  1.6966 +    if (parentContext) {
  1.6967 +      if (parentOutline->GetOutlineColor(outlineColor))
  1.6968 +        outline->SetOutlineColor(outlineColor);
  1.6969 +      else {
  1.6970 +        // We want to inherit the color from the parent, not use the
  1.6971 +        // color on the element where this chunk of style data will be
  1.6972 +        // used.  We can ensure that the data for the parent are fully
  1.6973 +        // computed (unlike for the element where this will be used, for
  1.6974 +        // which the color could be specified on a more specific rule).
  1.6975 +        outline->SetOutlineColor(parentContext->StyleColor()->mColor);
  1.6976 +      }
  1.6977 +    } else {
  1.6978 +      outline->SetOutlineInitialColor();
  1.6979 +    }
  1.6980 +  }
  1.6981 +  else if (SetColor(*outlineColorValue, unused, mPresContext,
  1.6982 +                    aContext, outlineColor, canStoreInRuleTree))
  1.6983 +    outline->SetOutlineColor(outlineColor);
  1.6984 +  else if (eCSSUnit_Enumerated == outlineColorValue->GetUnit() ||
  1.6985 +           eCSSUnit_Initial == outlineColorValue->GetUnit() ||
  1.6986 +           eCSSUnit_Unset == outlineColorValue->GetUnit()) {
  1.6987 +    outline->SetOutlineInitialColor();
  1.6988 +  }
  1.6989 +
  1.6990 +  // -moz-outline-radius: length, percent, inherit
  1.6991 +  {
  1.6992 +    const nsCSSProperty* subprops =
  1.6993 +      nsCSSProps::SubpropertyEntryFor(eCSSProperty__moz_outline_radius);
  1.6994 +    NS_FOR_CSS_FULL_CORNERS(corner) {
  1.6995 +      int cx = NS_FULL_TO_HALF_CORNER(corner, false);
  1.6996 +      int cy = NS_FULL_TO_HALF_CORNER(corner, true);
  1.6997 +      const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
  1.6998 +      nsStyleCoord parentX = parentOutline->mOutlineRadius.Get(cx);
  1.6999 +      nsStyleCoord parentY = parentOutline->mOutlineRadius.Get(cy);
  1.7000 +      nsStyleCoord coordX, coordY;
  1.7001 +
  1.7002 +      if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
  1.7003 +                        SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
  1.7004 +                          SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
  1.7005 +                        aContext, mPresContext, canStoreInRuleTree)) {
  1.7006 +        outline->mOutlineRadius.Set(cx, coordX);
  1.7007 +        outline->mOutlineRadius.Set(cy, coordY);
  1.7008 +      }
  1.7009 +    }
  1.7010 +  }
  1.7011 +
  1.7012 +  // outline-style: enum, inherit, initial
  1.7013 +  // cannot use SetDiscrete because of SetOutlineStyle
  1.7014 +  const nsCSSValue* outlineStyleValue = aRuleData->ValueForOutlineStyle();
  1.7015 +  nsCSSUnit unit = outlineStyleValue->GetUnit();
  1.7016 +  NS_ABORT_IF_FALSE(eCSSUnit_None != unit && eCSSUnit_Auto != unit,
  1.7017 +                    "'none' and 'auto' should be handled as enumerated values");
  1.7018 +  if (eCSSUnit_Enumerated == unit) {
  1.7019 +    outline->SetOutlineStyle(outlineStyleValue->GetIntValue());
  1.7020 +  } else if (eCSSUnit_Initial == unit ||
  1.7021 +             eCSSUnit_Unset == unit) {
  1.7022 +    outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_NONE);
  1.7023 +  } else if (eCSSUnit_Inherit == unit) {
  1.7024 +    canStoreInRuleTree = false;
  1.7025 +    outline->SetOutlineStyle(parentOutline->GetOutlineStyle());
  1.7026 +  }
  1.7027 +
  1.7028 +  outline->RecalcData(mPresContext);
  1.7029 +  COMPUTE_END_RESET(Outline, outline)
  1.7030 +}
  1.7031 +
  1.7032 +const void*
  1.7033 +nsRuleNode::ComputeListData(void* aStartStruct,
  1.7034 +                            const nsRuleData* aRuleData,
  1.7035 +                            nsStyleContext* aContext,
  1.7036 +                            nsRuleNode* aHighestNode,
  1.7037 +                            const RuleDetail aRuleDetail,
  1.7038 +                            const bool aCanStoreInRuleTree)
  1.7039 +{
  1.7040 +  COMPUTE_START_INHERITED(List, (), list, parentList)
  1.7041 +
  1.7042 +  // list-style-type: enum, inherit, initial
  1.7043 +  SetDiscrete(*aRuleData->ValueForListStyleType(),
  1.7044 +              list->mListStyleType, canStoreInRuleTree,
  1.7045 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.7046 +              parentList->mListStyleType,
  1.7047 +              NS_STYLE_LIST_STYLE_DISC, 0, 0, 0, 0);
  1.7048 +
  1.7049 +  // list-style-image: url, none, inherit
  1.7050 +  const nsCSSValue* imageValue = aRuleData->ValueForListStyleImage();
  1.7051 +  if (eCSSUnit_Image == imageValue->GetUnit()) {
  1.7052 +    NS_SET_IMAGE_REQUEST_WITH_DOC(list->SetListStyleImage,
  1.7053 +                                  aContext,
  1.7054 +                                  imageValue->GetImageValue)
  1.7055 +  }
  1.7056 +  else if (eCSSUnit_None == imageValue->GetUnit() ||
  1.7057 +           eCSSUnit_Initial == imageValue->GetUnit()) {
  1.7058 +    list->SetListStyleImage(nullptr);
  1.7059 +  }
  1.7060 +  else if (eCSSUnit_Inherit == imageValue->GetUnit() ||
  1.7061 +           eCSSUnit_Unset == imageValue->GetUnit()) {
  1.7062 +    canStoreInRuleTree = false;
  1.7063 +    NS_SET_IMAGE_REQUEST(list->SetListStyleImage,
  1.7064 +                         aContext,
  1.7065 +                         parentList->GetListStyleImage())
  1.7066 +  }
  1.7067 +
  1.7068 +  // list-style-position: enum, inherit, initial
  1.7069 +  SetDiscrete(*aRuleData->ValueForListStylePosition(),
  1.7070 +              list->mListStylePosition, canStoreInRuleTree,
  1.7071 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.7072 +              parentList->mListStylePosition,
  1.7073 +              NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, 0, 0, 0, 0);
  1.7074 +
  1.7075 +  // image region property: length, auto, inherit
  1.7076 +  const nsCSSValue* imageRegionValue = aRuleData->ValueForImageRegion();
  1.7077 +  switch (imageRegionValue->GetUnit()) {
  1.7078 +  case eCSSUnit_Inherit:
  1.7079 +  case eCSSUnit_Unset:
  1.7080 +    canStoreInRuleTree = false;
  1.7081 +    list->mImageRegion = parentList->mImageRegion;
  1.7082 +    break;
  1.7083 +
  1.7084 +  case eCSSUnit_Initial:
  1.7085 +  case eCSSUnit_Auto:
  1.7086 +    list->mImageRegion.SetRect(0,0,0,0);
  1.7087 +    break;
  1.7088 +
  1.7089 +  case eCSSUnit_Null:
  1.7090 +    break;
  1.7091 +
  1.7092 +  case eCSSUnit_Rect: {
  1.7093 +    const nsCSSRect& rgnRect = imageRegionValue->GetRectValue();
  1.7094 +
  1.7095 +    if (rgnRect.mTop.GetUnit() == eCSSUnit_Auto)
  1.7096 +      list->mImageRegion.y = 0;
  1.7097 +    else if (rgnRect.mTop.IsLengthUnit())
  1.7098 +      list->mImageRegion.y =
  1.7099 +        CalcLength(rgnRect.mTop, aContext, mPresContext, canStoreInRuleTree);
  1.7100 +
  1.7101 +    if (rgnRect.mBottom.GetUnit() == eCSSUnit_Auto)
  1.7102 +      list->mImageRegion.height = 0;
  1.7103 +    else if (rgnRect.mBottom.IsLengthUnit())
  1.7104 +      list->mImageRegion.height =
  1.7105 +        CalcLength(rgnRect.mBottom, aContext, mPresContext,
  1.7106 +                   canStoreInRuleTree) - list->mImageRegion.y;
  1.7107 +
  1.7108 +    if (rgnRect.mLeft.GetUnit() == eCSSUnit_Auto)
  1.7109 +      list->mImageRegion.x = 0;
  1.7110 +    else if (rgnRect.mLeft.IsLengthUnit())
  1.7111 +      list->mImageRegion.x =
  1.7112 +        CalcLength(rgnRect.mLeft, aContext, mPresContext, canStoreInRuleTree);
  1.7113 +
  1.7114 +    if (rgnRect.mRight.GetUnit() == eCSSUnit_Auto)
  1.7115 +      list->mImageRegion.width = 0;
  1.7116 +    else if (rgnRect.mRight.IsLengthUnit())
  1.7117 +      list->mImageRegion.width =
  1.7118 +        CalcLength(rgnRect.mRight, aContext, mPresContext,
  1.7119 +                   canStoreInRuleTree) - list->mImageRegion.x;
  1.7120 +    break;
  1.7121 +  }
  1.7122 +
  1.7123 +  default:
  1.7124 +    NS_ABORT_IF_FALSE(false, "unrecognized image-region unit");
  1.7125 +  }
  1.7126 +
  1.7127 +  COMPUTE_END_INHERITED(List, list)
  1.7128 +}
  1.7129 +
  1.7130 +static void
  1.7131 +SetGridTrackBreadth(const nsCSSValue& aValue,
  1.7132 +                    nsStyleCoord& aResult,
  1.7133 +                    nsStyleContext* aStyleContext,
  1.7134 +                    nsPresContext* aPresContext,
  1.7135 +                    bool& aCanStoreInRuleTree)
  1.7136 +{
  1.7137 +  nsCSSUnit unit = aValue.GetUnit();
  1.7138 +  if (unit == eCSSUnit_FlexFraction) {
  1.7139 +    aResult.SetFlexFractionValue(aValue.GetFloatValue());
  1.7140 +  } else {
  1.7141 +    MOZ_ASSERT(unit != eCSSUnit_Inherit && unit != eCSSUnit_Unset,
  1.7142 +               "Unexpected value that would use dummyParentCoord");
  1.7143 +    const nsStyleCoord dummyParentCoord;
  1.7144 +    SetCoord(aValue, aResult, dummyParentCoord,
  1.7145 +             SETCOORD_LPE | SETCOORD_STORE_CALC,
  1.7146 +             aStyleContext, aPresContext, aCanStoreInRuleTree);
  1.7147 +  }
  1.7148 +}
  1.7149 +
  1.7150 +static void
  1.7151 +SetGridTrackSize(const nsCSSValue& aValue,
  1.7152 +                 nsStyleCoord& aResultMin,
  1.7153 +                 nsStyleCoord& aResultMax,
  1.7154 +                 nsStyleContext* aStyleContext,
  1.7155 +                 nsPresContext* aPresContext,
  1.7156 +                 bool& aCanStoreInRuleTree)
  1.7157 +{
  1.7158 +  if (aValue.GetUnit() == eCSSUnit_Function) {
  1.7159 +    // A minmax() function.
  1.7160 +    nsCSSValue::Array* func = aValue.GetArrayValue();
  1.7161 +    NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_minmax,
  1.7162 +                 "Expected minmax(), got another function name");
  1.7163 +    SetGridTrackBreadth(func->Item(1), aResultMin,
  1.7164 +                        aStyleContext, aPresContext, aCanStoreInRuleTree);
  1.7165 +    SetGridTrackBreadth(func->Item(2), aResultMax,
  1.7166 +                        aStyleContext, aPresContext, aCanStoreInRuleTree);
  1.7167 +  } else if (aValue.GetUnit() == eCSSUnit_Auto) {
  1.7168 +    // 'auto' computes to 'minmax(min-content, max-content)'
  1.7169 +    aResultMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
  1.7170 +                           eStyleUnit_Enumerated);
  1.7171 +    aResultMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
  1.7172 +                           eStyleUnit_Enumerated);
  1.7173 +  } else {
  1.7174 +    // A single <track-breadth>,
  1.7175 +    // specifies identical min and max sizing functions.
  1.7176 +    SetGridTrackBreadth(aValue, aResultMin,
  1.7177 +                        aStyleContext, aPresContext, aCanStoreInRuleTree);
  1.7178 +    aResultMax = aResultMin;
  1.7179 +  }
  1.7180 +}
  1.7181 +
  1.7182 +static void
  1.7183 +SetGridAutoColumnsRows(const nsCSSValue& aValue,
  1.7184 +                       nsStyleCoord& aResultMin,
  1.7185 +                       nsStyleCoord& aResultMax,
  1.7186 +                       const nsStyleCoord& aParentValueMin,
  1.7187 +                       const nsStyleCoord& aParentValueMax,
  1.7188 +                       nsStyleContext* aStyleContext,
  1.7189 +                       nsPresContext* aPresContext,
  1.7190 +                       bool& aCanStoreInRuleTree)
  1.7191 +
  1.7192 +{
  1.7193 +  switch (aValue.GetUnit()) {
  1.7194 +  case eCSSUnit_Null:
  1.7195 +    break;
  1.7196 +
  1.7197 +  case eCSSUnit_Inherit:
  1.7198 +    aCanStoreInRuleTree = false;
  1.7199 +    aResultMin = aParentValueMin;
  1.7200 +    aResultMax = aParentValueMax;
  1.7201 +    break;
  1.7202 +
  1.7203 +  case eCSSUnit_Initial:
  1.7204 +  case eCSSUnit_Unset:
  1.7205 +    // The initial value is 'auto',
  1.7206 +    // which computes to 'minmax(min-content, max-content)'.
  1.7207 +    // (Explicitly-specified 'auto' values are handled in SetGridTrackSize.)
  1.7208 +    aResultMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
  1.7209 +                           eStyleUnit_Enumerated);
  1.7210 +    aResultMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
  1.7211 +                           eStyleUnit_Enumerated);
  1.7212 +    break;
  1.7213 +
  1.7214 +  default:
  1.7215 +    SetGridTrackSize(aValue, aResultMin, aResultMax,
  1.7216 +                     aStyleContext, aPresContext, aCanStoreInRuleTree);
  1.7217 +  }
  1.7218 +}
  1.7219 +
  1.7220 +static void
  1.7221 +AppendGridLineNames(const nsCSSValue& aValue,
  1.7222 +                    nsStyleGridTemplate& aResult)
  1.7223 +{
  1.7224 +  // Compute a <line-names> value
  1.7225 +  nsTArray<nsString>* nameList = aResult.mLineNameLists.AppendElement();
  1.7226 +  // Null unit means empty list, nothing more to do.
  1.7227 +  if (aValue.GetUnit() != eCSSUnit_Null) {
  1.7228 +    const nsCSSValueList* item = aValue.GetListValue();
  1.7229 +    do {
  1.7230 +      nsString* name = nameList->AppendElement();
  1.7231 +      item->mValue.GetStringValue(*name);
  1.7232 +      item = item->mNext;
  1.7233 +    } while (item);
  1.7234 +  }
  1.7235 +}
  1.7236 +
  1.7237 +static void
  1.7238 +SetGridTrackList(const nsCSSValue& aValue,
  1.7239 +                 nsStyleGridTemplate& aResult,
  1.7240 +                 const nsStyleGridTemplate& aParentValue,
  1.7241 +                 nsStyleContext* aStyleContext,
  1.7242 +                 nsPresContext* aPresContext,
  1.7243 +                 bool& aCanStoreInRuleTree)
  1.7244 +
  1.7245 +{
  1.7246 +  switch (aValue.GetUnit()) {
  1.7247 +  case eCSSUnit_Null:
  1.7248 +    break;
  1.7249 +
  1.7250 +  case eCSSUnit_Inherit:
  1.7251 +    aCanStoreInRuleTree = false;
  1.7252 +    aResult.mIsSubgrid = aParentValue.mIsSubgrid;
  1.7253 +    aResult.mLineNameLists = aParentValue.mLineNameLists;
  1.7254 +    aResult.mMinTrackSizingFunctions = aParentValue.mMinTrackSizingFunctions;
  1.7255 +    aResult.mMaxTrackSizingFunctions = aParentValue.mMaxTrackSizingFunctions;
  1.7256 +    break;
  1.7257 +
  1.7258 +  case eCSSUnit_Initial:
  1.7259 +  case eCSSUnit_Unset:
  1.7260 +  case eCSSUnit_None:
  1.7261 +    aResult.mIsSubgrid = false;
  1.7262 +    aResult.mLineNameLists.Clear();
  1.7263 +    aResult.mMinTrackSizingFunctions.Clear();
  1.7264 +    aResult.mMaxTrackSizingFunctions.Clear();
  1.7265 +    break;
  1.7266 +
  1.7267 +  default:
  1.7268 +    aResult.mLineNameLists.Clear();
  1.7269 +    aResult.mMinTrackSizingFunctions.Clear();
  1.7270 +    aResult.mMaxTrackSizingFunctions.Clear();
  1.7271 +    const nsCSSValueList* item = aValue.GetListValue();
  1.7272 +    if (item->mValue.GetUnit() == eCSSUnit_Enumerated &&
  1.7273 +        item->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) {
  1.7274 +      // subgrid <line-name-list>?
  1.7275 +      aResult.mIsSubgrid = true;
  1.7276 +      item = item->mNext;
  1.7277 +      while (item) {
  1.7278 +        AppendGridLineNames(item->mValue, aResult);
  1.7279 +        item = item->mNext;
  1.7280 +      }
  1.7281 +    } else {
  1.7282 +      // <track-list>
  1.7283 +      // The list is expected to have odd number of items, at least 3
  1.7284 +      // starting with a <line-names> (sub list of identifiers),
  1.7285 +      // and alternating between that and <track-size>.
  1.7286 +      aResult.mIsSubgrid = false;
  1.7287 +      for (;;) {
  1.7288 +        AppendGridLineNames(item->mValue, aResult);
  1.7289 +        item = item->mNext;
  1.7290 +
  1.7291 +        if (!item) {
  1.7292 +          break;
  1.7293 +        }
  1.7294 +
  1.7295 +        nsStyleCoord& min = *aResult.mMinTrackSizingFunctions.AppendElement();
  1.7296 +        nsStyleCoord& max = *aResult.mMaxTrackSizingFunctions.AppendElement();
  1.7297 +        SetGridTrackSize(item->mValue, min, max,
  1.7298 +                         aStyleContext, aPresContext, aCanStoreInRuleTree);
  1.7299 +
  1.7300 +        item = item->mNext;
  1.7301 +        MOZ_ASSERT(item, "Expected a eCSSUnit_List of odd length");
  1.7302 +      }
  1.7303 +      MOZ_ASSERT(!aResult.mMinTrackSizingFunctions.IsEmpty() &&
  1.7304 +                 aResult.mMinTrackSizingFunctions.Length() ==
  1.7305 +                 aResult.mMaxTrackSizingFunctions.Length() &&
  1.7306 +                 aResult.mMinTrackSizingFunctions.Length() + 1 ==
  1.7307 +                 aResult.mLineNameLists.Length(),
  1.7308 +                 "Inconstistent array lengths for nsStyleGridTemplate");
  1.7309 +    }
  1.7310 +  }
  1.7311 +}
  1.7312 +
  1.7313 +static void
  1.7314 +SetGridTemplateAreas(const nsCSSValue& aValue,
  1.7315 +                     nsRefPtr<css::GridTemplateAreasValue>* aResult,
  1.7316 +                     css::GridTemplateAreasValue* aParentValue,
  1.7317 +                     bool& aCanStoreInRuleTree)
  1.7318 +{
  1.7319 +  switch (aValue.GetUnit()) {
  1.7320 +  case eCSSUnit_Null:
  1.7321 +    break;
  1.7322 +
  1.7323 +  case eCSSUnit_Inherit:
  1.7324 +    aCanStoreInRuleTree = false;
  1.7325 +    *aResult = aParentValue;
  1.7326 +    break;
  1.7327 +
  1.7328 +  case eCSSUnit_Initial:
  1.7329 +  case eCSSUnit_Unset:
  1.7330 +  case eCSSUnit_None:
  1.7331 +    *aResult = nullptr;
  1.7332 +    break;
  1.7333 +
  1.7334 +  default:
  1.7335 +    *aResult = aValue.GetGridTemplateAreas();
  1.7336 +  }
  1.7337 +}
  1.7338 +
  1.7339 +static void
  1.7340 +SetGridLine(const nsCSSValue& aValue,
  1.7341 +            nsStyleGridLine& aResult,
  1.7342 +            const nsStyleGridLine& aParentValue,
  1.7343 +            bool& aCanStoreInRuleTree)
  1.7344 +
  1.7345 +{
  1.7346 +  switch (aValue.GetUnit()) {
  1.7347 +  case eCSSUnit_Null:
  1.7348 +    break;
  1.7349 +
  1.7350 +  case eCSSUnit_Inherit:
  1.7351 +    aCanStoreInRuleTree = false;
  1.7352 +    aResult = aParentValue;
  1.7353 +    break;
  1.7354 +
  1.7355 +  case eCSSUnit_Initial:
  1.7356 +  case eCSSUnit_Unset:
  1.7357 +  case eCSSUnit_Auto:
  1.7358 +    aResult.SetAuto();
  1.7359 +    break;
  1.7360 +
  1.7361 +  default:
  1.7362 +    aResult.SetAuto();  // Reset any existing value.
  1.7363 +    const nsCSSValueList* item = aValue.GetListValue();
  1.7364 +    do {
  1.7365 +      if (item->mValue.GetUnit() == eCSSUnit_Enumerated) {
  1.7366 +        aResult.mHasSpan = true;
  1.7367 +      } else if (item->mValue.GetUnit() == eCSSUnit_Integer) {
  1.7368 +        aResult.mInteger = item->mValue.GetIntValue();
  1.7369 +      } else if (item->mValue.GetUnit() == eCSSUnit_Ident) {
  1.7370 +        item->mValue.GetStringValue(aResult.mLineName);
  1.7371 +      } else {
  1.7372 +        NS_ASSERTION(false, "Unexpected unit");
  1.7373 +      }
  1.7374 +      item = item->mNext;
  1.7375 +    } while (item);
  1.7376 +    MOZ_ASSERT(!aResult.IsAuto(),
  1.7377 +               "should have set something away from default value");
  1.7378 +  }
  1.7379 +}
  1.7380 +
  1.7381 +const void*
  1.7382 +nsRuleNode::ComputePositionData(void* aStartStruct,
  1.7383 +                                const nsRuleData* aRuleData,
  1.7384 +                                nsStyleContext* aContext,
  1.7385 +                                nsRuleNode* aHighestNode,
  1.7386 +                                const RuleDetail aRuleDetail,
  1.7387 +                                const bool aCanStoreInRuleTree)
  1.7388 +{
  1.7389 +  COMPUTE_START_RESET(Position, (), pos, parentPos)
  1.7390 +
  1.7391 +  // box offsets: length, percent, calc, auto, inherit
  1.7392 +  static const nsCSSProperty offsetProps[] = {
  1.7393 +    eCSSProperty_top,
  1.7394 +    eCSSProperty_right,
  1.7395 +    eCSSProperty_bottom,
  1.7396 +    eCSSProperty_left
  1.7397 +  };
  1.7398 +  nsStyleCoord  coord;
  1.7399 +  NS_FOR_CSS_SIDES(side) {
  1.7400 +    nsStyleCoord parentCoord = parentPos->mOffset.Get(side);
  1.7401 +    if (SetCoord(*aRuleData->ValueFor(offsetProps[side]),
  1.7402 +                 coord, parentCoord,
  1.7403 +                 SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
  1.7404 +                   SETCOORD_UNSET_INITIAL,
  1.7405 +                 aContext, mPresContext, canStoreInRuleTree)) {
  1.7406 +      pos->mOffset.Set(side, coord);
  1.7407 +    }
  1.7408 +  }
  1.7409 +
  1.7410 +  SetCoord(*aRuleData->ValueForWidth(), pos->mWidth, parentPos->mWidth,
  1.7411 +           SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
  1.7412 +             SETCOORD_UNSET_INITIAL,
  1.7413 +           aContext, mPresContext, canStoreInRuleTree);
  1.7414 +  SetCoord(*aRuleData->ValueForMinWidth(), pos->mMinWidth, parentPos->mMinWidth,
  1.7415 +           SETCOORD_LPEH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  1.7416 +             SETCOORD_UNSET_INITIAL,
  1.7417 +           aContext, mPresContext, canStoreInRuleTree);
  1.7418 +  SetCoord(*aRuleData->ValueForMaxWidth(), pos->mMaxWidth, parentPos->mMaxWidth,
  1.7419 +           SETCOORD_LPOEH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
  1.7420 +             SETCOORD_UNSET_INITIAL,
  1.7421 +           aContext, mPresContext, canStoreInRuleTree);
  1.7422 +
  1.7423 +  SetCoord(*aRuleData->ValueForHeight(), pos->mHeight, parentPos->mHeight,
  1.7424 +           SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
  1.7425 +             SETCOORD_UNSET_INITIAL,
  1.7426 +           aContext, mPresContext, canStoreInRuleTree);
  1.7427 +  SetCoord(*aRuleData->ValueForMinHeight(), pos->mMinHeight, parentPos->mMinHeight,
  1.7428 +           SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
  1.7429 +             SETCOORD_UNSET_INITIAL,
  1.7430 +           aContext, mPresContext, canStoreInRuleTree);
  1.7431 +  SetCoord(*aRuleData->ValueForMaxHeight(), pos->mMaxHeight, parentPos->mMaxHeight,
  1.7432 +           SETCOORD_LPOH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
  1.7433 +             SETCOORD_UNSET_INITIAL,
  1.7434 +           aContext, mPresContext, canStoreInRuleTree);
  1.7435 +
  1.7436 +  // box-sizing: enum, inherit, initial
  1.7437 +  SetDiscrete(*aRuleData->ValueForBoxSizing(),
  1.7438 +              pos->mBoxSizing, canStoreInRuleTree,
  1.7439 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.7440 +              parentPos->mBoxSizing,
  1.7441 +              NS_STYLE_BOX_SIZING_CONTENT, 0, 0, 0, 0);
  1.7442 +
  1.7443 +  // align-content: enum, inherit, initial
  1.7444 +  SetDiscrete(*aRuleData->ValueForAlignContent(),
  1.7445 +              pos->mAlignContent, canStoreInRuleTree,
  1.7446 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.7447 +              parentPos->mAlignContent,
  1.7448 +              NS_STYLE_ALIGN_CONTENT_STRETCH, 0, 0, 0, 0);
  1.7449 +
  1.7450 +  // align-items: enum, inherit, initial
  1.7451 +  SetDiscrete(*aRuleData->ValueForAlignItems(),
  1.7452 +              pos->mAlignItems, canStoreInRuleTree,
  1.7453 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.7454 +              parentPos->mAlignItems,
  1.7455 +              NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE, 0, 0, 0, 0);
  1.7456 +
  1.7457 +  // align-self: enum, inherit, initial
  1.7458 +  // NOTE: align-self's initial value is the special keyword "auto", which is
  1.7459 +  // supposed to compute to our parent's computed value of "align-items".  So
  1.7460 +  // technically, "auto" itself is never a valid computed value for align-self,
  1.7461 +  // since it always computes to something else.  Despite that, we do actually
  1.7462 +  // store "auto" in nsStylePosition::mAlignSelf, as NS_STYLE_ALIGN_SELF_AUTO
  1.7463 +  // (and then resolve it as-necessary).  We do this because "auto" is the
  1.7464 +  // initial value for this property, so if we were to actually resolve it in
  1.7465 +  // nsStylePosition, we'd never be able to share any nsStylePosition structs
  1.7466 +  // in the rule tree, since their mAlignSelf values would depend on the parent
  1.7467 +  // style, by default.
  1.7468 +  if (aRuleData->ValueForAlignSelf()->GetUnit() == eCSSUnit_Inherit) {
  1.7469 +    // Special handling for "align-self: inherit", in case we're inheriting
  1.7470 +    // "align-self: auto", in which case we need to resolve the parent's "auto"
  1.7471 +    // and inherit that resolved value.
  1.7472 +    uint8_t inheritedAlignSelf = parentPos->mAlignSelf;
  1.7473 +    if (inheritedAlignSelf == NS_STYLE_ALIGN_SELF_AUTO) {
  1.7474 +      if (!parentContext) {
  1.7475 +        // We're the root node. Nothing to inherit from --> just use default
  1.7476 +        // value.
  1.7477 +        inheritedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
  1.7478 +      } else {
  1.7479 +        // Our parent's "auto" value should resolve to our grandparent's value
  1.7480 +        // for "align-items".  So, that's what we're supposed to inherit.
  1.7481 +        nsStyleContext* grandparentContext = parentContext->GetParent();
  1.7482 +        if (!grandparentContext) {
  1.7483 +          // No grandparent --> our parent is the root node, so its
  1.7484 +          // "align-self: auto" computes to the default "align-items" value:
  1.7485 +          inheritedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
  1.7486 +        } else {
  1.7487 +          // Normal case -- we have a grandparent.
  1.7488 +          // Its "align-items" value is what we should end up inheriting.
  1.7489 +          const nsStylePosition* grandparentPos =
  1.7490 +            grandparentContext->StylePosition();
  1.7491 +          inheritedAlignSelf = grandparentPos->mAlignItems;
  1.7492 +        }
  1.7493 +      }
  1.7494 +    }
  1.7495 +
  1.7496 +    pos->mAlignSelf = inheritedAlignSelf;
  1.7497 +    canStoreInRuleTree = false;
  1.7498 +  } else {
  1.7499 +    SetDiscrete(*aRuleData->ValueForAlignSelf(),
  1.7500 +                pos->mAlignSelf, canStoreInRuleTree,
  1.7501 +                SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.7502 +                parentPos->mAlignSelf, // (unused -- we handled inherit above)
  1.7503 +                NS_STYLE_ALIGN_SELF_AUTO, // initial == auto
  1.7504 +                0, 0, 0, 0);
  1.7505 +  }
  1.7506 +
  1.7507 +  // flex-basis: auto, length, percent, enum, calc, inherit, initial
  1.7508 +  // (Note: The flags here should match those used for 'width' property above.)
  1.7509 +  SetCoord(*aRuleData->ValueForFlexBasis(), pos->mFlexBasis, parentPos->mFlexBasis,
  1.7510 +           SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
  1.7511 +             SETCOORD_UNSET_INITIAL,
  1.7512 +           aContext, mPresContext, canStoreInRuleTree);
  1.7513 +
  1.7514 +  // flex-direction: enum, inherit, initial
  1.7515 +  SetDiscrete(*aRuleData->ValueForFlexDirection(),
  1.7516 +              pos->mFlexDirection, canStoreInRuleTree,
  1.7517 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.7518 +              parentPos->mFlexDirection,
  1.7519 +              NS_STYLE_FLEX_DIRECTION_ROW, 0, 0, 0, 0);
  1.7520 +
  1.7521 +  // flex-grow: float, inherit, initial
  1.7522 +  SetFactor(*aRuleData->ValueForFlexGrow(),
  1.7523 +            pos->mFlexGrow, canStoreInRuleTree,
  1.7524 +            parentPos->mFlexGrow, 0.0f,
  1.7525 +            SETFCT_UNSET_INITIAL);
  1.7526 +
  1.7527 +  // flex-shrink: float, inherit, initial
  1.7528 +  SetFactor(*aRuleData->ValueForFlexShrink(),
  1.7529 +            pos->mFlexShrink, canStoreInRuleTree,
  1.7530 +            parentPos->mFlexShrink, 1.0f,
  1.7531 +            SETFCT_UNSET_INITIAL);
  1.7532 +
  1.7533 +  // flex-wrap: enum, inherit, initial
  1.7534 +  SetDiscrete(*aRuleData->ValueForFlexWrap(),
  1.7535 +              pos->mFlexWrap, canStoreInRuleTree,
  1.7536 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.7537 +              parentPos->mFlexWrap,
  1.7538 +              NS_STYLE_FLEX_WRAP_NOWRAP, 0, 0, 0, 0);
  1.7539 +
  1.7540 +  // order: integer, inherit, initial
  1.7541 +  SetDiscrete(*aRuleData->ValueForOrder(),
  1.7542 +              pos->mOrder, canStoreInRuleTree,
  1.7543 +              SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
  1.7544 +              parentPos->mOrder,
  1.7545 +              NS_STYLE_ORDER_INITIAL, 0, 0, 0, 0);
  1.7546 +
  1.7547 +  // justify-content: enum, inherit, initial
  1.7548 +  SetDiscrete(*aRuleData->ValueForJustifyContent(),
  1.7549 +              pos->mJustifyContent, canStoreInRuleTree,
  1.7550 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.7551 +              parentPos->mJustifyContent,
  1.7552 +              NS_STYLE_JUSTIFY_CONTENT_FLEX_START, 0, 0, 0, 0);
  1.7553 +
  1.7554 +  // grid-auto-flow
  1.7555 +  const nsCSSValue& gridAutoFlow = *aRuleData->ValueForGridAutoFlow();
  1.7556 +  switch (gridAutoFlow.GetUnit()) {
  1.7557 +    case eCSSUnit_Null:
  1.7558 +      break;
  1.7559 +    case eCSSUnit_Inherit:
  1.7560 +      canStoreInRuleTree = false;
  1.7561 +      pos->mGridAutoFlow = parentPos->mGridAutoFlow;
  1.7562 +      break;
  1.7563 +    case eCSSUnit_Initial:
  1.7564 +    case eCSSUnit_Unset:
  1.7565 +      pos->mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_NONE;
  1.7566 +      break;
  1.7567 +    default:
  1.7568 +      NS_ASSERTION(gridAutoFlow.GetUnit() == eCSSUnit_Enumerated,
  1.7569 +                   "Unexpected unit");
  1.7570 +      pos->mGridAutoFlow = gridAutoFlow.GetIntValue();
  1.7571 +  }
  1.7572 +
  1.7573 +  // grid-auto-columns
  1.7574 +  SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoColumns(),
  1.7575 +                         pos->mGridAutoColumnsMin,
  1.7576 +                         pos->mGridAutoColumnsMax,
  1.7577 +                         parentPos->mGridAutoColumnsMin,
  1.7578 +                         parentPos->mGridAutoColumnsMax,
  1.7579 +                         aContext, mPresContext, canStoreInRuleTree);
  1.7580 +
  1.7581 +  // grid-auto-rows
  1.7582 +  SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoRows(),
  1.7583 +                         pos->mGridAutoRowsMin,
  1.7584 +                         pos->mGridAutoRowsMax,
  1.7585 +                         parentPos->mGridAutoRowsMin,
  1.7586 +                         parentPos->mGridAutoRowsMax,
  1.7587 +                         aContext, mPresContext, canStoreInRuleTree);
  1.7588 +
  1.7589 +  // grid-template-columns
  1.7590 +  SetGridTrackList(*aRuleData->ValueForGridTemplateColumns(),
  1.7591 +                   pos->mGridTemplateColumns, parentPos->mGridTemplateColumns,
  1.7592 +                   aContext, mPresContext, canStoreInRuleTree);
  1.7593 +
  1.7594 +  // grid-template-rows
  1.7595 +  SetGridTrackList(*aRuleData->ValueForGridTemplateRows(),
  1.7596 +                   pos->mGridTemplateRows, parentPos->mGridTemplateRows,
  1.7597 +                   aContext, mPresContext, canStoreInRuleTree);
  1.7598 +
  1.7599 +  // grid-tempate-areas
  1.7600 +  SetGridTemplateAreas(*aRuleData->ValueForGridTemplateAreas(),
  1.7601 +                       &pos->mGridTemplateAreas,
  1.7602 +                       parentPos->mGridTemplateAreas,
  1.7603 +                       canStoreInRuleTree);
  1.7604 +
  1.7605 +  // grid-auto-position
  1.7606 +  const nsCSSValue& gridAutoPosition = *aRuleData->ValueForGridAutoPosition();
  1.7607 +  switch (gridAutoPosition.GetUnit()) {
  1.7608 +    case eCSSUnit_Null:
  1.7609 +      break;
  1.7610 +    case eCSSUnit_Inherit:
  1.7611 +      canStoreInRuleTree = false;
  1.7612 +      pos->mGridAutoPositionColumn = parentPos->mGridAutoPositionColumn;
  1.7613 +      pos->mGridAutoPositionRow = parentPos->mGridAutoPositionRow;
  1.7614 +      break;
  1.7615 +    case eCSSUnit_Initial:
  1.7616 +    case eCSSUnit_Unset:
  1.7617 +      // '1 / 1'
  1.7618 +      pos->mGridAutoPositionColumn.SetToInteger(1);
  1.7619 +      pos->mGridAutoPositionRow.SetToInteger(1);
  1.7620 +      break;
  1.7621 +    default:
  1.7622 +      SetGridLine(gridAutoPosition.GetPairValue().mXValue,
  1.7623 +                  pos->mGridAutoPositionColumn,
  1.7624 +                  parentPos->mGridAutoPositionColumn,
  1.7625 +                  canStoreInRuleTree);
  1.7626 +      SetGridLine(gridAutoPosition.GetPairValue().mYValue,
  1.7627 +                  pos->mGridAutoPositionRow,
  1.7628 +                  parentPos->mGridAutoPositionRow,
  1.7629 +                  canStoreInRuleTree);
  1.7630 +  }
  1.7631 +
  1.7632 +  // grid-column-start
  1.7633 +  SetGridLine(*aRuleData->ValueForGridColumnStart(),
  1.7634 +              pos->mGridColumnStart,
  1.7635 +              parentPos->mGridColumnStart,
  1.7636 +              canStoreInRuleTree);
  1.7637 +
  1.7638 +  // grid-column-end
  1.7639 +  SetGridLine(*aRuleData->ValueForGridColumnEnd(),
  1.7640 +              pos->mGridColumnEnd,
  1.7641 +              parentPos->mGridColumnEnd,
  1.7642 +              canStoreInRuleTree);
  1.7643 +
  1.7644 +  // grid-row-start
  1.7645 +  SetGridLine(*aRuleData->ValueForGridRowStart(),
  1.7646 +              pos->mGridRowStart,
  1.7647 +              parentPos->mGridRowStart,
  1.7648 +              canStoreInRuleTree);
  1.7649 +
  1.7650 +  // grid-row-end
  1.7651 +  SetGridLine(*aRuleData->ValueForGridRowEnd(),
  1.7652 +              pos->mGridRowEnd,
  1.7653 +              parentPos->mGridRowEnd,
  1.7654 +              canStoreInRuleTree);
  1.7655 +
  1.7656 +  // z-index
  1.7657 +  const nsCSSValue* zIndexValue = aRuleData->ValueForZIndex();
  1.7658 +  if (! SetCoord(*zIndexValue, pos->mZIndex, parentPos->mZIndex,
  1.7659 +                 SETCOORD_IA | SETCOORD_INITIAL_AUTO | SETCOORD_UNSET_INITIAL,
  1.7660 +                 aContext, nullptr, canStoreInRuleTree)) {
  1.7661 +    if (eCSSUnit_Inherit == zIndexValue->GetUnit()) {
  1.7662 +      // handle inherit, because it's ok to inherit 'auto' here
  1.7663 +      canStoreInRuleTree = false;
  1.7664 +      pos->mZIndex = parentPos->mZIndex;
  1.7665 +    }
  1.7666 +  }
  1.7667 +
  1.7668 +  COMPUTE_END_RESET(Position, pos)
  1.7669 +}
  1.7670 +
  1.7671 +const void*
  1.7672 +nsRuleNode::ComputeTableData(void* aStartStruct,
  1.7673 +                             const nsRuleData* aRuleData,
  1.7674 +                             nsStyleContext* aContext,
  1.7675 +                             nsRuleNode* aHighestNode,
  1.7676 +                             const RuleDetail aRuleDetail,
  1.7677 +                             const bool aCanStoreInRuleTree)
  1.7678 +{
  1.7679 +  COMPUTE_START_RESET(Table, (), table, parentTable)
  1.7680 +
  1.7681 +  // table-layout: enum, inherit, initial
  1.7682 +  SetDiscrete(*aRuleData->ValueForTableLayout(),
  1.7683 +              table->mLayoutStrategy, canStoreInRuleTree,
  1.7684 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.7685 +              parentTable->mLayoutStrategy,
  1.7686 +              NS_STYLE_TABLE_LAYOUT_AUTO, 0, 0, 0, 0);
  1.7687 +
  1.7688 +  // span: pixels (not a real CSS prop)
  1.7689 +  const nsCSSValue* spanValue = aRuleData->ValueForSpan();
  1.7690 +  if (eCSSUnit_Enumerated == spanValue->GetUnit() ||
  1.7691 +      eCSSUnit_Integer == spanValue->GetUnit())
  1.7692 +    table->mSpan = spanValue->GetIntValue();
  1.7693 +
  1.7694 +  COMPUTE_END_RESET(Table, table)
  1.7695 +}
  1.7696 +
  1.7697 +const void*
  1.7698 +nsRuleNode::ComputeTableBorderData(void* aStartStruct,
  1.7699 +                                   const nsRuleData* aRuleData,
  1.7700 +                                   nsStyleContext* aContext,
  1.7701 +                                   nsRuleNode* aHighestNode,
  1.7702 +                                   const RuleDetail aRuleDetail,
  1.7703 +                                   const bool aCanStoreInRuleTree)
  1.7704 +{
  1.7705 +  COMPUTE_START_INHERITED(TableBorder, (mPresContext), table, parentTable)
  1.7706 +
  1.7707 +  // border-collapse: enum, inherit, initial
  1.7708 +  SetDiscrete(*aRuleData->ValueForBorderCollapse(), table->mBorderCollapse,
  1.7709 +              canStoreInRuleTree,
  1.7710 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.7711 +              parentTable->mBorderCollapse,
  1.7712 +              NS_STYLE_BORDER_SEPARATE, 0, 0, 0, 0);
  1.7713 +
  1.7714 +  const nsCSSValue* borderSpacingValue = aRuleData->ValueForBorderSpacing();
  1.7715 +  if (borderSpacingValue->GetUnit() != eCSSUnit_Null) {
  1.7716 +    // border-spacing-x/y: length, inherit
  1.7717 +    nsStyleCoord parentX(parentTable->mBorderSpacingX,
  1.7718 +                         nsStyleCoord::CoordConstructor);
  1.7719 +    nsStyleCoord parentY(parentTable->mBorderSpacingY,
  1.7720 +                         nsStyleCoord::CoordConstructor);
  1.7721 +    nsStyleCoord coordX, coordY;
  1.7722 +
  1.7723 +#ifdef DEBUG
  1.7724 +    bool result =
  1.7725 +#endif
  1.7726 +      SetPairCoords(*borderSpacingValue,
  1.7727 +                    coordX, coordY, parentX, parentY,
  1.7728 +                    SETCOORD_LH | SETCOORD_INITIAL_ZERO |
  1.7729 +                      SETCOORD_CALC_LENGTH_ONLY |
  1.7730 +                      SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INHERIT,
  1.7731 +                    aContext, mPresContext, canStoreInRuleTree);
  1.7732 +    NS_ASSERTION(result, "malformed table border value");
  1.7733 +    table->mBorderSpacingX = coordX.GetCoordValue();
  1.7734 +    table->mBorderSpacingY = coordY.GetCoordValue();
  1.7735 +  }
  1.7736 +
  1.7737 +  // caption-side: enum, inherit, initial
  1.7738 +  SetDiscrete(*aRuleData->ValueForCaptionSide(),
  1.7739 +              table->mCaptionSide, canStoreInRuleTree,
  1.7740 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.7741 +              parentTable->mCaptionSide,
  1.7742 +              NS_STYLE_CAPTION_SIDE_TOP, 0, 0, 0, 0);
  1.7743 +
  1.7744 +  // empty-cells: enum, inherit, initial
  1.7745 +  SetDiscrete(*aRuleData->ValueForEmptyCells(),
  1.7746 +              table->mEmptyCells, canStoreInRuleTree,
  1.7747 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.7748 +              parentTable->mEmptyCells,
  1.7749 +              (mPresContext->CompatibilityMode() == eCompatibility_NavQuirks)
  1.7750 +              ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
  1.7751 +              : NS_STYLE_TABLE_EMPTY_CELLS_SHOW,
  1.7752 +              0, 0, 0, 0);
  1.7753 +
  1.7754 +  COMPUTE_END_INHERITED(TableBorder, table)
  1.7755 +}
  1.7756 +
  1.7757 +const void*
  1.7758 +nsRuleNode::ComputeContentData(void* aStartStruct,
  1.7759 +                               const nsRuleData* aRuleData,
  1.7760 +                               nsStyleContext* aContext,
  1.7761 +                               nsRuleNode* aHighestNode,
  1.7762 +                               const RuleDetail aRuleDetail,
  1.7763 +                               const bool aCanStoreInRuleTree)
  1.7764 +{
  1.7765 +  uint32_t count;
  1.7766 +  nsAutoString buffer;
  1.7767 +
  1.7768 +  COMPUTE_START_RESET(Content, (), content, parentContent)
  1.7769 +
  1.7770 +  // content: [string, url, counter, attr, enum]+, normal, none, inherit
  1.7771 +  const nsCSSValue* contentValue = aRuleData->ValueForContent();
  1.7772 +  switch (contentValue->GetUnit()) {
  1.7773 +  case eCSSUnit_Null:
  1.7774 +    break;
  1.7775 +
  1.7776 +  case eCSSUnit_Normal:
  1.7777 +  case eCSSUnit_None:
  1.7778 +  case eCSSUnit_Initial:
  1.7779 +  case eCSSUnit_Unset:
  1.7780 +    // "normal", "none", "initial" and "unset" all mean no content
  1.7781 +    content->AllocateContents(0);
  1.7782 +    break;
  1.7783 +
  1.7784 +  case eCSSUnit_Inherit:
  1.7785 +    canStoreInRuleTree = false;
  1.7786 +    count = parentContent->ContentCount();
  1.7787 +    if (NS_SUCCEEDED(content->AllocateContents(count))) {
  1.7788 +      while (0 < count--) {
  1.7789 +        content->ContentAt(count) = parentContent->ContentAt(count);
  1.7790 +      }
  1.7791 +    }
  1.7792 +    break;
  1.7793 +
  1.7794 +  case eCSSUnit_Enumerated: {
  1.7795 +    NS_ABORT_IF_FALSE(contentValue->GetIntValue() ==
  1.7796 +                      NS_STYLE_CONTENT_ALT_CONTENT,
  1.7797 +                      "unrecognized solitary content keyword");
  1.7798 +    content->AllocateContents(1);
  1.7799 +    nsStyleContentData& data = content->ContentAt(0);
  1.7800 +    data.mType = eStyleContentType_AltContent;
  1.7801 +    data.mContent.mString = nullptr;
  1.7802 +    break;
  1.7803 +  }
  1.7804 +
  1.7805 +  case eCSSUnit_List:
  1.7806 +  case eCSSUnit_ListDep: {
  1.7807 +    const nsCSSValueList* contentValueList = contentValue->GetListValue();
  1.7808 +      count = 0;
  1.7809 +      while (contentValueList) {
  1.7810 +        count++;
  1.7811 +        contentValueList = contentValueList->mNext;
  1.7812 +      }
  1.7813 +      if (NS_SUCCEEDED(content->AllocateContents(count))) {
  1.7814 +        const nsAutoString  nullStr;
  1.7815 +        count = 0;
  1.7816 +        contentValueList = contentValue->GetListValue();
  1.7817 +        while (contentValueList) {
  1.7818 +          const nsCSSValue& value = contentValueList->mValue;
  1.7819 +          nsCSSUnit unit = value.GetUnit();
  1.7820 +          nsStyleContentType type;
  1.7821 +          nsStyleContentData &data = content->ContentAt(count++);
  1.7822 +          switch (unit) {
  1.7823 +          case eCSSUnit_String:   type = eStyleContentType_String;    break;
  1.7824 +          case eCSSUnit_Image:    type = eStyleContentType_Image;     break;
  1.7825 +          case eCSSUnit_Attr:     type = eStyleContentType_Attr;      break;
  1.7826 +          case eCSSUnit_Counter:  type = eStyleContentType_Counter;   break;
  1.7827 +          case eCSSUnit_Counters: type = eStyleContentType_Counters;  break;
  1.7828 +          case eCSSUnit_Enumerated:
  1.7829 +            switch (value.GetIntValue()) {
  1.7830 +            case NS_STYLE_CONTENT_OPEN_QUOTE:
  1.7831 +              type = eStyleContentType_OpenQuote;     break;
  1.7832 +            case NS_STYLE_CONTENT_CLOSE_QUOTE:
  1.7833 +              type = eStyleContentType_CloseQuote;    break;
  1.7834 +            case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
  1.7835 +              type = eStyleContentType_NoOpenQuote;   break;
  1.7836 +            case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
  1.7837 +              type = eStyleContentType_NoCloseQuote;  break;
  1.7838 +            default:
  1.7839 +              NS_ERROR("bad content value");
  1.7840 +              type = eStyleContentType_Uninitialized;
  1.7841 +            }
  1.7842 +            break;
  1.7843 +          default:
  1.7844 +            NS_ERROR("bad content type");
  1.7845 +            type = eStyleContentType_Uninitialized;
  1.7846 +          }
  1.7847 +          data.mType = type;
  1.7848 +          if (type == eStyleContentType_Image) {
  1.7849 +            NS_SET_IMAGE_REQUEST_WITH_DOC(data.SetImage,
  1.7850 +                                          aContext,
  1.7851 +                                          value.GetImageValue);
  1.7852 +          }
  1.7853 +          else if (type <= eStyleContentType_Attr) {
  1.7854 +            value.GetStringValue(buffer);
  1.7855 +            data.mContent.mString = NS_strdup(buffer.get());
  1.7856 +          }
  1.7857 +          else if (type <= eStyleContentType_Counters) {
  1.7858 +            data.mContent.mCounters = value.GetArrayValue();
  1.7859 +            data.mContent.mCounters->AddRef();
  1.7860 +          }
  1.7861 +          else {
  1.7862 +            data.mContent.mString = nullptr;
  1.7863 +          }
  1.7864 +          contentValueList = contentValueList->mNext;
  1.7865 +        }
  1.7866 +      }
  1.7867 +      break;
  1.7868 +  }
  1.7869 +
  1.7870 +  default:
  1.7871 +    NS_ABORT_IF_FALSE(false,
  1.7872 +                      nsPrintfCString("unrecognized content unit %d",
  1.7873 +                                      contentValue->GetUnit()).get());
  1.7874 +  }
  1.7875 +
  1.7876 +  // counter-increment: [string [int]]+, none, inherit
  1.7877 +  const nsCSSValue* counterIncrementValue =
  1.7878 +    aRuleData->ValueForCounterIncrement();
  1.7879 +  switch (counterIncrementValue->GetUnit()) {
  1.7880 +  case eCSSUnit_Null:
  1.7881 +    break;
  1.7882 +
  1.7883 +  case eCSSUnit_None:
  1.7884 +  case eCSSUnit_Initial:
  1.7885 +  case eCSSUnit_Unset:
  1.7886 +    content->AllocateCounterIncrements(0);
  1.7887 +    break;
  1.7888 +
  1.7889 +  case eCSSUnit_Inherit:
  1.7890 +    canStoreInRuleTree = false;
  1.7891 +    count = parentContent->CounterIncrementCount();
  1.7892 +    if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
  1.7893 +      while (0 < count--) {
  1.7894 +        const nsStyleCounterData *data =
  1.7895 +          parentContent->GetCounterIncrementAt(count);
  1.7896 +        content->SetCounterIncrementAt(count, data->mCounter, data->mValue);
  1.7897 +      }
  1.7898 +    }
  1.7899 +    break;
  1.7900 +
  1.7901 +  case eCSSUnit_PairList:
  1.7902 +  case eCSSUnit_PairListDep: {
  1.7903 +    const nsCSSValuePairList* ourIncrement =
  1.7904 +      counterIncrementValue->GetPairListValue();
  1.7905 +    NS_ABORT_IF_FALSE(ourIncrement->mXValue.GetUnit() == eCSSUnit_Ident,
  1.7906 +                      "unexpected value unit");
  1.7907 +    count = ListLength(ourIncrement);
  1.7908 +    if (NS_FAILED(content->AllocateCounterIncrements(count))) {
  1.7909 +      break;
  1.7910 +    }
  1.7911 +
  1.7912 +    count = 0;
  1.7913 +    for (const nsCSSValuePairList* p = ourIncrement; p; p = p->mNext, count++) {
  1.7914 +      int32_t increment;
  1.7915 +      if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
  1.7916 +        increment = p->mYValue.GetIntValue();
  1.7917 +      } else {
  1.7918 +        increment = 1;
  1.7919 +      }
  1.7920 +      p->mXValue.GetStringValue(buffer);
  1.7921 +      content->SetCounterIncrementAt(count, buffer, increment);
  1.7922 +    }
  1.7923 +    break;
  1.7924 +  }
  1.7925 +
  1.7926 +  default:
  1.7927 +    NS_ABORT_IF_FALSE(false, "unexpected value unit");
  1.7928 +  }
  1.7929 +
  1.7930 +  // counter-reset: [string [int]]+, none, inherit
  1.7931 +  const nsCSSValue* counterResetValue = aRuleData->ValueForCounterReset();
  1.7932 +  switch (counterResetValue->GetUnit()) {
  1.7933 +  case eCSSUnit_Null:
  1.7934 +    break;
  1.7935 +
  1.7936 +  case eCSSUnit_None:
  1.7937 +  case eCSSUnit_Initial:
  1.7938 +  case eCSSUnit_Unset:
  1.7939 +    content->AllocateCounterResets(0);
  1.7940 +    break;
  1.7941 +
  1.7942 +  case eCSSUnit_Inherit:
  1.7943 +    canStoreInRuleTree = false;
  1.7944 +    count = parentContent->CounterResetCount();
  1.7945 +    if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
  1.7946 +      while (0 < count--) {
  1.7947 +        const nsStyleCounterData *data =
  1.7948 +          parentContent->GetCounterResetAt(count);
  1.7949 +        content->SetCounterResetAt(count, data->mCounter, data->mValue);
  1.7950 +      }
  1.7951 +    }
  1.7952 +    break;
  1.7953 +
  1.7954 +  case eCSSUnit_PairList:
  1.7955 +  case eCSSUnit_PairListDep: {
  1.7956 +    const nsCSSValuePairList* ourReset =
  1.7957 +      counterResetValue->GetPairListValue();
  1.7958 +    NS_ABORT_IF_FALSE(ourReset->mXValue.GetUnit() == eCSSUnit_Ident,
  1.7959 +                      "unexpected value unit");
  1.7960 +    count = ListLength(ourReset);
  1.7961 +    if (NS_FAILED(content->AllocateCounterResets(count))) {
  1.7962 +      break;
  1.7963 +    }
  1.7964 +
  1.7965 +    count = 0;
  1.7966 +    for (const nsCSSValuePairList* p = ourReset; p; p = p->mNext, count++) {
  1.7967 +      int32_t reset;
  1.7968 +      if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
  1.7969 +        reset = p->mYValue.GetIntValue();
  1.7970 +      } else {
  1.7971 +        reset = 0;
  1.7972 +      }
  1.7973 +      p->mXValue.GetStringValue(buffer);
  1.7974 +      content->SetCounterResetAt(count, buffer, reset);
  1.7975 +    }
  1.7976 +    break;
  1.7977 +  }
  1.7978 +
  1.7979 +  default:
  1.7980 +    NS_ABORT_IF_FALSE(false, "unexpected value unit");
  1.7981 +  }
  1.7982 +
  1.7983 +  // marker-offset: length, auto, inherit
  1.7984 +  SetCoord(*aRuleData->ValueForMarkerOffset(), content->mMarkerOffset, parentContent->mMarkerOffset,
  1.7985 +           SETCOORD_LH | SETCOORD_AUTO | SETCOORD_INITIAL_AUTO |
  1.7986 +             SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INITIAL,
  1.7987 +           aContext, mPresContext, canStoreInRuleTree);
  1.7988 +
  1.7989 +  // If we ended up with an image, track it.
  1.7990 +  for (uint32_t i = 0; i < content->ContentCount(); ++i) {
  1.7991 +    if ((content->ContentAt(i).mType == eStyleContentType_Image) &&
  1.7992 +        content->ContentAt(i).mContent.mImage) {
  1.7993 +      content->ContentAt(i).TrackImage(aContext->PresContext());
  1.7994 +    }
  1.7995 +  }
  1.7996 +
  1.7997 +  COMPUTE_END_RESET(Content, content)
  1.7998 +}
  1.7999 +
  1.8000 +const void*
  1.8001 +nsRuleNode::ComputeQuotesData(void* aStartStruct,
  1.8002 +                              const nsRuleData* aRuleData,
  1.8003 +                              nsStyleContext* aContext,
  1.8004 +                              nsRuleNode* aHighestNode,
  1.8005 +                              const RuleDetail aRuleDetail,
  1.8006 +                              const bool aCanStoreInRuleTree)
  1.8007 +{
  1.8008 +  COMPUTE_START_INHERITED(Quotes, (), quotes, parentQuotes)
  1.8009 +
  1.8010 +  // quotes: inherit, initial, none, [string string]+
  1.8011 +  const nsCSSValue* quotesValue = aRuleData->ValueForQuotes();
  1.8012 +  switch (quotesValue->GetUnit()) {
  1.8013 +  case eCSSUnit_Null:
  1.8014 +    break;
  1.8015 +  case eCSSUnit_Inherit:
  1.8016 +  case eCSSUnit_Unset:
  1.8017 +    canStoreInRuleTree = false;
  1.8018 +    quotes->CopyFrom(*parentQuotes);
  1.8019 +    break;
  1.8020 +  case eCSSUnit_Initial:
  1.8021 +    quotes->SetInitial();
  1.8022 +    break;
  1.8023 +  case eCSSUnit_None:
  1.8024 +    quotes->AllocateQuotes(0);
  1.8025 +    break;
  1.8026 +  case eCSSUnit_PairList:
  1.8027 +  case eCSSUnit_PairListDep: {
  1.8028 +    const nsCSSValuePairList* ourQuotes
  1.8029 +      = quotesValue->GetPairListValue();
  1.8030 +    nsAutoString buffer;
  1.8031 +    nsAutoString closeBuffer;
  1.8032 +    uint32_t count = ListLength(ourQuotes);
  1.8033 +    if (NS_FAILED(quotes->AllocateQuotes(count))) {
  1.8034 +      break;
  1.8035 +    }
  1.8036 +    count = 0;
  1.8037 +    while (ourQuotes) {
  1.8038 +      NS_ABORT_IF_FALSE(ourQuotes->mXValue.GetUnit() == eCSSUnit_String &&
  1.8039 +                        ourQuotes->mYValue.GetUnit() == eCSSUnit_String,
  1.8040 +                        "improper list contents for quotes");
  1.8041 +      ourQuotes->mXValue.GetStringValue(buffer);
  1.8042 +      ourQuotes->mYValue.GetStringValue(closeBuffer);
  1.8043 +      quotes->SetQuotesAt(count++, buffer, closeBuffer);
  1.8044 +      ourQuotes = ourQuotes->mNext;
  1.8045 +    }
  1.8046 +    break;
  1.8047 +  }
  1.8048 +  default:
  1.8049 +    NS_ABORT_IF_FALSE(false, "unexpected value unit");
  1.8050 +  }
  1.8051 +
  1.8052 +  COMPUTE_END_INHERITED(Quotes, quotes)
  1.8053 +}
  1.8054 +
  1.8055 +const void*
  1.8056 +nsRuleNode::ComputeXULData(void* aStartStruct,
  1.8057 +                           const nsRuleData* aRuleData,
  1.8058 +                           nsStyleContext* aContext,
  1.8059 +                           nsRuleNode* aHighestNode,
  1.8060 +                           const RuleDetail aRuleDetail,
  1.8061 +                           const bool aCanStoreInRuleTree)
  1.8062 +{
  1.8063 +  COMPUTE_START_RESET(XUL, (), xul, parentXUL)
  1.8064 +
  1.8065 +  // box-align: enum, inherit, initial
  1.8066 +  SetDiscrete(*aRuleData->ValueForBoxAlign(),
  1.8067 +              xul->mBoxAlign, canStoreInRuleTree,
  1.8068 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.8069 +              parentXUL->mBoxAlign,
  1.8070 +              NS_STYLE_BOX_ALIGN_STRETCH, 0, 0, 0, 0);
  1.8071 +
  1.8072 +  // box-direction: enum, inherit, initial
  1.8073 +  SetDiscrete(*aRuleData->ValueForBoxDirection(),
  1.8074 +              xul->mBoxDirection, canStoreInRuleTree,
  1.8075 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.8076 +              parentXUL->mBoxDirection,
  1.8077 +              NS_STYLE_BOX_DIRECTION_NORMAL, 0, 0, 0, 0);
  1.8078 +
  1.8079 +  // box-flex: factor, inherit
  1.8080 +  SetFactor(*aRuleData->ValueForBoxFlex(),
  1.8081 +            xul->mBoxFlex, canStoreInRuleTree,
  1.8082 +            parentXUL->mBoxFlex, 0.0f,
  1.8083 +            SETFCT_UNSET_INITIAL);
  1.8084 +
  1.8085 +  // box-orient: enum, inherit, initial
  1.8086 +  SetDiscrete(*aRuleData->ValueForBoxOrient(),
  1.8087 +              xul->mBoxOrient, canStoreInRuleTree,
  1.8088 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.8089 +              parentXUL->mBoxOrient,
  1.8090 +              NS_STYLE_BOX_ORIENT_HORIZONTAL, 0, 0, 0, 0);
  1.8091 +
  1.8092 +  // box-pack: enum, inherit, initial
  1.8093 +  SetDiscrete(*aRuleData->ValueForBoxPack(),
  1.8094 +              xul->mBoxPack, canStoreInRuleTree,
  1.8095 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.8096 +              parentXUL->mBoxPack,
  1.8097 +              NS_STYLE_BOX_PACK_START, 0, 0, 0, 0);
  1.8098 +
  1.8099 +  // box-ordinal-group: integer, inherit, initial
  1.8100 +  SetDiscrete(*aRuleData->ValueForBoxOrdinalGroup(),
  1.8101 +              xul->mBoxOrdinal, canStoreInRuleTree,
  1.8102 +              SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
  1.8103 +              parentXUL->mBoxOrdinal, 1,
  1.8104 +              0, 0, 0, 0);
  1.8105 +
  1.8106 +  const nsCSSValue* stackSizingValue = aRuleData->ValueForStackSizing();
  1.8107 +  if (eCSSUnit_Inherit == stackSizingValue->GetUnit()) {
  1.8108 +    canStoreInRuleTree = false;
  1.8109 +    xul->mStretchStack = parentXUL->mStretchStack;
  1.8110 +  } else if (eCSSUnit_Initial == stackSizingValue->GetUnit() ||
  1.8111 +             eCSSUnit_Unset == stackSizingValue->GetUnit()) {
  1.8112 +    xul->mStretchStack = true;
  1.8113 +  } else if (eCSSUnit_Enumerated == stackSizingValue->GetUnit()) {
  1.8114 +    xul->mStretchStack = stackSizingValue->GetIntValue() ==
  1.8115 +      NS_STYLE_STACK_SIZING_STRETCH_TO_FIT;
  1.8116 +  }
  1.8117 +
  1.8118 +  COMPUTE_END_RESET(XUL, xul)
  1.8119 +}
  1.8120 +
  1.8121 +const void*
  1.8122 +nsRuleNode::ComputeColumnData(void* aStartStruct,
  1.8123 +                              const nsRuleData* aRuleData,
  1.8124 +                              nsStyleContext* aContext,
  1.8125 +                              nsRuleNode* aHighestNode,
  1.8126 +                              const RuleDetail aRuleDetail,
  1.8127 +                              const bool aCanStoreInRuleTree)
  1.8128 +{
  1.8129 +  COMPUTE_START_RESET(Column, (mPresContext), column, parent)
  1.8130 +
  1.8131 +  // column-width: length, auto, inherit
  1.8132 +  SetCoord(*aRuleData->ValueForColumnWidth(),
  1.8133 +           column->mColumnWidth, parent->mColumnWidth,
  1.8134 +           SETCOORD_LAH | SETCOORD_INITIAL_AUTO |
  1.8135 +             SETCOORD_CALC_LENGTH_ONLY | SETCOORD_CALC_CLAMP_NONNEGATIVE |
  1.8136 +             SETCOORD_UNSET_INITIAL,
  1.8137 +           aContext, mPresContext, canStoreInRuleTree);
  1.8138 +
  1.8139 +  // column-gap: length, inherit, normal
  1.8140 +  SetCoord(*aRuleData->ValueForColumnGap(),
  1.8141 +           column->mColumnGap, parent->mColumnGap,
  1.8142 +           SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
  1.8143 +             SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INITIAL,
  1.8144 +           aContext, mPresContext, canStoreInRuleTree);
  1.8145 +  // clamp negative calc() to 0
  1.8146 +  if (column->mColumnGap.GetUnit() == eStyleUnit_Coord) {
  1.8147 +    column->mColumnGap.SetCoordValue(
  1.8148 +      std::max(column->mColumnGap.GetCoordValue(), 0));
  1.8149 +  }
  1.8150 +
  1.8151 +  // column-count: auto, integer, inherit
  1.8152 +  const nsCSSValue* columnCountValue = aRuleData->ValueForColumnCount();
  1.8153 +  if (eCSSUnit_Auto == columnCountValue->GetUnit() ||
  1.8154 +      eCSSUnit_Initial == columnCountValue->GetUnit() ||
  1.8155 +      eCSSUnit_Unset == columnCountValue->GetUnit()) {
  1.8156 +    column->mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
  1.8157 +  } else if (eCSSUnit_Integer == columnCountValue->GetUnit()) {
  1.8158 +    column->mColumnCount = columnCountValue->GetIntValue();
  1.8159 +    // Max kMaxColumnCount columns - wallpaper for bug 345583.
  1.8160 +    column->mColumnCount = std::min(column->mColumnCount,
  1.8161 +                                    nsStyleColumn::kMaxColumnCount);
  1.8162 +  } else if (eCSSUnit_Inherit == columnCountValue->GetUnit()) {
  1.8163 +    canStoreInRuleTree = false;
  1.8164 +    column->mColumnCount = parent->mColumnCount;
  1.8165 +  }
  1.8166 +
  1.8167 +  // column-rule-width: length, enum, inherit
  1.8168 +  const nsCSSValue& widthValue = *aRuleData->ValueForColumnRuleWidth();
  1.8169 +  if (eCSSUnit_Initial == widthValue.GetUnit() ||
  1.8170 +      eCSSUnit_Unset == widthValue.GetUnit()) {
  1.8171 +    column->SetColumnRuleWidth(
  1.8172 +        (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
  1.8173 +  }
  1.8174 +  else if (eCSSUnit_Enumerated == widthValue.GetUnit()) {
  1.8175 +    NS_ASSERTION(widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
  1.8176 +                 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
  1.8177 +                 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
  1.8178 +                 "Unexpected enum value");
  1.8179 +    column->SetColumnRuleWidth(
  1.8180 +        (mPresContext->GetBorderWidthTable())[widthValue.GetIntValue()]);
  1.8181 +  }
  1.8182 +  else if (eCSSUnit_Inherit == widthValue.GetUnit()) {
  1.8183 +    column->SetColumnRuleWidth(parent->GetComputedColumnRuleWidth());
  1.8184 +    canStoreInRuleTree = false;
  1.8185 +  }
  1.8186 +  else if (widthValue.IsLengthUnit() || widthValue.IsCalcUnit()) {
  1.8187 +    nscoord len =
  1.8188 +      CalcLength(widthValue, aContext, mPresContext, canStoreInRuleTree);
  1.8189 +    if (len < 0) {
  1.8190 +      // FIXME: This is untested (by test_value_storage.html) for
  1.8191 +      // column-rule-width since it gets covered up by the border
  1.8192 +      // rounding code.
  1.8193 +      NS_ASSERTION(widthValue.IsCalcUnit(),
  1.8194 +                   "parser should have rejected negative length");
  1.8195 +      len = 0;
  1.8196 +    }
  1.8197 +    column->SetColumnRuleWidth(len);
  1.8198 +  }
  1.8199 +
  1.8200 +  // column-rule-style: enum, inherit
  1.8201 +  const nsCSSValue& styleValue = *aRuleData->ValueForColumnRuleStyle();
  1.8202 +  NS_ABORT_IF_FALSE(eCSSUnit_None != styleValue.GetUnit(),
  1.8203 +                    "'none' should be handled as enumerated value");
  1.8204 +  if (eCSSUnit_Enumerated == styleValue.GetUnit()) {
  1.8205 +    column->mColumnRuleStyle = styleValue.GetIntValue();
  1.8206 +  }
  1.8207 +  else if (eCSSUnit_Initial == styleValue.GetUnit() ||
  1.8208 +           eCSSUnit_Unset == styleValue.GetUnit()) {
  1.8209 +    column->mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
  1.8210 +  }
  1.8211 +  else if (eCSSUnit_Inherit == styleValue.GetUnit()) {
  1.8212 +    canStoreInRuleTree = false;
  1.8213 +    column->mColumnRuleStyle = parent->mColumnRuleStyle;
  1.8214 +  }
  1.8215 +
  1.8216 +  // column-rule-color: color, inherit
  1.8217 +  const nsCSSValue& colorValue = *aRuleData->ValueForColumnRuleColor();
  1.8218 +  if (eCSSUnit_Inherit == colorValue.GetUnit()) {
  1.8219 +    canStoreInRuleTree = false;
  1.8220 +    column->mColumnRuleColorIsForeground = false;
  1.8221 +    if (parent->mColumnRuleColorIsForeground) {
  1.8222 +      if (parentContext) {
  1.8223 +        column->mColumnRuleColor = parentContext->StyleColor()->mColor;
  1.8224 +      } else {
  1.8225 +        nsStyleColor defaultColumnRuleColor(mPresContext);
  1.8226 +        column->mColumnRuleColor = defaultColumnRuleColor.mColor;
  1.8227 +      }
  1.8228 +    } else {
  1.8229 +      column->mColumnRuleColor = parent->mColumnRuleColor;
  1.8230 +    }
  1.8231 +  }
  1.8232 +  else if (eCSSUnit_Initial == colorValue.GetUnit() ||
  1.8233 +           eCSSUnit_Unset == colorValue.GetUnit() ||
  1.8234 +           eCSSUnit_Enumerated == colorValue.GetUnit()) {
  1.8235 +    column->mColumnRuleColorIsForeground = true;
  1.8236 +  }
  1.8237 +  else if (SetColor(colorValue, 0, mPresContext, aContext,
  1.8238 +                    column->mColumnRuleColor, canStoreInRuleTree)) {
  1.8239 +    column->mColumnRuleColorIsForeground = false;
  1.8240 +  }
  1.8241 +
  1.8242 +  // column-fill: enum
  1.8243 +  SetDiscrete(*aRuleData->ValueForColumnFill(),
  1.8244 +                column->mColumnFill, canStoreInRuleTree,
  1.8245 +                SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.8246 +                parent->mColumnFill,
  1.8247 +                NS_STYLE_COLUMN_FILL_BALANCE,
  1.8248 +                0, 0, 0, 0);
  1.8249 +
  1.8250 +  COMPUTE_END_RESET(Column, column)
  1.8251 +}
  1.8252 +
  1.8253 +static void
  1.8254 +SetSVGPaint(const nsCSSValue& aValue, const nsStyleSVGPaint& parentPaint,
  1.8255 +            nsPresContext* aPresContext, nsStyleContext *aContext,
  1.8256 +            nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
  1.8257 +            bool& aCanStoreInRuleTree)
  1.8258 +{
  1.8259 +  nscolor color;
  1.8260 +
  1.8261 +  if (aValue.GetUnit() == eCSSUnit_Inherit ||
  1.8262 +      aValue.GetUnit() == eCSSUnit_Unset) {
  1.8263 +    aResult = parentPaint;
  1.8264 +    aCanStoreInRuleTree = false;
  1.8265 +  } else if (aValue.GetUnit() == eCSSUnit_None) {
  1.8266 +    aResult.SetType(eStyleSVGPaintType_None);
  1.8267 +  } else if (aValue.GetUnit() == eCSSUnit_Initial) {
  1.8268 +    aResult.SetType(aInitialPaintType);
  1.8269 +    aResult.mPaint.mColor = NS_RGB(0, 0, 0);
  1.8270 +    aResult.mFallbackColor = NS_RGB(0, 0, 0);
  1.8271 +  } else if (SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aContext,
  1.8272 +                      color, aCanStoreInRuleTree)) {
  1.8273 +    aResult.SetType(eStyleSVGPaintType_Color);
  1.8274 +    aResult.mPaint.mColor = color;
  1.8275 +  } else if (aValue.GetUnit() == eCSSUnit_Pair) {
  1.8276 +    const nsCSSValuePair& pair = aValue.GetPairValue();
  1.8277 +
  1.8278 +    if (pair.mXValue.GetUnit() == eCSSUnit_URL) {
  1.8279 +      aResult.SetType(eStyleSVGPaintType_Server);
  1.8280 +      aResult.mPaint.mPaintServer = pair.mXValue.GetURLValue();
  1.8281 +      NS_IF_ADDREF(aResult.mPaint.mPaintServer);
  1.8282 +    } else if (pair.mXValue.GetUnit() == eCSSUnit_Enumerated) {
  1.8283 +
  1.8284 +      switch (pair.mXValue.GetIntValue()) {
  1.8285 +      case NS_COLOR_CONTEXT_FILL:
  1.8286 +        aResult.SetType(eStyleSVGPaintType_ContextFill);
  1.8287 +        break;
  1.8288 +      case NS_COLOR_CONTEXT_STROKE:
  1.8289 +        aResult.SetType(eStyleSVGPaintType_ContextStroke);
  1.8290 +        break;
  1.8291 +      default:
  1.8292 +        NS_NOTREACHED("unknown keyword as paint server value");
  1.8293 +      }
  1.8294 +
  1.8295 +    } else {
  1.8296 +      NS_NOTREACHED("malformed paint server value");
  1.8297 +    }
  1.8298 +
  1.8299 +    if (pair.mYValue.GetUnit() == eCSSUnit_None) {
  1.8300 +      aResult.mFallbackColor = NS_RGBA(0, 0, 0, 0);
  1.8301 +    } else {
  1.8302 +      NS_ABORT_IF_FALSE(pair.mYValue.GetUnit() != eCSSUnit_Inherit,
  1.8303 +                        "cannot inherit fallback colour");
  1.8304 +      SetColor(pair.mYValue, NS_RGB(0, 0, 0), aPresContext, aContext,
  1.8305 +               aResult.mFallbackColor, aCanStoreInRuleTree);
  1.8306 +    }
  1.8307 +  } else {
  1.8308 +    NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Null,
  1.8309 +                      "malformed paint server value");
  1.8310 +  }
  1.8311 +}
  1.8312 +
  1.8313 +static void
  1.8314 +SetSVGOpacity(const nsCSSValue& aValue,
  1.8315 +              float& aOpacityField, nsStyleSVGOpacitySource& aOpacityTypeField,
  1.8316 +              bool& aCanStoreInRuleTree,
  1.8317 +              float aParentOpacity, nsStyleSVGOpacitySource aParentOpacityType)
  1.8318 +{
  1.8319 +  if (eCSSUnit_Enumerated == aValue.GetUnit()) {
  1.8320 +    switch (aValue.GetIntValue()) {
  1.8321 +    case NS_STYLE_CONTEXT_FILL_OPACITY:
  1.8322 +      aOpacityTypeField = eStyleSVGOpacitySource_ContextFillOpacity;
  1.8323 +      break;
  1.8324 +    case NS_STYLE_CONTEXT_STROKE_OPACITY:
  1.8325 +      aOpacityTypeField = eStyleSVGOpacitySource_ContextStrokeOpacity;
  1.8326 +      break;
  1.8327 +    default:
  1.8328 +      NS_NOTREACHED("SetSVGOpacity: Unknown keyword");
  1.8329 +    }
  1.8330 +    // Fall back on fully opaque
  1.8331 +    aOpacityField = 1.0f;
  1.8332 +  } else if (eCSSUnit_Inherit == aValue.GetUnit() ||
  1.8333 +             eCSSUnit_Unset == aValue.GetUnit()) {
  1.8334 +    aCanStoreInRuleTree = false;
  1.8335 +    aOpacityField = aParentOpacity;
  1.8336 +    aOpacityTypeField = aParentOpacityType;
  1.8337 +  } else if (eCSSUnit_Null != aValue.GetUnit()) {
  1.8338 +    SetFactor(aValue, aOpacityField, aCanStoreInRuleTree,
  1.8339 +              aParentOpacity, 1.0f, SETFCT_OPACITY);
  1.8340 +    aOpacityTypeField = eStyleSVGOpacitySource_Normal;
  1.8341 +  }
  1.8342 +}
  1.8343 +
  1.8344 +const void*
  1.8345 +nsRuleNode::ComputeSVGData(void* aStartStruct,
  1.8346 +                           const nsRuleData* aRuleData,
  1.8347 +                           nsStyleContext* aContext,
  1.8348 +                           nsRuleNode* aHighestNode,
  1.8349 +                           const RuleDetail aRuleDetail,
  1.8350 +                           const bool aCanStoreInRuleTree)
  1.8351 +{
  1.8352 +  COMPUTE_START_INHERITED(SVG, (), svg, parentSVG)
  1.8353 +
  1.8354 +  // clip-rule: enum, inherit, initial
  1.8355 +  SetDiscrete(*aRuleData->ValueForClipRule(),
  1.8356 +              svg->mClipRule, canStoreInRuleTree,
  1.8357 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.8358 +              parentSVG->mClipRule,
  1.8359 +              NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
  1.8360 +
  1.8361 +  // color-interpolation: enum, inherit, initial
  1.8362 +  SetDiscrete(*aRuleData->ValueForColorInterpolation(),
  1.8363 +              svg->mColorInterpolation, canStoreInRuleTree,
  1.8364 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.8365 +              parentSVG->mColorInterpolation,
  1.8366 +              NS_STYLE_COLOR_INTERPOLATION_SRGB, 0, 0, 0, 0);
  1.8367 +
  1.8368 +  // color-interpolation-filters: enum, inherit, initial
  1.8369 +  SetDiscrete(*aRuleData->ValueForColorInterpolationFilters(),
  1.8370 +              svg->mColorInterpolationFilters, canStoreInRuleTree,
  1.8371 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.8372 +              parentSVG->mColorInterpolationFilters,
  1.8373 +              NS_STYLE_COLOR_INTERPOLATION_LINEARRGB, 0, 0, 0, 0);
  1.8374 +
  1.8375 +  // fill:
  1.8376 +  SetSVGPaint(*aRuleData->ValueForFill(),
  1.8377 +              parentSVG->mFill, mPresContext, aContext,
  1.8378 +              svg->mFill, eStyleSVGPaintType_Color, canStoreInRuleTree);
  1.8379 +
  1.8380 +  // fill-opacity: factor, inherit, initial,
  1.8381 +  // context-fill-opacity, context-stroke-opacity
  1.8382 +  nsStyleSVGOpacitySource contextFillOpacity = svg->mFillOpacitySource;
  1.8383 +  SetSVGOpacity(*aRuleData->ValueForFillOpacity(),
  1.8384 +                svg->mFillOpacity, contextFillOpacity, canStoreInRuleTree,
  1.8385 +                parentSVG->mFillOpacity, parentSVG->mFillOpacitySource);
  1.8386 +  svg->mFillOpacitySource = contextFillOpacity;
  1.8387 +
  1.8388 +  // fill-rule: enum, inherit, initial
  1.8389 +  SetDiscrete(*aRuleData->ValueForFillRule(),
  1.8390 +              svg->mFillRule, canStoreInRuleTree,
  1.8391 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.8392 +              parentSVG->mFillRule,
  1.8393 +              NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
  1.8394 +
  1.8395 +  // image-rendering: enum, inherit
  1.8396 +  SetDiscrete(*aRuleData->ValueForImageRendering(),
  1.8397 +              svg->mImageRendering, canStoreInRuleTree,
  1.8398 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.8399 +              parentSVG->mImageRendering,
  1.8400 +              NS_STYLE_IMAGE_RENDERING_AUTO, 0, 0, 0, 0);
  1.8401 +
  1.8402 +  // marker-end: url, none, inherit
  1.8403 +  const nsCSSValue* markerEndValue = aRuleData->ValueForMarkerEnd();
  1.8404 +  if (eCSSUnit_URL == markerEndValue->GetUnit()) {
  1.8405 +    svg->mMarkerEnd = markerEndValue->GetURLValue();
  1.8406 +  } else if (eCSSUnit_None == markerEndValue->GetUnit() ||
  1.8407 +             eCSSUnit_Initial == markerEndValue->GetUnit()) {
  1.8408 +    svg->mMarkerEnd = nullptr;
  1.8409 +  } else if (eCSSUnit_Inherit == markerEndValue->GetUnit() ||
  1.8410 +             eCSSUnit_Unset == markerEndValue->GetUnit()) {
  1.8411 +    canStoreInRuleTree = false;
  1.8412 +    svg->mMarkerEnd = parentSVG->mMarkerEnd;
  1.8413 +  }
  1.8414 +
  1.8415 +  // marker-mid: url, none, inherit
  1.8416 +  const nsCSSValue* markerMidValue = aRuleData->ValueForMarkerMid();
  1.8417 +  if (eCSSUnit_URL == markerMidValue->GetUnit()) {
  1.8418 +    svg->mMarkerMid = markerMidValue->GetURLValue();
  1.8419 +  } else if (eCSSUnit_None == markerMidValue->GetUnit() ||
  1.8420 +             eCSSUnit_Initial == markerMidValue->GetUnit()) {
  1.8421 +    svg->mMarkerMid = nullptr;
  1.8422 +  } else if (eCSSUnit_Inherit == markerMidValue->GetUnit() ||
  1.8423 +             eCSSUnit_Unset == markerMidValue->GetUnit()) {
  1.8424 +    canStoreInRuleTree = false;
  1.8425 +    svg->mMarkerMid = parentSVG->mMarkerMid;
  1.8426 +  }
  1.8427 +
  1.8428 +  // marker-start: url, none, inherit
  1.8429 +  const nsCSSValue* markerStartValue = aRuleData->ValueForMarkerStart();
  1.8430 +  if (eCSSUnit_URL == markerStartValue->GetUnit()) {
  1.8431 +    svg->mMarkerStart = markerStartValue->GetURLValue();
  1.8432 +  } else if (eCSSUnit_None == markerStartValue->GetUnit() ||
  1.8433 +             eCSSUnit_Initial == markerStartValue->GetUnit()) {
  1.8434 +    svg->mMarkerStart = nullptr;
  1.8435 +  } else if (eCSSUnit_Inherit == markerStartValue->GetUnit() ||
  1.8436 +             eCSSUnit_Unset == markerStartValue->GetUnit()) {
  1.8437 +    canStoreInRuleTree = false;
  1.8438 +    svg->mMarkerStart = parentSVG->mMarkerStart;
  1.8439 +  }
  1.8440 +
  1.8441 +  // paint-order: enum (bit field), inherit, initial
  1.8442 +  const nsCSSValue* paintOrderValue = aRuleData->ValueForPaintOrder();
  1.8443 +  switch (paintOrderValue->GetUnit()) {
  1.8444 +    case eCSSUnit_Null:
  1.8445 +      break;
  1.8446 +
  1.8447 +    case eCSSUnit_Enumerated:
  1.8448 +      static_assert
  1.8449 +        (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <= 8,
  1.8450 +         "SVGStyleStruct::mPaintOrder not big enough");
  1.8451 +      svg->mPaintOrder = static_cast<uint8_t>(paintOrderValue->GetIntValue());
  1.8452 +      break;
  1.8453 +
  1.8454 +    case eCSSUnit_Inherit:
  1.8455 +    case eCSSUnit_Unset:
  1.8456 +      canStoreInRuleTree = false;
  1.8457 +      svg->mPaintOrder = parentSVG->mPaintOrder;
  1.8458 +      break;
  1.8459 +
  1.8460 +    case eCSSUnit_Initial:
  1.8461 +      svg->mPaintOrder = NS_STYLE_PAINT_ORDER_NORMAL;
  1.8462 +      break;
  1.8463 +
  1.8464 +    default:
  1.8465 +      NS_NOTREACHED("unexpected unit");
  1.8466 +  }
  1.8467 +
  1.8468 +  // shape-rendering: enum, inherit
  1.8469 +  SetDiscrete(*aRuleData->ValueForShapeRendering(),
  1.8470 +              svg->mShapeRendering, canStoreInRuleTree,
  1.8471 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.8472 +              parentSVG->mShapeRendering,
  1.8473 +              NS_STYLE_SHAPE_RENDERING_AUTO, 0, 0, 0, 0);
  1.8474 +
  1.8475 +  // stroke:
  1.8476 +  SetSVGPaint(*aRuleData->ValueForStroke(),
  1.8477 +              parentSVG->mStroke, mPresContext, aContext,
  1.8478 +              svg->mStroke, eStyleSVGPaintType_None, canStoreInRuleTree);
  1.8479 +
  1.8480 +  // stroke-dasharray: <dasharray>, none, inherit, context-value
  1.8481 +  const nsCSSValue* strokeDasharrayValue = aRuleData->ValueForStrokeDasharray();
  1.8482 +  switch (strokeDasharrayValue->GetUnit()) {
  1.8483 +  case eCSSUnit_Null:
  1.8484 +    break;
  1.8485 +
  1.8486 +  case eCSSUnit_Inherit:
  1.8487 +  case eCSSUnit_Unset:
  1.8488 +    canStoreInRuleTree = false;
  1.8489 +    svg->mStrokeDasharrayFromObject = parentSVG->mStrokeDasharrayFromObject;
  1.8490 +    // only do the copy if weren't already set up by the copy constructor
  1.8491 +    // FIXME Bug 389408: This is broken when aStartStruct is non-null!
  1.8492 +    if (!svg->mStrokeDasharray) {
  1.8493 +      svg->mStrokeDasharrayLength = parentSVG->mStrokeDasharrayLength;
  1.8494 +      if (svg->mStrokeDasharrayLength) {
  1.8495 +        svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
  1.8496 +        if (svg->mStrokeDasharray)
  1.8497 +          memcpy(svg->mStrokeDasharray,
  1.8498 +                 parentSVG->mStrokeDasharray,
  1.8499 +                 svg->mStrokeDasharrayLength * sizeof(nsStyleCoord));
  1.8500 +        else
  1.8501 +          svg->mStrokeDasharrayLength = 0;
  1.8502 +      }
  1.8503 +    }
  1.8504 +    break;
  1.8505 +
  1.8506 +  case eCSSUnit_Enumerated:
  1.8507 +    NS_ABORT_IF_FALSE(strokeDasharrayValue->GetIntValue() ==
  1.8508 +                            NS_STYLE_STROKE_PROP_CONTEXT_VALUE,
  1.8509 +                      "Unknown keyword for stroke-dasharray");
  1.8510 +    svg->mStrokeDasharrayFromObject = true;
  1.8511 +    delete [] svg->mStrokeDasharray;
  1.8512 +    svg->mStrokeDasharray = nullptr;
  1.8513 +    svg->mStrokeDasharrayLength = 0;
  1.8514 +    break;
  1.8515 +
  1.8516 +  case eCSSUnit_Initial:
  1.8517 +  case eCSSUnit_None:
  1.8518 +    svg->mStrokeDasharrayFromObject = false;
  1.8519 +    delete [] svg->mStrokeDasharray;
  1.8520 +    svg->mStrokeDasharray = nullptr;
  1.8521 +    svg->mStrokeDasharrayLength = 0;
  1.8522 +    break;
  1.8523 +
  1.8524 +  case eCSSUnit_List:
  1.8525 +  case eCSSUnit_ListDep: {
  1.8526 +    svg->mStrokeDasharrayFromObject = false;
  1.8527 +    delete [] svg->mStrokeDasharray;
  1.8528 +    svg->mStrokeDasharray = nullptr;
  1.8529 +    svg->mStrokeDasharrayLength = 0;
  1.8530 +
  1.8531 +    // count number of values
  1.8532 +    const nsCSSValueList *value = strokeDasharrayValue->GetListValue();
  1.8533 +    svg->mStrokeDasharrayLength = ListLength(value);
  1.8534 +
  1.8535 +    NS_ASSERTION(svg->mStrokeDasharrayLength != 0, "no dasharray items");
  1.8536 +
  1.8537 +    svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
  1.8538 +
  1.8539 +    if (svg->mStrokeDasharray) {
  1.8540 +      uint32_t i = 0;
  1.8541 +      while (nullptr != value) {
  1.8542 +        SetCoord(value->mValue,
  1.8543 +                 svg->mStrokeDasharray[i++], nsStyleCoord(),
  1.8544 +                 SETCOORD_LP | SETCOORD_FACTOR,
  1.8545 +                 aContext, mPresContext, canStoreInRuleTree);
  1.8546 +        value = value->mNext;
  1.8547 +      }
  1.8548 +    } else {
  1.8549 +      svg->mStrokeDasharrayLength = 0;
  1.8550 +    }
  1.8551 +    break;
  1.8552 +  }
  1.8553 +
  1.8554 +  default:
  1.8555 +    NS_ABORT_IF_FALSE(false, "unrecognized dasharray unit");
  1.8556 +  }
  1.8557 +
  1.8558 +  // stroke-dashoffset: <dashoffset>, inherit
  1.8559 +  const nsCSSValue *strokeDashoffsetValue =
  1.8560 +    aRuleData->ValueForStrokeDashoffset();
  1.8561 +  svg->mStrokeDashoffsetFromObject =
  1.8562 +    strokeDashoffsetValue->GetUnit() == eCSSUnit_Enumerated &&
  1.8563 +    strokeDashoffsetValue->GetIntValue() == NS_STYLE_STROKE_PROP_CONTEXT_VALUE;
  1.8564 +  if (svg->mStrokeDashoffsetFromObject) {
  1.8565 +    svg->mStrokeDashoffset.SetCoordValue(0);
  1.8566 +  } else {
  1.8567 +    SetCoord(*aRuleData->ValueForStrokeDashoffset(),
  1.8568 +             svg->mStrokeDashoffset, parentSVG->mStrokeDashoffset,
  1.8569 +             SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_INITIAL_ZERO |
  1.8570 +               SETCOORD_UNSET_INHERIT,
  1.8571 +             aContext, mPresContext, canStoreInRuleTree);
  1.8572 +  }
  1.8573 +
  1.8574 +  // stroke-linecap: enum, inherit, initial
  1.8575 +  SetDiscrete(*aRuleData->ValueForStrokeLinecap(),
  1.8576 +              svg->mStrokeLinecap, canStoreInRuleTree,
  1.8577 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.8578 +              parentSVG->mStrokeLinecap,
  1.8579 +              NS_STYLE_STROKE_LINECAP_BUTT, 0, 0, 0, 0);
  1.8580 +
  1.8581 +  // stroke-linejoin: enum, inherit, initial
  1.8582 +  SetDiscrete(*aRuleData->ValueForStrokeLinejoin(),
  1.8583 +              svg->mStrokeLinejoin, canStoreInRuleTree,
  1.8584 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.8585 +              parentSVG->mStrokeLinejoin,
  1.8586 +              NS_STYLE_STROKE_LINEJOIN_MITER, 0, 0, 0, 0);
  1.8587 +
  1.8588 +  // stroke-miterlimit: <miterlimit>, inherit
  1.8589 +  SetFactor(*aRuleData->ValueForStrokeMiterlimit(),
  1.8590 +            svg->mStrokeMiterlimit,
  1.8591 +            canStoreInRuleTree,
  1.8592 +            parentSVG->mStrokeMiterlimit, 4.0f,
  1.8593 +            SETFCT_UNSET_INHERIT);
  1.8594 +
  1.8595 +  // stroke-opacity:
  1.8596 +  nsStyleSVGOpacitySource contextStrokeOpacity = svg->mStrokeOpacitySource;
  1.8597 +  SetSVGOpacity(*aRuleData->ValueForStrokeOpacity(),
  1.8598 +                svg->mStrokeOpacity, contextStrokeOpacity, canStoreInRuleTree,
  1.8599 +                parentSVG->mStrokeOpacity, parentSVG->mStrokeOpacitySource);
  1.8600 +  svg->mStrokeOpacitySource = contextStrokeOpacity;
  1.8601 +
  1.8602 +  // stroke-width:
  1.8603 +  const nsCSSValue* strokeWidthValue = aRuleData->ValueForStrokeWidth();
  1.8604 +  switch (strokeWidthValue->GetUnit()) {
  1.8605 +  case eCSSUnit_Enumerated:
  1.8606 +    NS_ABORT_IF_FALSE(strokeWidthValue->GetIntValue() ==
  1.8607 +                        NS_STYLE_STROKE_PROP_CONTEXT_VALUE,
  1.8608 +                      "Unrecognized keyword for stroke-width");
  1.8609 +    svg->mStrokeWidthFromObject = true;
  1.8610 +    svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
  1.8611 +    break;
  1.8612 +
  1.8613 +  case eCSSUnit_Initial:
  1.8614 +    svg->mStrokeWidthFromObject = false;
  1.8615 +    svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
  1.8616 +    break;
  1.8617 +
  1.8618 +  default:
  1.8619 +    svg->mStrokeWidthFromObject = false;
  1.8620 +    SetCoord(*strokeWidthValue,
  1.8621 +             svg->mStrokeWidth, parentSVG->mStrokeWidth,
  1.8622 +             SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_UNSET_INHERIT,
  1.8623 +             aContext, mPresContext, canStoreInRuleTree);
  1.8624 +  }
  1.8625 +
  1.8626 +  // text-anchor: enum, inherit, initial
  1.8627 +  SetDiscrete(*aRuleData->ValueForTextAnchor(),
  1.8628 +              svg->mTextAnchor, canStoreInRuleTree,
  1.8629 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.8630 +              parentSVG->mTextAnchor,
  1.8631 +              NS_STYLE_TEXT_ANCHOR_START, 0, 0, 0, 0);
  1.8632 +
  1.8633 +  // text-rendering: enum, inherit, initial
  1.8634 +  SetDiscrete(*aRuleData->ValueForTextRendering(),
  1.8635 +              svg->mTextRendering, canStoreInRuleTree,
  1.8636 +              SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
  1.8637 +              parentSVG->mTextRendering,
  1.8638 +              NS_STYLE_TEXT_RENDERING_AUTO, 0, 0, 0, 0);
  1.8639 +
  1.8640 +  COMPUTE_END_INHERITED(SVG, svg)
  1.8641 +}
  1.8642 +
  1.8643 +// Returns true if the nsStyleFilter was successfully set using the nsCSSValue.
  1.8644 +bool
  1.8645 +nsRuleNode::SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
  1.8646 +                                     const nsCSSValue& aValue,
  1.8647 +                                     nsStyleContext* aStyleContext,
  1.8648 +                                     nsPresContext* aPresContext,
  1.8649 +                                     bool& aCanStoreInRuleTree)
  1.8650 +{
  1.8651 +  nsCSSUnit unit = aValue.GetUnit();
  1.8652 +  if (unit == eCSSUnit_URL) {
  1.8653 +    nsIURI* url = aValue.GetURLValue();
  1.8654 +    if (!url)
  1.8655 +      return false;
  1.8656 +    aStyleFilter->SetURL(url);
  1.8657 +    return true;
  1.8658 +  }
  1.8659 +
  1.8660 +  NS_ABORT_IF_FALSE(unit == eCSSUnit_Function, "expected a filter function");
  1.8661 +
  1.8662 +  nsCSSValue::Array* filterFunction = aValue.GetArrayValue();
  1.8663 +  nsCSSKeyword functionName =
  1.8664 +    (nsCSSKeyword)filterFunction->Item(0).GetIntValue();
  1.8665 +
  1.8666 +  int32_t type;
  1.8667 +  DebugOnly<bool> foundKeyword =
  1.8668 +    nsCSSProps::FindKeyword(functionName,
  1.8669 +                            nsCSSProps::kFilterFunctionKTable,
  1.8670 +                            type);
  1.8671 +  NS_ABORT_IF_FALSE(foundKeyword, "unknown filter type");
  1.8672 +  if (type == NS_STYLE_FILTER_DROP_SHADOW) {
  1.8673 +    nsRefPtr<nsCSSShadowArray> shadowArray = GetShadowData(
  1.8674 +      filterFunction->Item(1).GetListValue(),
  1.8675 +      aStyleContext,
  1.8676 +      false,
  1.8677 +      aCanStoreInRuleTree);
  1.8678 +    aStyleFilter->SetDropShadow(shadowArray);
  1.8679 +    return true;
  1.8680 +  }
  1.8681 +
  1.8682 +  int32_t mask = SETCOORD_PERCENT | SETCOORD_FACTOR;
  1.8683 +  if (type == NS_STYLE_FILTER_BLUR) {
  1.8684 +    mask = SETCOORD_LENGTH | SETCOORD_STORE_CALC;
  1.8685 +  } else if (type == NS_STYLE_FILTER_HUE_ROTATE) {
  1.8686 +    mask = SETCOORD_ANGLE;
  1.8687 +  }
  1.8688 +
  1.8689 +  NS_ABORT_IF_FALSE(filterFunction->Count() == 2,
  1.8690 +                    "all filter functions should have "
  1.8691 +                    "exactly one argument");
  1.8692 +
  1.8693 +  nsCSSValue& arg = filterFunction->Item(1);
  1.8694 +  nsStyleCoord filterParameter;
  1.8695 +  DebugOnly<bool> didSetCoord = SetCoord(arg, filterParameter,
  1.8696 +                                         nsStyleCoord(), mask,
  1.8697 +                                         aStyleContext, aPresContext,
  1.8698 +                                         aCanStoreInRuleTree);
  1.8699 +  aStyleFilter->SetFilterParameter(filterParameter, type);
  1.8700 +  NS_ABORT_IF_FALSE(didSetCoord, "unexpected unit");
  1.8701 +  return true;
  1.8702 +}
  1.8703 +
  1.8704 +const void*
  1.8705 +nsRuleNode::ComputeSVGResetData(void* aStartStruct,
  1.8706 +                                const nsRuleData* aRuleData,
  1.8707 +                                nsStyleContext* aContext,
  1.8708 +                                nsRuleNode* aHighestNode,
  1.8709 +                                const RuleDetail aRuleDetail,
  1.8710 +                                const bool aCanStoreInRuleTree)
  1.8711 +{
  1.8712 +  COMPUTE_START_RESET(SVGReset, (), svgReset, parentSVGReset)
  1.8713 +
  1.8714 +  // stop-color:
  1.8715 +  const nsCSSValue* stopColorValue = aRuleData->ValueForStopColor();
  1.8716 +  if (eCSSUnit_Initial == stopColorValue->GetUnit() ||
  1.8717 +      eCSSUnit_Unset == stopColorValue->GetUnit()) {
  1.8718 +    svgReset->mStopColor = NS_RGB(0, 0, 0);
  1.8719 +  } else {
  1.8720 +    SetColor(*stopColorValue, parentSVGReset->mStopColor,
  1.8721 +             mPresContext, aContext, svgReset->mStopColor, canStoreInRuleTree);
  1.8722 +  }
  1.8723 +
  1.8724 +  // flood-color:
  1.8725 +  const nsCSSValue* floodColorValue = aRuleData->ValueForFloodColor();
  1.8726 +  if (eCSSUnit_Initial == floodColorValue->GetUnit() ||
  1.8727 +      eCSSUnit_Unset == floodColorValue->GetUnit()) {
  1.8728 +    svgReset->mFloodColor = NS_RGB(0, 0, 0);
  1.8729 +  } else {
  1.8730 +    SetColor(*floodColorValue, parentSVGReset->mFloodColor,
  1.8731 +             mPresContext, aContext, svgReset->mFloodColor, canStoreInRuleTree);
  1.8732 +  }
  1.8733 +
  1.8734 +  // lighting-color:
  1.8735 +  const nsCSSValue* lightingColorValue = aRuleData->ValueForLightingColor();
  1.8736 +  if (eCSSUnit_Initial == lightingColorValue->GetUnit() ||
  1.8737 +      eCSSUnit_Unset == lightingColorValue->GetUnit()) {
  1.8738 +    svgReset->mLightingColor = NS_RGB(255, 255, 255);
  1.8739 +  } else {
  1.8740 +    SetColor(*lightingColorValue, parentSVGReset->mLightingColor,
  1.8741 +             mPresContext, aContext, svgReset->mLightingColor,
  1.8742 +             canStoreInRuleTree);
  1.8743 +  }
  1.8744 +
  1.8745 +  // clip-path: url, none, inherit
  1.8746 +  const nsCSSValue* clipPathValue = aRuleData->ValueForClipPath();
  1.8747 +  if (eCSSUnit_URL == clipPathValue->GetUnit()) {
  1.8748 +    svgReset->mClipPath = clipPathValue->GetURLValue();
  1.8749 +  } else if (eCSSUnit_None == clipPathValue->GetUnit() ||
  1.8750 +             eCSSUnit_Initial == clipPathValue->GetUnit() ||
  1.8751 +             eCSSUnit_Unset == clipPathValue->GetUnit()) {
  1.8752 +    svgReset->mClipPath = nullptr;
  1.8753 +  } else if (eCSSUnit_Inherit == clipPathValue->GetUnit()) {
  1.8754 +    canStoreInRuleTree = false;
  1.8755 +    svgReset->mClipPath = parentSVGReset->mClipPath;
  1.8756 +  }
  1.8757 +
  1.8758 +  // stop-opacity:
  1.8759 +  SetFactor(*aRuleData->ValueForStopOpacity(),
  1.8760 +            svgReset->mStopOpacity, canStoreInRuleTree,
  1.8761 +            parentSVGReset->mStopOpacity, 1.0f,
  1.8762 +            SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
  1.8763 +
  1.8764 +  // flood-opacity:
  1.8765 +  SetFactor(*aRuleData->ValueForFloodOpacity(),
  1.8766 +            svgReset->mFloodOpacity, canStoreInRuleTree,
  1.8767 +            parentSVGReset->mFloodOpacity, 1.0f,
  1.8768 +            SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
  1.8769 +
  1.8770 +  // dominant-baseline: enum, inherit, initial
  1.8771 +  SetDiscrete(*aRuleData->ValueForDominantBaseline(),
  1.8772 +              svgReset->mDominantBaseline,
  1.8773 +              canStoreInRuleTree,
  1.8774 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.8775 +              parentSVGReset->mDominantBaseline,
  1.8776 +              NS_STYLE_DOMINANT_BASELINE_AUTO, 0, 0, 0, 0);
  1.8777 +
  1.8778 +  // vector-effect: enum, inherit, initial
  1.8779 +  SetDiscrete(*aRuleData->ValueForVectorEffect(),
  1.8780 +              svgReset->mVectorEffect,
  1.8781 +              canStoreInRuleTree,
  1.8782 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.8783 +              parentSVGReset->mVectorEffect,
  1.8784 +              NS_STYLE_VECTOR_EFFECT_NONE, 0, 0, 0, 0);
  1.8785 +
  1.8786 +  // filter: url, none, inherit
  1.8787 +  const nsCSSValue* filterValue = aRuleData->ValueForFilter();
  1.8788 +  switch (filterValue->GetUnit()) {
  1.8789 +    case eCSSUnit_Null:
  1.8790 +      break;
  1.8791 +    case eCSSUnit_None:
  1.8792 +    case eCSSUnit_Initial:
  1.8793 +    case eCSSUnit_Unset:
  1.8794 +      svgReset->mFilters.Clear();
  1.8795 +      break;
  1.8796 +    case eCSSUnit_Inherit:
  1.8797 +      canStoreInRuleTree = false;
  1.8798 +      svgReset->mFilters = parentSVGReset->mFilters;
  1.8799 +      break;
  1.8800 +    case eCSSUnit_List:
  1.8801 +    case eCSSUnit_ListDep: {
  1.8802 +      svgReset->mFilters.Clear();
  1.8803 +      const nsCSSValueList* cur = filterValue->GetListValue();
  1.8804 +      while (cur) {
  1.8805 +        nsStyleFilter styleFilter;
  1.8806 +        if (!SetStyleFilterToCSSValue(&styleFilter, cur->mValue, aContext,
  1.8807 +                                      mPresContext, canStoreInRuleTree)) {
  1.8808 +          svgReset->mFilters.Clear();
  1.8809 +          break;
  1.8810 +        }
  1.8811 +        NS_ABORT_IF_FALSE(styleFilter.GetType() != NS_STYLE_FILTER_NONE,
  1.8812 +                          "filter should be set");
  1.8813 +        svgReset->mFilters.AppendElement(styleFilter);
  1.8814 +        cur = cur->mNext;
  1.8815 +      }
  1.8816 +      break;
  1.8817 +    }
  1.8818 +    default:
  1.8819 +      NS_NOTREACHED("unexpected unit");
  1.8820 +  }
  1.8821 +
  1.8822 +  // mask: url, none, inherit
  1.8823 +  const nsCSSValue* maskValue = aRuleData->ValueForMask();
  1.8824 +  if (eCSSUnit_URL == maskValue->GetUnit()) {
  1.8825 +    svgReset->mMask = maskValue->GetURLValue();
  1.8826 +  } else if (eCSSUnit_None == maskValue->GetUnit() ||
  1.8827 +             eCSSUnit_Initial == maskValue->GetUnit() ||
  1.8828 +             eCSSUnit_Unset == maskValue->GetUnit()) {
  1.8829 +    svgReset->mMask = nullptr;
  1.8830 +  } else if (eCSSUnit_Inherit == maskValue->GetUnit()) {
  1.8831 +    canStoreInRuleTree = false;
  1.8832 +    svgReset->mMask = parentSVGReset->mMask;
  1.8833 +  }
  1.8834 +
  1.8835 +  // mask-type: enum, inherit, initial
  1.8836 +  SetDiscrete(*aRuleData->ValueForMaskType(),
  1.8837 +              svgReset->mMaskType,
  1.8838 +              canStoreInRuleTree,
  1.8839 +              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
  1.8840 +              parentSVGReset->mMaskType,
  1.8841 +              NS_STYLE_MASK_TYPE_LUMINANCE, 0, 0, 0, 0);
  1.8842 +
  1.8843 +  COMPUTE_END_RESET(SVGReset, svgReset)
  1.8844 +}
  1.8845 +
  1.8846 +const void*
  1.8847 +nsRuleNode::ComputeVariablesData(void* aStartStruct,
  1.8848 +                                 const nsRuleData* aRuleData,
  1.8849 +                                 nsStyleContext* aContext,
  1.8850 +                                 nsRuleNode* aHighestNode,
  1.8851 +                                 const RuleDetail aRuleDetail,
  1.8852 +                                 const bool aCanStoreInRuleTree)
  1.8853 +{
  1.8854 +  COMPUTE_START_INHERITED(Variables, (), variables, parentVariables)
  1.8855 +
  1.8856 +  MOZ_ASSERT(aRuleData->mVariables,
  1.8857 +             "shouldn't be in ComputeVariablesData if there were no variable "
  1.8858 +             "declarations specified");
  1.8859 +
  1.8860 +  CSSVariableResolver resolver(&variables->mVariables);
  1.8861 +  resolver.Resolve(&parentVariables->mVariables,
  1.8862 +                   aRuleData->mVariables);
  1.8863 +  canStoreInRuleTree = false;
  1.8864 +
  1.8865 +  COMPUTE_END_INHERITED(Variables, variables)
  1.8866 +}
  1.8867 +
  1.8868 +const void*
  1.8869 +nsRuleNode::GetStyleData(nsStyleStructID aSID,
  1.8870 +                         nsStyleContext* aContext,
  1.8871 +                         bool aComputeData)
  1.8872 +{
  1.8873 +  NS_ASSERTION(IsUsedDirectly(),
  1.8874 +               "if we ever call this on rule nodes that aren't used "
  1.8875 +               "directly, we should adjust handling of mDependentBits "
  1.8876 +               "in some way.");
  1.8877 +
  1.8878 +  const void *data;
  1.8879 +  data = mStyleData.GetStyleData(aSID);
  1.8880 +  if (MOZ_LIKELY(data != nullptr))
  1.8881 +    return data; // We have a fully specified struct. Just return it.
  1.8882 +
  1.8883 +  if (MOZ_UNLIKELY(!aComputeData))
  1.8884 +    return nullptr;
  1.8885 +
  1.8886 +  // Nothing is cached.  We'll have to delve further and examine our rules.
  1.8887 +  data = WalkRuleTree(aSID, aContext);
  1.8888 +
  1.8889 +  NS_ABORT_IF_FALSE(data, "should have aborted on out-of-memory");
  1.8890 +  return data;
  1.8891 +}
  1.8892 +
  1.8893 +// See comments above in GetStyleData for an explanation of what the
  1.8894 +// code below does.
  1.8895 +#define STYLE_STRUCT(name_, checkdata_cb_)                                    \
  1.8896 +const nsStyle##name_*                                                         \
  1.8897 +nsRuleNode::GetStyle##name_(nsStyleContext* aContext, bool aComputeData)      \
  1.8898 +{                                                                             \
  1.8899 +  NS_ASSERTION(IsUsedDirectly(),                                              \
  1.8900 +               "if we ever call this on rule nodes that aren't used "         \
  1.8901 +               "directly, we should adjust handling of mDependentBits "       \
  1.8902 +               "in some way.");                                               \
  1.8903 +                                                                              \
  1.8904 +  const nsStyle##name_ *data;                                                 \
  1.8905 +  data = mStyleData.GetStyle##name_();                                        \
  1.8906 +  if (MOZ_LIKELY(data != nullptr))                                            \
  1.8907 +    return data;                                                              \
  1.8908 +                                                                              \
  1.8909 +  if (MOZ_UNLIKELY(!aComputeData))                                            \
  1.8910 +    return nullptr;                                                           \
  1.8911 +                                                                              \
  1.8912 +  data = static_cast<const nsStyle##name_ *>                                  \
  1.8913 +           (WalkRuleTree(eStyleStruct_##name_, aContext));                    \
  1.8914 +                                                                              \
  1.8915 +  NS_ABORT_IF_FALSE(data, "should have aborted on out-of-memory");            \
  1.8916 +  return data;                                                                \
  1.8917 +}
  1.8918 +#include "nsStyleStructList.h"
  1.8919 +#undef STYLE_STRUCT
  1.8920 +
  1.8921 +void
  1.8922 +nsRuleNode::Mark()
  1.8923 +{
  1.8924 +  for (nsRuleNode *node = this;
  1.8925 +       node && !(node->mDependentBits & NS_RULE_NODE_GC_MARK);
  1.8926 +       node = node->mParent)
  1.8927 +    node->mDependentBits |= NS_RULE_NODE_GC_MARK;
  1.8928 +}
  1.8929 +
  1.8930 +static PLDHashOperator
  1.8931 +SweepRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
  1.8932 +                      uint32_t number, void *arg)
  1.8933 +{
  1.8934 +  ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
  1.8935 +  if (entry->mRuleNode->Sweep())
  1.8936 +    return PL_DHASH_REMOVE; // implies NEXT, unless |ed with STOP
  1.8937 +  return PL_DHASH_NEXT;
  1.8938 +}
  1.8939 +
  1.8940 +bool
  1.8941 +nsRuleNode::Sweep()
  1.8942 +{
  1.8943 +  // If we're not marked, then we have to delete ourself.
  1.8944 +  // However, we never allow the root node to GC itself, because nsStyleSet
  1.8945 +  // wants to hold onto the root node and not worry about re-creating a
  1.8946 +  // rule walker if the root node is deleted.
  1.8947 +  if (!(mDependentBits & NS_RULE_NODE_GC_MARK) &&
  1.8948 +      // Skip this only if we're the *current* root and not an old one.
  1.8949 +      !(IsRoot() && mPresContext->StyleSet()->GetRuleTree() == this)) {
  1.8950 +    Destroy();
  1.8951 +    return true;
  1.8952 +  }
  1.8953 +
  1.8954 +  // Clear our mark, for the next time around.
  1.8955 +  mDependentBits &= ~NS_RULE_NODE_GC_MARK;
  1.8956 +
  1.8957 +  // Call sweep on the children, since some may not be marked, and
  1.8958 +  // remove any deleted children from the child lists.
  1.8959 +  if (HaveChildren()) {
  1.8960 +    uint32_t childrenDestroyed;
  1.8961 +    if (ChildrenAreHashed()) {
  1.8962 +      PLDHashTable *children = ChildrenHash();
  1.8963 +      uint32_t oldChildCount = children->entryCount;
  1.8964 +      PL_DHashTableEnumerate(children, SweepRuleNodeChildren, nullptr);
  1.8965 +      childrenDestroyed = children->entryCount - oldChildCount;
  1.8966 +    } else {
  1.8967 +      childrenDestroyed = 0;
  1.8968 +      for (nsRuleNode **children = ChildrenListPtr(); *children; ) {
  1.8969 +        nsRuleNode *next = (*children)->mNextSibling;
  1.8970 +        if ((*children)->Sweep()) {
  1.8971 +          // This rule node was destroyed, so implicitly advance by
  1.8972 +          // making *children point to the next entry.
  1.8973 +          *children = next;
  1.8974 +          ++childrenDestroyed;
  1.8975 +        } else {
  1.8976 +          // Advance.
  1.8977 +          children = &(*children)->mNextSibling;
  1.8978 +        }
  1.8979 +      }
  1.8980 +    }
  1.8981 +    mRefCnt -= childrenDestroyed;
  1.8982 +    NS_POSTCONDITION(IsRoot() || mRefCnt > 0,
  1.8983 +                     "We didn't get swept, so we'd better have style contexts "
  1.8984 +                     "pointing to us or to one of our descendants, which means "
  1.8985 +                     "we'd better have a nonzero mRefCnt here!");
  1.8986 +  }
  1.8987 +  return false;
  1.8988 +}
  1.8989 +
  1.8990 +/* static */ bool
  1.8991 +nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
  1.8992 +                                    uint32_t ruleTypeMask,
  1.8993 +                                    bool aAuthorColorsAllowed)
  1.8994 +{
  1.8995 +  uint32_t inheritBits = 0;
  1.8996 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND)
  1.8997 +    inheritBits |= NS_STYLE_INHERIT_BIT(Background);
  1.8998 +
  1.8999 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER)
  1.9000 +    inheritBits |= NS_STYLE_INHERIT_BIT(Border);
  1.9001 +
  1.9002 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING)
  1.9003 +    inheritBits |= NS_STYLE_INHERIT_BIT(Padding);
  1.9004 +
  1.9005 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW)
  1.9006 +    inheritBits |= NS_STYLE_INHERIT_BIT(Text);
  1.9007 +
  1.9008 +  // properties in the SIDS, whether or not we care about them
  1.9009 +  size_t nprops = 0,
  1.9010 +         backgroundOffset, borderOffset, paddingOffset, textShadowOffset;
  1.9011 +
  1.9012 +  // We put the reset properties the start of the nsCSSValue array....
  1.9013 +
  1.9014 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
  1.9015 +    backgroundOffset = nprops;
  1.9016 +    nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Background);
  1.9017 +  }
  1.9018 +
  1.9019 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
  1.9020 +    borderOffset = nprops;
  1.9021 +    nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Border);
  1.9022 +  }
  1.9023 +
  1.9024 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
  1.9025 +    paddingOffset = nprops;
  1.9026 +    nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Padding);
  1.9027 +  }
  1.9028 +
  1.9029 +  // ...and the inherited properties at the end of the array.
  1.9030 +  size_t inheritedOffset = nprops;
  1.9031 +
  1.9032 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
  1.9033 +    textShadowOffset = nprops;
  1.9034 +    nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Text);
  1.9035 +  }
  1.9036 +
  1.9037 +  void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
  1.9038 +  AutoCSSValueArray dataArray(dataStorage, nprops);
  1.9039 +
  1.9040 +  /* We're relying on the use of |aStyleContext| not mutating it! */
  1.9041 +  nsRuleData ruleData(inheritBits, dataArray.get(),
  1.9042 +                      aStyleContext->PresContext(), aStyleContext);
  1.9043 +
  1.9044 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
  1.9045 +    ruleData.mValueOffsets[eStyleStruct_Background] = backgroundOffset;
  1.9046 +  }
  1.9047 +
  1.9048 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
  1.9049 +    ruleData.mValueOffsets[eStyleStruct_Border] = borderOffset;
  1.9050 +  }
  1.9051 +
  1.9052 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
  1.9053 +    ruleData.mValueOffsets[eStyleStruct_Padding] = paddingOffset;
  1.9054 +  }
  1.9055 +
  1.9056 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
  1.9057 +    ruleData.mValueOffsets[eStyleStruct_Text] = textShadowOffset;
  1.9058 +  }
  1.9059 +
  1.9060 +  static const nsCSSProperty backgroundValues[] = {
  1.9061 +    eCSSProperty_background_color,
  1.9062 +    eCSSProperty_background_image,
  1.9063 +  };
  1.9064 +
  1.9065 +  static const nsCSSProperty borderValues[] = {
  1.9066 +    eCSSProperty_border_top_color,
  1.9067 +    eCSSProperty_border_top_style,
  1.9068 +    eCSSProperty_border_top_width,
  1.9069 +    eCSSProperty_border_right_color_value,
  1.9070 +    eCSSProperty_border_right_style_value,
  1.9071 +    eCSSProperty_border_right_width_value,
  1.9072 +    eCSSProperty_border_bottom_color,
  1.9073 +    eCSSProperty_border_bottom_style,
  1.9074 +    eCSSProperty_border_bottom_width,
  1.9075 +    eCSSProperty_border_left_color_value,
  1.9076 +    eCSSProperty_border_left_style_value,
  1.9077 +    eCSSProperty_border_left_width_value,
  1.9078 +    eCSSProperty_border_start_color_value,
  1.9079 +    eCSSProperty_border_start_style_value,
  1.9080 +    eCSSProperty_border_start_width_value,
  1.9081 +    eCSSProperty_border_end_color_value,
  1.9082 +    eCSSProperty_border_end_style_value,
  1.9083 +    eCSSProperty_border_end_width_value,
  1.9084 +    eCSSProperty_border_top_left_radius,
  1.9085 +    eCSSProperty_border_top_right_radius,
  1.9086 +    eCSSProperty_border_bottom_right_radius,
  1.9087 +    eCSSProperty_border_bottom_left_radius,
  1.9088 +  };
  1.9089 +
  1.9090 +  static const nsCSSProperty paddingValues[] = {
  1.9091 +    eCSSProperty_padding_top,
  1.9092 +    eCSSProperty_padding_right_value,
  1.9093 +    eCSSProperty_padding_bottom,
  1.9094 +    eCSSProperty_padding_left_value,
  1.9095 +    eCSSProperty_padding_start_value,
  1.9096 +    eCSSProperty_padding_end_value,
  1.9097 +  };
  1.9098 +
  1.9099 +  static const nsCSSProperty textShadowValues[] = {
  1.9100 +    eCSSProperty_text_shadow
  1.9101 +  };
  1.9102 +
  1.9103 +  // Number of properties we care about
  1.9104 +  size_t nValues = 0;
  1.9105 +
  1.9106 +  nsCSSValue* values[MOZ_ARRAY_LENGTH(backgroundValues) +
  1.9107 +                     MOZ_ARRAY_LENGTH(borderValues) +
  1.9108 +                     MOZ_ARRAY_LENGTH(paddingValues) +
  1.9109 +                     MOZ_ARRAY_LENGTH(textShadowValues)];
  1.9110 +
  1.9111 +  nsCSSProperty properties[MOZ_ARRAY_LENGTH(backgroundValues) +
  1.9112 +                           MOZ_ARRAY_LENGTH(borderValues) +
  1.9113 +                           MOZ_ARRAY_LENGTH(paddingValues) +
  1.9114 +                           MOZ_ARRAY_LENGTH(textShadowValues)];
  1.9115 +
  1.9116 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
  1.9117 +    for (uint32_t i = 0, i_end = ArrayLength(backgroundValues);
  1.9118 +         i < i_end; ++i) {
  1.9119 +      properties[nValues] = backgroundValues[i];
  1.9120 +      values[nValues++] = ruleData.ValueFor(backgroundValues[i]);
  1.9121 +    }
  1.9122 +  }
  1.9123 +
  1.9124 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
  1.9125 +    for (uint32_t i = 0, i_end = ArrayLength(borderValues);
  1.9126 +         i < i_end; ++i) {
  1.9127 +      properties[nValues] = borderValues[i];
  1.9128 +      values[nValues++] = ruleData.ValueFor(borderValues[i]);
  1.9129 +    }
  1.9130 +  }
  1.9131 +
  1.9132 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
  1.9133 +    for (uint32_t i = 0, i_end = ArrayLength(paddingValues);
  1.9134 +         i < i_end; ++i) {
  1.9135 +      properties[nValues] = paddingValues[i];
  1.9136 +      values[nValues++] = ruleData.ValueFor(paddingValues[i]);
  1.9137 +    }
  1.9138 +  }
  1.9139 +
  1.9140 +  if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
  1.9141 +    for (uint32_t i = 0, i_end = ArrayLength(textShadowValues);
  1.9142 +         i < i_end; ++i) {
  1.9143 +      properties[nValues] = textShadowValues[i];
  1.9144 +      values[nValues++] = ruleData.ValueFor(textShadowValues[i]);
  1.9145 +    }
  1.9146 +  }
  1.9147 +
  1.9148 +  nsStyleContext* styleContext = aStyleContext;
  1.9149 +
  1.9150 +  // We need to be careful not to count styles covered up by user-important or
  1.9151 +  // UA-important declarations.  But we do want to catch explicit inherit
  1.9152 +  // styling in those and check our parent style context to see whether we have
  1.9153 +  // user styling for those properties.  Note that we don't care here about
  1.9154 +  // inheritance due to lack of a specified value, since all the properties we
  1.9155 +  // care about are reset properties.
  1.9156 +  bool haveExplicitUAInherit;
  1.9157 +  do {
  1.9158 +    haveExplicitUAInherit = false;
  1.9159 +    for (nsRuleNode* ruleNode = styleContext->RuleNode(); ruleNode;
  1.9160 +         ruleNode = ruleNode->GetParent()) {
  1.9161 +      nsIStyleRule *rule = ruleNode->GetRule();
  1.9162 +      if (rule) {
  1.9163 +        ruleData.mLevel = ruleNode->GetLevel();
  1.9164 +        ruleData.mIsImportantRule = ruleNode->IsImportantRule();
  1.9165 +
  1.9166 +        rule->MapRuleInfoInto(&ruleData);
  1.9167 +
  1.9168 +        if (ruleData.mLevel == nsStyleSet::eAgentSheet ||
  1.9169 +            ruleData.mLevel == nsStyleSet::eUserSheet) {
  1.9170 +          // This is a rule whose effect we want to ignore, so if any of
  1.9171 +          // the properties we care about were set, set them to the dummy
  1.9172 +          // value that they'll never otherwise get.
  1.9173 +          for (uint32_t i = 0; i < nValues; ++i) {
  1.9174 +            nsCSSUnit unit = values[i]->GetUnit();
  1.9175 +            if (unit != eCSSUnit_Null &&
  1.9176 +                unit != eCSSUnit_Dummy &&
  1.9177 +                unit != eCSSUnit_DummyInherit) {
  1.9178 +              if (unit == eCSSUnit_Inherit ||
  1.9179 +                  (i >= inheritedOffset && unit == eCSSUnit_Unset)) {
  1.9180 +                haveExplicitUAInherit = true;
  1.9181 +                values[i]->SetDummyInheritValue();
  1.9182 +              } else {
  1.9183 +                values[i]->SetDummyValue();
  1.9184 +              }
  1.9185 +            }
  1.9186 +          }
  1.9187 +        } else {
  1.9188 +          // If any of the values we care about was set by the above rule,
  1.9189 +          // we have author style.
  1.9190 +          for (uint32_t i = 0; i < nValues; ++i) {
  1.9191 +            if (values[i]->GetUnit() != eCSSUnit_Null &&
  1.9192 +                values[i]->GetUnit() != eCSSUnit_Dummy && // see above
  1.9193 +                values[i]->GetUnit() != eCSSUnit_DummyInherit) {
  1.9194 +              // If author colors are not allowed, only claim to have
  1.9195 +              // author-specified rules if we're looking at a non-color
  1.9196 +              // property or if we're looking at the background color and it's
  1.9197 +              // set to transparent.  Anything else should get set to a dummy
  1.9198 +              // value instead.
  1.9199 +              if (aAuthorColorsAllowed ||
  1.9200 +                  !nsCSSProps::PropHasFlags(properties[i],
  1.9201 +                     CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED) ||
  1.9202 +                  (properties[i] == eCSSProperty_background_color &&
  1.9203 +                   !values[i]->IsNonTransparentColor())) {
  1.9204 +                return true;
  1.9205 +              }
  1.9206 +
  1.9207 +              values[i]->SetDummyValue();
  1.9208 +            }
  1.9209 +          }
  1.9210 +        }
  1.9211 +      }
  1.9212 +    }
  1.9213 +
  1.9214 +    if (haveExplicitUAInherit) {
  1.9215 +      // reset all the eCSSUnit_Null values to eCSSUnit_Dummy (since they're
  1.9216 +      // not styled by the author, or by anyone else), and then reset all the
  1.9217 +      // eCSSUnit_DummyInherit values to eCSSUnit_Null (so we will be able to
  1.9218 +      // detect them being styled by the author) and move up to our parent
  1.9219 +      // style context.
  1.9220 +      for (uint32_t i = 0; i < nValues; ++i)
  1.9221 +        if (values[i]->GetUnit() == eCSSUnit_Null)
  1.9222 +          values[i]->SetDummyValue();
  1.9223 +      for (uint32_t i = 0; i < nValues; ++i)
  1.9224 +        if (values[i]->GetUnit() == eCSSUnit_DummyInherit)
  1.9225 +          values[i]->Reset();
  1.9226 +      styleContext = styleContext->GetParent();
  1.9227 +    }
  1.9228 +  } while (haveExplicitUAInherit && styleContext);
  1.9229 +
  1.9230 +  return false;
  1.9231 +}
  1.9232 +
  1.9233 +/* static */
  1.9234 +bool
  1.9235 +nsRuleNode::ComputeColor(const nsCSSValue& aValue, nsPresContext* aPresContext,
  1.9236 +                         nsStyleContext* aStyleContext, nscolor& aResult)
  1.9237 +{
  1.9238 +  MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Inherit,
  1.9239 +             "aValue shouldn't have eCSSUnit_Inherit");
  1.9240 +  MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Initial,
  1.9241 +             "aValue shouldn't have eCSSUnit_Initial");
  1.9242 +  MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Unset,
  1.9243 +             "aValue shouldn't have eCSSUnit_Unset");
  1.9244 +
  1.9245 +  bool canStoreInRuleTree;
  1.9246 +  bool ok = SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aStyleContext,
  1.9247 +                     aResult, canStoreInRuleTree);
  1.9248 +  MOZ_ASSERT(ok || !(aPresContext && aStyleContext));
  1.9249 +  return ok;
  1.9250 +}

mercurial