Bumping manifests a=b2g-bump
[gecko.git] / layout / style / nsRuleNode.cpp
blob55189ac3a0c73f7351158a1f5c780cd8dd04facf
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=78: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * a node in the lexicographic tree of rules that match an element,
9 * responsible for converting the rules' information into computed style
12 #include <algorithm>
14 #include "mozilla/ArrayUtils.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/DebugOnly.h"
17 #include "mozilla/Likely.h"
18 #include "mozilla/LookAndFeel.h"
20 #include "nsRuleNode.h"
21 #include "nscore.h"
22 #include "nsIWidget.h"
23 #include "nsIPresShell.h"
24 #include "nsFontMetrics.h"
25 #include "gfxFont.h"
26 #include "nsCSSPseudoElements.h"
27 #include "nsThemeConstants.h"
28 #include "pldhash.h"
29 #include "nsStyleContext.h"
30 #include "nsStyleSet.h"
31 #include "nsStyleStruct.h"
32 #include "nsSize.h"
33 #include "nsRuleData.h"
34 #include "nsIStyleRule.h"
35 #include "nsBidiUtils.h"
36 #include "nsStyleStructInlines.h"
37 #include "nsCSSProps.h"
38 #include "nsTArray.h"
39 #include "nsContentUtils.h"
40 #include "CSSCalc.h"
41 #include "nsPrintfCString.h"
42 #include "nsRenderingContext.h"
43 #include "nsStyleUtil.h"
44 #include "nsIDocument.h"
45 #include "prtime.h"
46 #include "CSSVariableResolver.h"
47 #include "nsCSSParser.h"
48 #include "CounterStyleManager.h"
50 #if defined(_MSC_VER) || defined(__MINGW32__)
51 #include <malloc.h>
52 #ifdef _MSC_VER
53 #define alloca _alloca
54 #endif
55 #endif
56 #ifdef SOLARIS
57 #include <alloca.h>
58 #endif
60 using std::max;
61 using std::min;
62 using namespace mozilla;
63 using namespace mozilla::dom;
65 #define NS_SET_IMAGE_REQUEST(method_, context_, request_) \
66 if ((context_)->PresContext()->IsDynamic()) { \
67 method_(request_); \
68 } else { \
69 nsRefPtr<imgRequestProxy> req = nsContentUtils::GetStaticRequest(request_); \
70 method_(req); \
73 #define NS_SET_IMAGE_REQUEST_WITH_DOC(method_, context_, requestgetter_) \
74 { \
75 nsIDocument* doc = (context_)->PresContext()->Document(); \
76 NS_SET_IMAGE_REQUEST(method_, context_, requestgetter_(doc)) \
80 * For storage of an |nsRuleNode|'s children in a PLDHashTable.
83 struct ChildrenHashEntry : public PLDHashEntryHdr {
84 // key is |mRuleNode->GetKey()|
85 nsRuleNode *mRuleNode;
88 /* static */ PLDHashNumber
89 nsRuleNode::ChildrenHashHashKey(PLDHashTable *aTable, const void *aKey)
91 const nsRuleNode::Key *key =
92 static_cast<const nsRuleNode::Key*>(aKey);
93 // Disagreement on importance and level for the same rule is extremely
94 // rare, so hash just on the rule.
95 return PL_DHashVoidPtrKeyStub(aTable, key->mRule);
98 /* static */ bool
99 nsRuleNode::ChildrenHashMatchEntry(PLDHashTable *aTable,
100 const PLDHashEntryHdr *aHdr,
101 const void *aKey)
103 const ChildrenHashEntry *entry =
104 static_cast<const ChildrenHashEntry*>(aHdr);
105 const nsRuleNode::Key *key =
106 static_cast<const nsRuleNode::Key*>(aKey);
107 return entry->mRuleNode->GetKey() == *key;
110 /* static */ const PLDHashTableOps
111 nsRuleNode::ChildrenHashOps = {
112 // It's probably better to allocate the table itself using malloc and
113 // free rather than the pres shell's arena because the table doesn't
114 // grow very often and the pres shell's arena doesn't recycle very
115 // large size allocations.
116 PL_DHashAllocTable,
117 PL_DHashFreeTable,
118 ChildrenHashHashKey,
119 ChildrenHashMatchEntry,
120 PL_DHashMoveEntryStub,
121 PL_DHashClearEntryStub,
122 PL_DHashFinalizeStub,
123 nullptr
127 // EnsureBlockDisplay:
128 // - if the display value (argument) is not a block-type
129 // then we set it to a valid block display value
130 // - For enforcing the floated/positioned element CSS2 rules
131 // - We allow the behavior of "list-item" to be customized.
132 // CSS21 says that position/float do not convert 'list-item' to 'block',
133 // but it explicitly does not define whether 'list-item' should be
134 // converted to block *on the root node*. To allow for flexibility
135 // (so that we don't have to support a list-item root node), this method
136 // lets the caller pick either behavior, using the 'aConvertListItem' arg.
137 // Reference: http://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo
138 /* static */
139 void
140 nsRuleNode::EnsureBlockDisplay(uint8_t& display,
141 bool aConvertListItem /* = false */)
143 // see if the display value is already a block
144 switch (display) {
145 case NS_STYLE_DISPLAY_LIST_ITEM :
146 if (aConvertListItem) {
147 display = NS_STYLE_DISPLAY_BLOCK;
148 break;
149 } // else, fall through to share the 'break' for non-changing display vals
150 case NS_STYLE_DISPLAY_NONE :
151 // never change display:none *ever*
152 case NS_STYLE_DISPLAY_TABLE :
153 case NS_STYLE_DISPLAY_BLOCK :
154 case NS_STYLE_DISPLAY_FLEX :
155 case NS_STYLE_DISPLAY_GRID :
156 // do not muck with these at all - already blocks
157 // This is equivalent to nsStyleDisplay::IsBlockOutside. (XXX Maybe we
158 // should just call that?)
159 // This needs to match the check done in
160 // nsCSSFrameConstructor::FindMathMLData for <math>.
161 break;
163 case NS_STYLE_DISPLAY_INLINE_TABLE :
164 // make inline tables into tables
165 display = NS_STYLE_DISPLAY_TABLE;
166 break;
168 case NS_STYLE_DISPLAY_INLINE_FLEX:
169 // make inline flex containers into flex containers
170 display = NS_STYLE_DISPLAY_FLEX;
171 break;
173 case NS_STYLE_DISPLAY_INLINE_GRID:
174 // make inline grid containers into grid containers
175 display = NS_STYLE_DISPLAY_GRID;
176 break;
178 default :
179 // make it a block
180 display = NS_STYLE_DISPLAY_BLOCK;
184 // EnsureInlineDisplay:
185 // - if the display value (argument) is not an inline type
186 // then we set it to a valid inline display value
187 /* static */
188 void
189 nsRuleNode::EnsureInlineDisplay(uint8_t& display)
191 // see if the display value is already inline
192 switch (display) {
193 case NS_STYLE_DISPLAY_BLOCK :
194 display = NS_STYLE_DISPLAY_INLINE_BLOCK;
195 break;
196 case NS_STYLE_DISPLAY_TABLE :
197 display = NS_STYLE_DISPLAY_INLINE_TABLE;
198 break;
199 case NS_STYLE_DISPLAY_FLEX :
200 display = NS_STYLE_DISPLAY_INLINE_FLEX;
201 break;
202 case NS_STYLE_DISPLAY_GRID :
203 display = NS_STYLE_DISPLAY_INLINE_GRID;
204 break;
205 case NS_STYLE_DISPLAY_BOX:
206 display = NS_STYLE_DISPLAY_INLINE_BOX;
207 break;
208 case NS_STYLE_DISPLAY_STACK:
209 display = NS_STYLE_DISPLAY_INLINE_STACK;
210 break;
214 static nscoord CalcLengthWith(const nsCSSValue& aValue,
215 nscoord aFontSize,
216 const nsStyleFont* aStyleFont,
217 nsStyleContext* aStyleContext,
218 nsPresContext* aPresContext,
219 bool aUseProvidedRootEmSize,
220 bool aUseUserFontSet,
221 bool& aCanStoreInRuleTree);
223 struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
224 public css::NumbersAlreadyNormalizedOps
226 // All of the parameters to CalcLengthWith except aValue.
227 const nscoord mFontSize;
228 const nsStyleFont* const mStyleFont;
229 nsStyleContext* const mStyleContext;
230 nsPresContext* const mPresContext;
231 const bool mUseProvidedRootEmSize;
232 const bool mUseUserFontSet;
233 bool& mCanStoreInRuleTree;
235 CalcLengthCalcOps(nscoord aFontSize, const nsStyleFont* aStyleFont,
236 nsStyleContext* aStyleContext, nsPresContext* aPresContext,
237 bool aUseProvidedRootEmSize, bool aUseUserFontSet,
238 bool& aCanStoreInRuleTree)
239 : mFontSize(aFontSize),
240 mStyleFont(aStyleFont),
241 mStyleContext(aStyleContext),
242 mPresContext(aPresContext),
243 mUseProvidedRootEmSize(aUseProvidedRootEmSize),
244 mUseUserFontSet(aUseUserFontSet),
245 mCanStoreInRuleTree(aCanStoreInRuleTree)
249 result_type ComputeLeafValue(const nsCSSValue& aValue)
251 return CalcLengthWith(aValue, mFontSize, mStyleFont,
252 mStyleContext, mPresContext, mUseProvidedRootEmSize,
253 mUseUserFontSet, mCanStoreInRuleTree);
257 static inline nscoord ScaleCoordRound(const nsCSSValue& aValue, float aFactor)
259 return NSToCoordRoundWithClamp(aValue.GetFloatValue() * aFactor);
262 static inline nscoord ScaleViewportCoordTrunc(const nsCSSValue& aValue,
263 nscoord aViewportSize)
265 // For units (like percentages and viewport units) where authors might
266 // repeatedly use a value and expect some multiple of the value to be
267 // smaller than a container, we need to use floor rather than round.
268 // We need to use division by 100.0 rather than multiplication by 0.1f
269 // to avoid introducing error.
270 return NSToCoordTruncClamped(aValue.GetFloatValue() *
271 aViewportSize / 100.0f);
274 already_AddRefed<nsFontMetrics>
275 GetMetricsFor(nsPresContext* aPresContext,
276 nsStyleContext* aStyleContext,
277 const nsStyleFont* aStyleFont,
278 nscoord aFontSize, // overrides value from aStyleFont
279 bool aUseUserFontSet)
281 nsFont font = aStyleFont->mFont;
282 font.size = aFontSize;
283 gfxUserFontSet *fs = nullptr;
284 if (aUseUserFontSet) {
285 fs = aPresContext->GetUserFontSet();
287 gfxTextPerfMetrics *tp = aPresContext->GetTextPerfMetrics();
288 nsRefPtr<nsFontMetrics> fm;
289 aPresContext->DeviceContext()->GetMetricsFor(font,
290 aStyleFont->mLanguage,
291 fs, tp, *getter_AddRefs(fm));
292 return fm.forget();
296 static nsSize CalcViewportUnitsScale(nsPresContext* aPresContext)
298 // The caller is making use of viewport units, so notify the pres context
299 // that it will need to rebuild the rule tree if the size of the viewport
300 // changes.
301 aPresContext->SetUsesViewportUnits(true);
303 // The default (when we have 'overflow: auto' on the root element, or
304 // trivially for 'overflow: hidden' since we never have scrollbars in that
305 // case) is to define the scale of the viewport units without considering
306 // scrollbars.
307 nsSize viewportSize(aPresContext->GetVisibleArea().Size());
309 // Check for 'overflow: scroll' styles on the root scroll frame. If we find
310 // any, the standard requires us to take scrollbars into account.
311 nsIScrollableFrame* scrollFrame =
312 aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
313 if (scrollFrame) {
314 ScrollbarStyles styles(scrollFrame->GetScrollbarStyles());
316 if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL ||
317 styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
318 // Gather scrollbar size information.
319 nsRefPtr<nsRenderingContext> context =
320 aPresContext->PresShell()->CreateReferenceRenderingContext();
321 nsMargin sizes(scrollFrame->GetDesiredScrollbarSizes(aPresContext, context));
323 if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
324 // 'overflow-x: scroll' means we must consider the horizontal scrollbar,
325 // which affects the scale of viewport height units.
326 viewportSize.height -= sizes.TopBottom();
329 if (styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
330 // 'overflow-y: scroll' means we must consider the vertical scrollbar,
331 // which affects the scale of viewport width units.
332 viewportSize.width -= sizes.LeftRight();
337 return viewportSize;
340 static nscoord CalcLengthWith(const nsCSSValue& aValue,
341 nscoord aFontSize,
342 const nsStyleFont* aStyleFont,
343 nsStyleContext* aStyleContext,
344 nsPresContext* aPresContext,
345 bool aUseProvidedRootEmSize,
346 // aUseUserFontSet should always be true
347 // except when called from
348 // CalcLengthWithInitialFont.
349 bool aUseUserFontSet,
350 bool& aCanStoreInRuleTree)
352 NS_ASSERTION(aValue.IsLengthUnit() || aValue.IsCalcUnit(),
353 "not a length or calc unit");
354 NS_ASSERTION(aStyleFont || aStyleContext,
355 "Must have style data");
356 NS_ASSERTION(!aStyleFont || !aStyleContext,
357 "Duplicate sources of data");
358 NS_ASSERTION(aPresContext, "Must have prescontext");
360 if (aValue.IsFixedLengthUnit()) {
361 return aValue.GetFixedLength(aPresContext);
363 if (aValue.IsPixelLengthUnit()) {
364 return aValue.GetPixelLength();
366 if (aValue.IsCalcUnit()) {
367 // For properties for which lengths are the *only* units accepted in
368 // calc(), we can handle calc() here and just compute a final
369 // result. We ensure that we don't get to this code for other
370 // properties by not calling CalcLength in those cases: SetCoord
371 // only calls CalcLength for a calc when it is appropriate to do so.
372 CalcLengthCalcOps ops(aFontSize, aStyleFont,
373 aStyleContext, aPresContext,
374 aUseProvidedRootEmSize, aUseUserFontSet,
375 aCanStoreInRuleTree);
376 return css::ComputeCalc(aValue, ops);
378 switch (aValue.GetUnit()) {
379 // nsPresContext::SetVisibleArea and
380 // nsPresContext::MediaFeatureValuesChanged handle dynamic changes
381 // of the basis for viewport units by rebuilding the rule tree and
382 // style context tree. Not caching them in the rule tree wouldn't
383 // be sufficient to handle these changes because we also need a way
384 // to get rid of cached values in the style context tree without any
385 // changes in specified style. We can either do this by not caching
386 // in the rule tree and then throwing away the style context tree
387 // for dynamic viewport size changes, or by allowing caching in the
388 // rule tree and using the existing rebuild style data path that
389 // throws away the style context and the rule tree.
390 // Thus we do cache viewport units in the rule tree. This allows us
391 // to benefit from the performance advantages of the rule tree
392 // (e.g., faster dynamic changes on other things, like transforms)
393 // and allows us not to need an additional code path, in exchange
394 // for an increased cost to dynamic changes to the viewport size
395 // when viewport units are in use.
396 case eCSSUnit_ViewportWidth: {
397 nscoord viewportWidth = CalcViewportUnitsScale(aPresContext).width;
398 return ScaleViewportCoordTrunc(aValue, viewportWidth);
400 case eCSSUnit_ViewportHeight: {
401 nscoord viewportHeight = CalcViewportUnitsScale(aPresContext).height;
402 return ScaleViewportCoordTrunc(aValue, viewportHeight);
404 case eCSSUnit_ViewportMin: {
405 nsSize vuScale(CalcViewportUnitsScale(aPresContext));
406 nscoord viewportMin = min(vuScale.width, vuScale.height);
407 return ScaleViewportCoordTrunc(aValue, viewportMin);
409 case eCSSUnit_ViewportMax: {
410 nsSize vuScale(CalcViewportUnitsScale(aPresContext));
411 nscoord viewportMax = max(vuScale.width, vuScale.height);
412 return ScaleViewportCoordTrunc(aValue, viewportMax);
414 // While we could deal with 'rem' units correctly by simply not
415 // caching any data that uses them in the rule tree, it's valuable
416 // to store them in the rule tree (for faster dynamic changes of
417 // other things). And since the font size of the root element
418 // changes rarely, we instead handle dynamic changes to the root
419 // element's font size by rebuilding all style data in
420 // nsCSSFrameConstructor::RestyleElement.
421 case eCSSUnit_RootEM: {
422 aPresContext->SetUsesRootEMUnits(true);
423 nscoord rootFontSize;
425 // NOTE: Be very careful with |styleFont|, since we haven't set
426 // aCanStoreInRuleTree to false yet, so we don't want to introduce
427 // any dependencies on aStyleContext's data here.
428 const nsStyleFont *styleFont =
429 aStyleFont ? aStyleFont : aStyleContext->StyleFont();
431 if (aUseProvidedRootEmSize) {
432 // We should use the provided aFontSize as the reference length to
433 // scale. This only happens when we are calculating font-size or
434 // an equivalent (scriptminsize or CalcLengthWithInitialFont) on
435 // the root element, in which case aFontSize is already the
436 // value we want.
437 if (aFontSize == -1) {
438 // XXX Should this be styleFont->mSize instead to avoid taking
439 // minfontsize prefs into account?
440 aFontSize = styleFont->mFont.size;
442 rootFontSize = aFontSize;
443 } else if (aStyleContext && !aStyleContext->GetParent()) {
444 // This is the root element (XXX we don't really know this, but
445 // nsRuleNode::SetFont makes the same assumption!), so we should
446 // use StyleFont on this context to get the root element's
447 // font size.
448 rootFontSize = styleFont->mFont.size;
449 } else {
450 // This is not the root element or we are calculating something other
451 // than font size, so rem is relative to the root element's font size.
452 nsRefPtr<nsStyleContext> rootStyle;
453 const nsStyleFont *rootStyleFont = styleFont;
454 Element* docElement = aPresContext->Document()->GetRootElement();
456 if (docElement) {
457 nsIFrame* rootFrame = docElement->GetPrimaryFrame();
458 if (rootFrame) {
459 rootStyle = rootFrame->StyleContext();
460 } else {
461 rootStyle = aPresContext->StyleSet()->ResolveStyleFor(docElement,
462 nullptr);
464 rootStyleFont = rootStyle->StyleFont();
467 rootFontSize = rootStyleFont->mFont.size;
470 return ScaleCoordRound(aValue, float(rootFontSize));
472 default:
473 // Fall through to the code for units that can't be stored in the
474 // rule tree because they depend on font data.
475 break;
477 // Common code for units that depend on the element's font data and
478 // thus can't be stored in the rule tree:
479 aCanStoreInRuleTree = false;
480 const nsStyleFont *styleFont =
481 aStyleFont ? aStyleFont : aStyleContext->StyleFont();
482 if (aFontSize == -1) {
483 // XXX Should this be styleFont->mSize instead to avoid taking minfontsize
484 // prefs into account?
485 aFontSize = styleFont->mFont.size;
487 switch (aValue.GetUnit()) {
488 case eCSSUnit_EM: {
489 // CSS2.1 specifies that this unit scales to the computed font
490 // size, not the em-width in the font metrics, despite the name.
491 return ScaleCoordRound(aValue, float(aFontSize));
493 case eCSSUnit_XHeight: {
494 nsRefPtr<nsFontMetrics> fm =
495 GetMetricsFor(aPresContext, aStyleContext, styleFont,
496 aFontSize, aUseUserFontSet);
497 return ScaleCoordRound(aValue, float(fm->XHeight()));
499 case eCSSUnit_Char: {
500 nsRefPtr<nsFontMetrics> fm =
501 GetMetricsFor(aPresContext, aStyleContext, styleFont,
502 aFontSize, aUseUserFontSet);
503 gfxFloat zeroWidth = (fm->GetThebesFontGroup()->GetFontAt(0)
504 ->GetMetrics().zeroOrAveCharWidth);
506 return ScaleCoordRound(aValue, ceil(aPresContext->AppUnitsPerDevPixel() *
507 zeroWidth));
509 default:
510 NS_NOTREACHED("unexpected unit");
511 break;
513 return 0;
516 /* static */ nscoord
517 nsRuleNode::CalcLength(const nsCSSValue& aValue,
518 nsStyleContext* aStyleContext,
519 nsPresContext* aPresContext,
520 bool& aCanStoreInRuleTree)
522 NS_ASSERTION(aStyleContext, "Must have style data");
524 return CalcLengthWith(aValue, -1, nullptr,
525 aStyleContext, aPresContext,
526 false, true, aCanStoreInRuleTree);
529 /* Inline helper function to redirect requests to CalcLength. */
530 static inline nscoord CalcLength(const nsCSSValue& aValue,
531 nsStyleContext* aStyleContext,
532 nsPresContext* aPresContext,
533 bool& aCanStoreInRuleTree)
535 return nsRuleNode::CalcLength(aValue, aStyleContext,
536 aPresContext, aCanStoreInRuleTree);
539 /* static */ nscoord
540 nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
541 const nsCSSValue& aValue)
543 nsStyleFont defaultFont(aPresContext); // FIXME: best language?
544 bool canStoreInRuleTree;
545 return CalcLengthWith(aValue, -1, &defaultFont,
546 nullptr, aPresContext,
547 true, false, canStoreInRuleTree);
550 struct LengthPercentPairCalcOps : public css::NumbersAlreadyNormalizedOps
552 typedef nsRuleNode::ComputedCalc result_type;
554 LengthPercentPairCalcOps(nsStyleContext* aContext,
555 nsPresContext* aPresContext,
556 bool& aCanStoreInRuleTree)
557 : mContext(aContext),
558 mPresContext(aPresContext),
559 mCanStoreInRuleTree(aCanStoreInRuleTree),
560 mHasPercent(false) {}
562 nsStyleContext* mContext;
563 nsPresContext* mPresContext;
564 bool& mCanStoreInRuleTree;
565 bool mHasPercent;
567 result_type ComputeLeafValue(const nsCSSValue& aValue)
569 if (aValue.GetUnit() == eCSSUnit_Percent) {
570 mHasPercent = true;
571 return result_type(0, aValue.GetPercentValue());
573 return result_type(CalcLength(aValue, mContext, mPresContext,
574 mCanStoreInRuleTree),
575 0.0f);
578 result_type
579 MergeAdditive(nsCSSUnit aCalcFunction,
580 result_type aValue1, result_type aValue2)
582 if (aCalcFunction == eCSSUnit_Calc_Plus) {
583 return result_type(NSCoordSaturatingAdd(aValue1.mLength,
584 aValue2.mLength),
585 aValue1.mPercent + aValue2.mPercent);
587 NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Minus,
588 "min() and max() are not allowed in calc() on "
589 "transform");
590 return result_type(NSCoordSaturatingSubtract(aValue1.mLength,
591 aValue2.mLength, 0),
592 aValue1.mPercent - aValue2.mPercent);
595 result_type
596 MergeMultiplicativeL(nsCSSUnit aCalcFunction,
597 float aValue1, result_type aValue2)
599 NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_L,
600 "unexpected unit");
601 return result_type(NSCoordSaturatingMultiply(aValue2.mLength, aValue1),
602 aValue1 * aValue2.mPercent);
605 result_type
606 MergeMultiplicativeR(nsCSSUnit aCalcFunction,
607 result_type aValue1, float aValue2)
609 NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_R ||
610 aCalcFunction == eCSSUnit_Calc_Divided,
611 "unexpected unit");
612 if (aCalcFunction == eCSSUnit_Calc_Divided) {
613 aValue2 = 1.0f / aValue2;
615 return result_type(NSCoordSaturatingMultiply(aValue1.mLength, aValue2),
616 aValue1.mPercent * aValue2);
621 static void
622 SpecifiedCalcToComputedCalc(const nsCSSValue& aValue, nsStyleCoord& aCoord,
623 nsStyleContext* aStyleContext,
624 bool& aCanStoreInRuleTree)
626 LengthPercentPairCalcOps ops(aStyleContext, aStyleContext->PresContext(),
627 aCanStoreInRuleTree);
628 nsRuleNode::ComputedCalc vals = ComputeCalc(aValue, ops);
630 nsStyleCoord::Calc* calcObj = new nsStyleCoord::Calc;
632 calcObj->mLength = vals.mLength;
633 calcObj->mPercent = vals.mPercent;
634 calcObj->mHasPercent = ops.mHasPercent;
636 aCoord.SetCalcValue(calcObj);
639 /* static */ nsRuleNode::ComputedCalc
640 nsRuleNode::SpecifiedCalcToComputedCalc(const nsCSSValue& aValue,
641 nsStyleContext* aStyleContext,
642 nsPresContext* aPresContext,
643 bool& aCanStoreInRuleTree)
645 LengthPercentPairCalcOps ops(aStyleContext, aPresContext,
646 aCanStoreInRuleTree);
647 return ComputeCalc(aValue, ops);
650 // This is our public API for handling calc() expressions that involve
651 // percentages.
652 /* static */ nscoord
653 nsRuleNode::ComputeComputedCalc(const nsStyleCoord& aValue,
654 nscoord aPercentageBasis)
656 nsStyleCoord::Calc* calc = aValue.GetCalcValue();
657 return calc->mLength +
658 NSToCoordFloorClamped(aPercentageBasis * calc->mPercent);
661 /* static */ nscoord
662 nsRuleNode::ComputeCoordPercentCalc(const nsStyleCoord& aCoord,
663 nscoord aPercentageBasis)
665 switch (aCoord.GetUnit()) {
666 case eStyleUnit_Coord:
667 return aCoord.GetCoordValue();
668 case eStyleUnit_Percent:
669 return NSToCoordFloorClamped(aPercentageBasis * aCoord.GetPercentValue());
670 case eStyleUnit_Calc:
671 return ComputeComputedCalc(aCoord, aPercentageBasis);
672 default:
673 NS_ABORT_IF_FALSE(false, "unexpected unit");
674 return 0;
678 /* Given an enumerated value that represents a box position, converts it to
679 * a float representing the percentage of the box it corresponds to. For
680 * example, "center" becomes 0.5f.
682 * @param aEnumValue The enumerated value.
683 * @return The float percent it corresponds to.
685 static float
686 GetFloatFromBoxPosition(int32_t aEnumValue)
688 switch (aEnumValue) {
689 case NS_STYLE_BG_POSITION_LEFT:
690 case NS_STYLE_BG_POSITION_TOP:
691 return 0.0f;
692 case NS_STYLE_BG_POSITION_RIGHT:
693 case NS_STYLE_BG_POSITION_BOTTOM:
694 return 1.0f;
695 default:
696 NS_NOTREACHED("unexpected value");
697 // fall through
698 case NS_STYLE_BG_POSITION_CENTER:
699 return 0.5f;
703 #define SETCOORD_NORMAL 0x01 // N
704 #define SETCOORD_AUTO 0x02 // A
705 #define SETCOORD_INHERIT 0x04 // H
706 #define SETCOORD_PERCENT 0x08 // P
707 #define SETCOORD_FACTOR 0x10 // F
708 #define SETCOORD_LENGTH 0x20 // L
709 #define SETCOORD_INTEGER 0x40 // I
710 #define SETCOORD_ENUMERATED 0x80 // E
711 #define SETCOORD_NONE 0x100 // O
712 #define SETCOORD_INITIAL_ZERO 0x200
713 #define SETCOORD_INITIAL_AUTO 0x400
714 #define SETCOORD_INITIAL_NONE 0x800
715 #define SETCOORD_INITIAL_NORMAL 0x1000
716 #define SETCOORD_INITIAL_HALF 0x2000
717 #define SETCOORD_INITIAL_HUNDRED_PCT 0x00004000
718 #define SETCOORD_INITIAL_FACTOR_ONE 0x00008000
719 #define SETCOORD_INITIAL_FACTOR_ZERO 0x00010000
720 #define SETCOORD_CALC_LENGTH_ONLY 0x00020000
721 #define SETCOORD_CALC_CLAMP_NONNEGATIVE 0x00040000 // modifier for CALC_LENGTH_ONLY
722 #define SETCOORD_STORE_CALC 0x00080000
723 #define SETCOORD_BOX_POSITION 0x00100000 // exclusive with _ENUMERATED
724 #define SETCOORD_ANGLE 0x00200000
725 #define SETCOORD_UNSET_INHERIT 0x00400000
726 #define SETCOORD_UNSET_INITIAL 0x00800000
728 #define SETCOORD_LP (SETCOORD_LENGTH | SETCOORD_PERCENT)
729 #define SETCOORD_LH (SETCOORD_LENGTH | SETCOORD_INHERIT)
730 #define SETCOORD_AH (SETCOORD_AUTO | SETCOORD_INHERIT)
731 #define SETCOORD_LAH (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT)
732 #define SETCOORD_LPH (SETCOORD_LP | SETCOORD_INHERIT)
733 #define SETCOORD_LPAH (SETCOORD_LP | SETCOORD_AH)
734 #define SETCOORD_LPE (SETCOORD_LP | SETCOORD_ENUMERATED)
735 #define SETCOORD_LPEH (SETCOORD_LPE | SETCOORD_INHERIT)
736 #define SETCOORD_LPAEH (SETCOORD_LPAH | SETCOORD_ENUMERATED)
737 #define SETCOORD_LPO (SETCOORD_LP | SETCOORD_NONE)
738 #define SETCOORD_LPOH (SETCOORD_LPH | SETCOORD_NONE)
739 #define SETCOORD_LPOEH (SETCOORD_LPOH | SETCOORD_ENUMERATED)
740 #define SETCOORD_LE (SETCOORD_LENGTH | SETCOORD_ENUMERATED)
741 #define SETCOORD_LEH (SETCOORD_LE | SETCOORD_INHERIT)
742 #define SETCOORD_IA (SETCOORD_INTEGER | SETCOORD_AUTO)
743 #define SETCOORD_LAE (SETCOORD_LENGTH | SETCOORD_AUTO | SETCOORD_ENUMERATED)
745 // changes aCoord iff it returns true
746 static bool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
747 const nsStyleCoord& aParentCoord,
748 int32_t aMask, nsStyleContext* aStyleContext,
749 nsPresContext* aPresContext,
750 bool& aCanStoreInRuleTree)
752 bool result = true;
753 if (aValue.GetUnit() == eCSSUnit_Null) {
754 result = false;
756 else if ((((aMask & SETCOORD_LENGTH) != 0) &&
757 aValue.IsLengthUnit()) ||
758 (((aMask & SETCOORD_CALC_LENGTH_ONLY) != 0) &&
759 aValue.IsCalcUnit())) {
760 nscoord len = CalcLength(aValue, aStyleContext, aPresContext,
761 aCanStoreInRuleTree);
762 if ((aMask & SETCOORD_CALC_CLAMP_NONNEGATIVE) && len < 0) {
763 NS_ASSERTION(aValue.IsCalcUnit(),
764 "parser should have ensured no nonnegative lengths");
765 len = 0;
767 aCoord.SetCoordValue(len);
769 else if (((aMask & SETCOORD_PERCENT) != 0) &&
770 (aValue.GetUnit() == eCSSUnit_Percent)) {
771 aCoord.SetPercentValue(aValue.GetPercentValue());
773 else if (((aMask & SETCOORD_INTEGER) != 0) &&
774 (aValue.GetUnit() == eCSSUnit_Integer)) {
775 aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Integer);
777 else if (((aMask & SETCOORD_ENUMERATED) != 0) &&
778 (aValue.GetUnit() == eCSSUnit_Enumerated)) {
779 aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Enumerated);
781 else if (((aMask & SETCOORD_BOX_POSITION) != 0) &&
782 (aValue.GetUnit() == eCSSUnit_Enumerated)) {
783 aCoord.SetPercentValue(GetFloatFromBoxPosition(aValue.GetIntValue()));
785 else if (((aMask & SETCOORD_AUTO) != 0) &&
786 (aValue.GetUnit() == eCSSUnit_Auto)) {
787 aCoord.SetAutoValue();
789 else if ((((aMask & SETCOORD_INHERIT) != 0) &&
790 aValue.GetUnit() == eCSSUnit_Inherit) ||
791 (((aMask & SETCOORD_UNSET_INHERIT) != 0) &&
792 aValue.GetUnit() == eCSSUnit_Unset)) {
793 aCoord = aParentCoord; // just inherit value from parent
794 aCanStoreInRuleTree = false;
796 else if (((aMask & SETCOORD_NORMAL) != 0) &&
797 (aValue.GetUnit() == eCSSUnit_Normal)) {
798 aCoord.SetNormalValue();
800 else if (((aMask & SETCOORD_NONE) != 0) &&
801 (aValue.GetUnit() == eCSSUnit_None)) {
802 aCoord.SetNoneValue();
804 else if (((aMask & SETCOORD_FACTOR) != 0) &&
805 (aValue.GetUnit() == eCSSUnit_Number)) {
806 aCoord.SetFactorValue(aValue.GetFloatValue());
808 else if (((aMask & SETCOORD_STORE_CALC) != 0) &&
809 (aValue.IsCalcUnit())) {
810 SpecifiedCalcToComputedCalc(aValue, aCoord, aStyleContext,
811 aCanStoreInRuleTree);
813 else if (aValue.GetUnit() == eCSSUnit_Initial ||
814 (aValue.GetUnit() == eCSSUnit_Unset &&
815 ((aMask & SETCOORD_UNSET_INITIAL) != 0))) {
816 if ((aMask & SETCOORD_INITIAL_AUTO) != 0) {
817 aCoord.SetAutoValue();
819 else if ((aMask & SETCOORD_INITIAL_ZERO) != 0) {
820 aCoord.SetCoordValue(0);
822 else if ((aMask & SETCOORD_INITIAL_FACTOR_ZERO) != 0) {
823 aCoord.SetFactorValue(0.0f);
825 else if ((aMask & SETCOORD_INITIAL_NONE) != 0) {
826 aCoord.SetNoneValue();
828 else if ((aMask & SETCOORD_INITIAL_NORMAL) != 0) {
829 aCoord.SetNormalValue();
831 else if ((aMask & SETCOORD_INITIAL_HALF) != 0) {
832 aCoord.SetPercentValue(0.5f);
834 else if ((aMask & SETCOORD_INITIAL_HUNDRED_PCT) != 0) {
835 aCoord.SetPercentValue(1.0f);
837 else if ((aMask & SETCOORD_INITIAL_FACTOR_ONE) != 0) {
838 aCoord.SetFactorValue(1.0f);
840 else {
841 result = false; // didn't set anything
844 else if ((aMask & SETCOORD_ANGLE) != 0 &&
845 (aValue.IsAngularUnit())) {
846 nsStyleUnit unit;
847 switch (aValue.GetUnit()) {
848 case eCSSUnit_Degree: unit = eStyleUnit_Degree; break;
849 case eCSSUnit_Grad: unit = eStyleUnit_Grad; break;
850 case eCSSUnit_Radian: unit = eStyleUnit_Radian; break;
851 case eCSSUnit_Turn: unit = eStyleUnit_Turn; break;
852 default: NS_NOTREACHED("unrecognized angular unit");
853 unit = eStyleUnit_Degree;
855 aCoord.SetAngleValue(aValue.GetAngleValue(), unit);
857 else {
858 result = false; // didn't set anything
860 return result;
863 // This inline function offers a shortcut for SetCoord() by refusing to accept
864 // SETCOORD_LENGTH, SETCOORD_INHERIT and SETCOORD_UNSET_* masks.
865 static inline bool SetAbsCoord(const nsCSSValue& aValue,
866 nsStyleCoord& aCoord,
867 int32_t aMask)
869 NS_ABORT_IF_FALSE((aMask & (SETCOORD_LH | SETCOORD_UNSET_INHERIT |
870 SETCOORD_UNSET_INITIAL)) == 0,
871 "does not handle SETCOORD_LENGTH, SETCOORD_INHERIT and "
872 "SETCOORD_UNSET_*");
874 // The values of the following variables will never be used; so it does not
875 // matter what to set.
876 const nsStyleCoord dummyParentCoord;
877 nsStyleContext* dummyStyleContext = nullptr;
878 nsPresContext* dummyPresContext = nullptr;
879 bool dummyCanStoreInRuleTree = true;
881 bool rv = SetCoord(aValue, aCoord, dummyParentCoord, aMask,
882 dummyStyleContext, dummyPresContext,
883 dummyCanStoreInRuleTree);
884 NS_ABORT_IF_FALSE(dummyCanStoreInRuleTree,
885 "SetCoord() should not modify dummyCanStoreInRuleTree.");
887 return rv;
890 /* Given a specified value that might be a pair value, call SetCoord twice,
891 * either using each member of the pair, or using the unpaired value twice.
893 static bool
894 SetPairCoords(const nsCSSValue& aValue,
895 nsStyleCoord& aCoordX, nsStyleCoord& aCoordY,
896 const nsStyleCoord& aParentX, const nsStyleCoord& aParentY,
897 int32_t aMask, nsStyleContext* aStyleContext,
898 nsPresContext* aPresContext, bool& aCanStoreInRuleTree)
900 const nsCSSValue& valX =
901 aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mXValue : aValue;
902 const nsCSSValue& valY =
903 aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mYValue : aValue;
905 bool cX = SetCoord(valX, aCoordX, aParentX, aMask, aStyleContext,
906 aPresContext, aCanStoreInRuleTree);
907 mozilla::DebugOnly<bool> cY = SetCoord(valY, aCoordY, aParentY, aMask,
908 aStyleContext, aPresContext, aCanStoreInRuleTree);
909 NS_ABORT_IF_FALSE(cX == cY, "changed one but not the other");
910 return cX;
913 static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
914 nsPresContext* aPresContext, nsStyleContext *aContext,
915 nscolor& aResult, bool& aCanStoreInRuleTree)
917 bool result = false;
918 nsCSSUnit unit = aValue.GetUnit();
920 if (aValue.IsNumericColorUnit()) {
921 aResult = aValue.GetColorValue();
922 result = true;
924 else if (eCSSUnit_Ident == unit) {
925 nsAutoString value;
926 aValue.GetStringValue(value);
927 nscolor rgba;
928 if (NS_ColorNameToRGB(value, &rgba)) {
929 aResult = rgba;
930 result = true;
933 else if (eCSSUnit_EnumColor == unit) {
934 int32_t intValue = aValue.GetIntValue();
935 if (0 <= intValue) {
936 LookAndFeel::ColorID colorID = (LookAndFeel::ColorID) intValue;
937 if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID, &aResult))) {
938 result = true;
941 else {
942 aResult = NS_RGB(0, 0, 0);
943 result = false;
944 switch (intValue) {
945 case NS_COLOR_MOZ_HYPERLINKTEXT:
946 if (aPresContext) {
947 aResult = aPresContext->DefaultLinkColor();
948 result = true;
950 break;
951 case NS_COLOR_MOZ_VISITEDHYPERLINKTEXT:
952 if (aPresContext) {
953 aResult = aPresContext->DefaultVisitedLinkColor();
954 result = true;
956 break;
957 case NS_COLOR_MOZ_ACTIVEHYPERLINKTEXT:
958 if (aPresContext) {
959 aResult = aPresContext->DefaultActiveLinkColor();
960 result = true;
962 break;
963 case NS_COLOR_CURRENTCOLOR:
964 // The data computed from this can't be shared in the rule tree
965 // because they could be used on a node with a different color
966 aCanStoreInRuleTree = false;
967 if (aContext) {
968 aResult = aContext->StyleColor()->mColor;
969 result = true;
971 break;
972 case NS_COLOR_MOZ_DEFAULT_COLOR:
973 if (aPresContext) {
974 aResult = aPresContext->DefaultColor();
975 result = true;
977 break;
978 case NS_COLOR_MOZ_DEFAULT_BACKGROUND_COLOR:
979 if (aPresContext) {
980 aResult = aPresContext->DefaultBackgroundColor();
981 result = true;
983 break;
984 default:
985 NS_NOTREACHED("Should never have an unknown negative colorID.");
986 break;
990 else if (eCSSUnit_Inherit == unit) {
991 aResult = aParentColor;
992 result = true;
993 aCanStoreInRuleTree = false;
995 else if (eCSSUnit_Enumerated == unit &&
996 aValue.GetIntValue() == NS_STYLE_COLOR_INHERIT_FROM_BODY) {
997 NS_ASSERTION(aPresContext->CompatibilityMode() == eCompatibility_NavQuirks,
998 "Should only get this value in quirks mode");
999 // We just grab the color from the prescontext, and rely on the fact that
1000 // if the body color ever changes all its descendants will get new style
1001 // contexts (but NOT necessarily new rulenodes).
1002 aResult = aPresContext->BodyTextColor();
1003 result = true;
1004 aCanStoreInRuleTree = false;
1006 return result;
1009 static void SetGradientCoord(const nsCSSValue& aValue, nsPresContext* aPresContext,
1010 nsStyleContext* aContext, nsStyleCoord& aResult,
1011 bool& aCanStoreInRuleTree)
1013 // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
1014 if (!SetCoord(aValue, aResult, nsStyleCoord(),
1015 SETCOORD_LPO | SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC,
1016 aContext, aPresContext, aCanStoreInRuleTree)) {
1017 NS_NOTREACHED("unexpected unit for gradient anchor point");
1018 aResult.SetNoneValue();
1022 static void SetGradient(const nsCSSValue& aValue, nsPresContext* aPresContext,
1023 nsStyleContext* aContext, nsStyleGradient& aResult,
1024 bool& aCanStoreInRuleTree)
1026 NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Gradient,
1027 "The given data is not a gradient");
1029 const nsCSSValueGradient* gradient = aValue.GetGradientValue();
1031 if (gradient->mIsExplicitSize) {
1032 SetCoord(gradient->GetRadiusX(), aResult.mRadiusX, nsStyleCoord(),
1033 SETCOORD_LP | SETCOORD_STORE_CALC,
1034 aContext, aPresContext, aCanStoreInRuleTree);
1035 if (gradient->GetRadiusY().GetUnit() != eCSSUnit_None) {
1036 SetCoord(gradient->GetRadiusY(), aResult.mRadiusY, nsStyleCoord(),
1037 SETCOORD_LP | SETCOORD_STORE_CALC,
1038 aContext, aPresContext, aCanStoreInRuleTree);
1039 aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
1040 } else {
1041 aResult.mRadiusY = aResult.mRadiusX;
1042 aResult.mShape = NS_STYLE_GRADIENT_SHAPE_CIRCULAR;
1044 aResult.mSize = NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE;
1045 } else if (gradient->mIsRadial) {
1046 if (gradient->GetRadialShape().GetUnit() == eCSSUnit_Enumerated) {
1047 aResult.mShape = gradient->GetRadialShape().GetIntValue();
1048 } else {
1049 NS_ASSERTION(gradient->GetRadialShape().GetUnit() == eCSSUnit_None,
1050 "bad unit for radial shape");
1051 aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
1053 if (gradient->GetRadialSize().GetUnit() == eCSSUnit_Enumerated) {
1054 aResult.mSize = gradient->GetRadialSize().GetIntValue();
1055 } else {
1056 NS_ASSERTION(gradient->GetRadialSize().GetUnit() == eCSSUnit_None,
1057 "bad unit for radial shape");
1058 aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
1060 } else {
1061 NS_ASSERTION(gradient->GetRadialShape().GetUnit() == eCSSUnit_None,
1062 "bad unit for linear shape");
1063 NS_ASSERTION(gradient->GetRadialSize().GetUnit() == eCSSUnit_None,
1064 "bad unit for linear size");
1065 aResult.mShape = NS_STYLE_GRADIENT_SHAPE_LINEAR;
1066 aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
1069 aResult.mLegacySyntax = gradient->mIsLegacySyntax;
1071 // bg-position
1072 SetGradientCoord(gradient->mBgPos.mXValue, aPresContext, aContext,
1073 aResult.mBgPosX, aCanStoreInRuleTree);
1075 SetGradientCoord(gradient->mBgPos.mYValue, aPresContext, aContext,
1076 aResult.mBgPosY, aCanStoreInRuleTree);
1078 aResult.mRepeating = gradient->mIsRepeating;
1080 // angle
1081 const nsStyleCoord dummyParentCoord;
1082 if (!SetCoord(gradient->mAngle, aResult.mAngle, dummyParentCoord, SETCOORD_ANGLE,
1083 aContext, aPresContext, aCanStoreInRuleTree)) {
1084 NS_ASSERTION(gradient->mAngle.GetUnit() == eCSSUnit_None,
1085 "bad unit for gradient angle");
1086 aResult.mAngle.SetNoneValue();
1089 // stops
1090 for (uint32_t i = 0; i < gradient->mStops.Length(); i++) {
1091 nsStyleGradientStop stop;
1092 const nsCSSValueGradientStop &valueStop = gradient->mStops[i];
1094 if (!SetCoord(valueStop.mLocation, stop.mLocation,
1095 nsStyleCoord(), SETCOORD_LPO | SETCOORD_STORE_CALC,
1096 aContext, aPresContext, aCanStoreInRuleTree)) {
1097 NS_NOTREACHED("unexpected unit for gradient stop location");
1100 // inherit is not a valid color for stops, so we pass in a dummy
1101 // parent color
1102 NS_ASSERTION(valueStop.mColor.GetUnit() != eCSSUnit_Inherit,
1103 "inherit is not a valid color for gradient stops");
1104 SetColor(valueStop.mColor, NS_RGB(0, 0, 0), aPresContext,
1105 aContext, stop.mColor, aCanStoreInRuleTree);
1107 aResult.mStops.AppendElement(stop);
1111 // -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
1112 static void SetStyleImageToImageRect(nsStyleContext* aStyleContext,
1113 const nsCSSValue& aValue,
1114 nsStyleImage& aResult)
1116 NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Function &&
1117 aValue.EqualsFunction(eCSSKeyword__moz_image_rect),
1118 "the value is not valid -moz-image-rect()");
1120 nsCSSValue::Array* arr = aValue.GetArrayValue();
1121 NS_ABORT_IF_FALSE(arr && arr->Count() == 6, "invalid number of arguments");
1123 // <uri>
1124 if (arr->Item(1).GetUnit() == eCSSUnit_Image) {
1125 NS_SET_IMAGE_REQUEST_WITH_DOC(aResult.SetImageData,
1126 aStyleContext,
1127 arr->Item(1).GetImageValue)
1128 } else {
1129 NS_WARNING("nsCSSValue::Image::Image() failed?");
1132 // <top>, <right>, <bottom>, <left>
1133 nsStyleSides cropRect;
1134 NS_FOR_CSS_SIDES(side) {
1135 nsStyleCoord coord;
1136 const nsCSSValue& val = arr->Item(2 + side);
1138 #ifdef DEBUG
1139 bool unitOk =
1140 #endif
1141 SetAbsCoord(val, coord, SETCOORD_FACTOR | SETCOORD_PERCENT);
1142 NS_ABORT_IF_FALSE(unitOk, "Incorrect data structure created by CSS parser");
1143 cropRect.Set(side, coord);
1145 aResult.SetCropRect(&cropRect);
1148 static void SetStyleImage(nsStyleContext* aStyleContext,
1149 const nsCSSValue& aValue,
1150 nsStyleImage& aResult,
1151 bool& aCanStoreInRuleTree)
1153 if (aValue.GetUnit() == eCSSUnit_Null) {
1154 return;
1157 aResult.SetNull();
1159 switch (aValue.GetUnit()) {
1160 case eCSSUnit_Image:
1161 NS_SET_IMAGE_REQUEST_WITH_DOC(aResult.SetImageData,
1162 aStyleContext,
1163 aValue.GetImageValue)
1164 break;
1165 case eCSSUnit_Function:
1166 if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
1167 SetStyleImageToImageRect(aStyleContext, aValue, aResult);
1168 } else {
1169 NS_NOTREACHED("-moz-image-rect() is the only expected function");
1171 break;
1172 case eCSSUnit_Gradient:
1174 nsStyleGradient* gradient = new nsStyleGradient();
1175 if (gradient) {
1176 SetGradient(aValue, aStyleContext->PresContext(), aStyleContext,
1177 *gradient, aCanStoreInRuleTree);
1178 aResult.SetGradientData(gradient);
1180 break;
1182 case eCSSUnit_Element:
1183 aResult.SetElementId(aValue.GetStringBufferValue());
1184 break;
1185 case eCSSUnit_Initial:
1186 case eCSSUnit_Unset:
1187 case eCSSUnit_None:
1188 break;
1189 default:
1190 // We might have eCSSUnit_URL values for if-visited style
1191 // contexts, which we can safely treat like 'none'. Otherwise
1192 // this is an unexpected unit.
1193 NS_ASSERTION(aStyleContext->IsStyleIfVisited() &&
1194 aValue.GetUnit() == eCSSUnit_URL,
1195 "unexpected unit; maybe nsCSSValue::Image::Image() failed?");
1196 break;
1200 // flags for SetDiscrete - align values with SETCOORD_* constants
1201 // where possible
1203 #define SETDSC_NORMAL 0x01 // N
1204 #define SETDSC_AUTO 0x02 // A
1205 #define SETDSC_INTEGER 0x40 // I
1206 #define SETDSC_ENUMERATED 0x80 // E
1207 #define SETDSC_NONE 0x100 // O
1208 #define SETDSC_SYSTEM_FONT 0x2000
1209 #define SETDSC_UNSET_INHERIT 0x00400000
1210 #define SETDSC_UNSET_INITIAL 0x00800000
1212 // no caller cares whether aField was changed or not
1213 template <typename FieldT,
1214 typename T1, typename T2, typename T3, typename T4, typename T5>
1215 static void
1216 SetDiscrete(const nsCSSValue& aValue, FieldT & aField,
1217 bool& aCanStoreInRuleTree, uint32_t aMask,
1218 FieldT aParentValue,
1219 T1 aInitialValue,
1220 T2 aAutoValue,
1221 T3 aNoneValue,
1222 T4 aNormalValue,
1223 T5 aSystemFontValue)
1225 switch (aValue.GetUnit()) {
1226 case eCSSUnit_Null:
1227 return;
1229 // every caller of SetDiscrete provides inherit and initial
1230 // alternatives, so we don't require them to say so in the mask
1231 case eCSSUnit_Inherit:
1232 aCanStoreInRuleTree = false;
1233 aField = aParentValue;
1234 return;
1236 case eCSSUnit_Initial:
1237 aField = aInitialValue;
1238 return;
1240 // every caller provides one or other of these alternatives,
1241 // but they have to say which
1242 case eCSSUnit_Enumerated:
1243 if (aMask & SETDSC_ENUMERATED) {
1244 aField = aValue.GetIntValue();
1245 return;
1247 break;
1249 case eCSSUnit_Integer:
1250 if (aMask & SETDSC_INTEGER) {
1251 aField = aValue.GetIntValue();
1252 return;
1254 break;
1256 // remaining possibilities in descending order of frequency of use
1257 case eCSSUnit_Auto:
1258 if (aMask & SETDSC_AUTO) {
1259 aField = aAutoValue;
1260 return;
1262 break;
1264 case eCSSUnit_None:
1265 if (aMask & SETDSC_NONE) {
1266 aField = aNoneValue;
1267 return;
1269 break;
1271 case eCSSUnit_Normal:
1272 if (aMask & SETDSC_NORMAL) {
1273 aField = aNormalValue;
1274 return;
1276 break;
1278 case eCSSUnit_System_Font:
1279 if (aMask & SETDSC_SYSTEM_FONT) {
1280 aField = aSystemFontValue;
1281 return;
1283 break;
1285 case eCSSUnit_Unset:
1286 if (aMask & SETDSC_UNSET_INHERIT) {
1287 aCanStoreInRuleTree = false;
1288 aField = aParentValue;
1289 return;
1291 if (aMask & SETDSC_UNSET_INITIAL) {
1292 aField = aInitialValue;
1293 return;
1295 break;
1297 default:
1298 break;
1301 NS_NOTREACHED("SetDiscrete: inappropriate unit");
1304 // flags for SetFactor
1305 #define SETFCT_POSITIVE 0x01 // assert value is >= 0.0f
1306 #define SETFCT_OPACITY 0x02 // clamp value to [0.0f .. 1.0f]
1307 #define SETFCT_NONE 0x04 // allow _None (uses aInitialValue).
1308 #define SETFCT_UNSET_INHERIT 0x00400000
1309 #define SETFCT_UNSET_INITIAL 0x00800000
1311 static void
1312 SetFactor(const nsCSSValue& aValue, float& aField, bool& aCanStoreInRuleTree,
1313 float aParentValue, float aInitialValue, uint32_t aFlags = 0)
1315 switch (aValue.GetUnit()) {
1316 case eCSSUnit_Null:
1317 return;
1319 case eCSSUnit_Number:
1320 aField = aValue.GetFloatValue();
1321 if (aFlags & SETFCT_POSITIVE) {
1322 NS_ASSERTION(aField >= 0.0f, "negative value for positive-only property");
1323 if (aField < 0.0f)
1324 aField = 0.0f;
1326 if (aFlags & SETFCT_OPACITY) {
1327 if (aField < 0.0f)
1328 aField = 0.0f;
1329 if (aField > 1.0f)
1330 aField = 1.0f;
1332 return;
1334 case eCSSUnit_Inherit:
1335 aCanStoreInRuleTree = false;
1336 aField = aParentValue;
1337 return;
1339 case eCSSUnit_Initial:
1340 aField = aInitialValue;
1341 return;
1343 case eCSSUnit_None:
1344 if (aFlags & SETFCT_NONE) {
1345 aField = aInitialValue;
1346 return;
1348 break;
1350 case eCSSUnit_Unset:
1351 if (aFlags & SETFCT_UNSET_INHERIT) {
1352 aCanStoreInRuleTree = false;
1353 aField = aParentValue;
1354 return;
1356 if (aFlags & SETFCT_UNSET_INITIAL) {
1357 aField = aInitialValue;
1358 return;
1360 break;
1362 default:
1363 break;
1366 NS_NOTREACHED("SetFactor: inappropriate unit");
1369 // Overloaded new operator that allocates from a presShell arena.
1370 void*
1371 nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
1373 // Check the recycle list first.
1374 return aPresContext->PresShell()->AllocateByObjectID(nsPresArena::nsRuleNode_id, sz);
1377 /* static */ PLDHashOperator
1378 nsRuleNode::EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
1379 uint32_t number, void *arg)
1381 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
1382 nsRuleNode ***destroyQueueTail = static_cast<nsRuleNode***>(arg);
1383 **destroyQueueTail = entry->mRuleNode;
1384 *destroyQueueTail = &entry->mRuleNode->mNextSibling;
1385 return PL_DHASH_NEXT;
1388 // Overridden to prevent the global delete from being called, since the memory
1389 // came out of an nsIArena instead of the global delete operator's heap.
1390 void
1391 nsRuleNode::DestroyInternal(nsRuleNode ***aDestroyQueueTail)
1393 nsRuleNode *destroyQueue, **destroyQueueTail;
1394 if (aDestroyQueueTail) {
1395 destroyQueueTail = *aDestroyQueueTail;
1396 } else {
1397 destroyQueue = nullptr;
1398 destroyQueueTail = &destroyQueue;
1401 if (ChildrenAreHashed()) {
1402 PLDHashTable *children = ChildrenHash();
1403 PL_DHashTableEnumerate(children, EnqueueRuleNodeChildren,
1404 &destroyQueueTail);
1405 *destroyQueueTail = nullptr; // ensure null-termination
1406 PL_DHashTableDestroy(children);
1407 } else if (HaveChildren()) {
1408 *destroyQueueTail = ChildrenList();
1409 do {
1410 destroyQueueTail = &(*destroyQueueTail)->mNextSibling;
1411 } while (*destroyQueueTail);
1413 mChildren.asVoid = nullptr;
1415 if (aDestroyQueueTail) {
1416 // Our caller destroys the queue.
1417 *aDestroyQueueTail = destroyQueueTail;
1418 } else {
1419 // We have to do destroy the queue. When we destroy each node, it
1420 // will add its children to the queue.
1421 while (destroyQueue) {
1422 nsRuleNode *cur = destroyQueue;
1423 destroyQueue = destroyQueue->mNextSibling;
1424 if (!destroyQueue) {
1425 NS_ASSERTION(destroyQueueTail == &cur->mNextSibling, "mangled list");
1426 destroyQueueTail = &destroyQueue;
1428 cur->DestroyInternal(&destroyQueueTail);
1432 // Destroy ourselves.
1433 this->~nsRuleNode();
1435 // Don't let the memory be freed, since it will be recycled
1436 // instead. Don't call the global operator delete.
1437 mPresContext->PresShell()->FreeByObjectID(nsPresArena::nsRuleNode_id, this);
1440 nsRuleNode* nsRuleNode::CreateRootNode(nsPresContext* aPresContext)
1442 return new (aPresContext)
1443 nsRuleNode(aPresContext, nullptr, nullptr, 0xff, false);
1446 nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
1447 nsIStyleRule* aRule, uint8_t aLevel,
1448 bool aIsImportant)
1449 : mPresContext(aContext),
1450 mParent(aParent),
1451 mRule(aRule),
1452 mNextSibling(nullptr),
1453 mDependentBits((uint32_t(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
1454 (aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
1455 mNoneBits(0),
1456 mRefCnt(0)
1458 MOZ_ASSERT(aContext);
1459 NS_ABORT_IF_FALSE(IsRoot() == !aRule,
1460 "non-root rule nodes must have a rule");
1462 mChildren.asVoid = nullptr;
1463 MOZ_COUNT_CTOR(nsRuleNode);
1465 if (mRule) {
1466 mRule->AddRef();
1469 NS_ASSERTION(IsRoot() || GetLevel() == aLevel, "not enough bits");
1470 NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes");
1471 /* If IsRoot(), then aContext->StyleSet() is typically null at this
1472 point. In any case, we don't want to treat the root rulenode as
1473 unused. */
1474 if (!IsRoot()) {
1475 mParent->AddRef();
1476 aContext->StyleSet()->RuleNodeUnused();
1479 // nsStyleSet::GetContext depends on there being only one animation
1480 // rule.
1481 NS_ABORT_IF_FALSE(IsRoot() || GetLevel() != nsStyleSet::eAnimationSheet ||
1482 mParent->IsRoot() ||
1483 mParent->GetLevel() != nsStyleSet::eAnimationSheet,
1484 "must be only one rule at animation level");
1487 nsRuleNode::~nsRuleNode()
1489 MOZ_COUNT_DTOR(nsRuleNode);
1490 if (mStyleData.mResetData || mStyleData.mInheritedData)
1491 mStyleData.Destroy(mDependentBits, mPresContext);
1492 if (mRule) {
1493 mRule->Release();
1497 nsRuleNode*
1498 nsRuleNode::Transition(nsIStyleRule* aRule, uint8_t aLevel,
1499 bool aIsImportantRule)
1501 nsRuleNode* next = nullptr;
1502 nsRuleNode::Key key(aRule, aLevel, aIsImportantRule);
1504 if (HaveChildren() && !ChildrenAreHashed()) {
1505 int32_t numKids = 0;
1506 nsRuleNode* curr = ChildrenList();
1507 while (curr && curr->GetKey() != key) {
1508 curr = curr->mNextSibling;
1509 ++numKids;
1511 if (curr)
1512 next = curr;
1513 else if (numKids >= kMaxChildrenInList)
1514 ConvertChildrenToHash(numKids);
1517 if (ChildrenAreHashed()) {
1518 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>
1519 (PL_DHashTableOperate(ChildrenHash(), &key, PL_DHASH_ADD));
1520 if (!entry) {
1521 NS_WARNING("out of memory");
1522 return this;
1524 if (entry->mRuleNode)
1525 next = entry->mRuleNode;
1526 else {
1527 next = entry->mRuleNode = new (mPresContext)
1528 nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
1529 if (!next) {
1530 PL_DHashTableRawRemove(ChildrenHash(), entry);
1531 NS_WARNING("out of memory");
1532 return this;
1535 } else if (!next) {
1536 // Create the new entry in our list.
1537 next = new (mPresContext)
1538 nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
1539 if (!next) {
1540 NS_WARNING("out of memory");
1541 return this;
1543 next->mNextSibling = ChildrenList();
1544 SetChildrenList(next);
1547 return next;
1550 void nsRuleNode::SetUsedDirectly()
1552 mDependentBits |= NS_RULE_NODE_USED_DIRECTLY;
1554 // Maintain the invariant that any rule node that is used directly has
1555 // all structs that live in the rule tree cached (which
1556 // nsRuleNode::GetStyleData depends on for speed).
1557 if (mDependentBits & NS_STYLE_INHERIT_MASK) {
1558 for (nsStyleStructID sid = nsStyleStructID(0); sid < nsStyleStructID_Length;
1559 sid = nsStyleStructID(sid + 1)) {
1560 uint32_t bit = nsCachedStyleData::GetBitForSID(sid);
1561 if (mDependentBits & bit) {
1562 nsRuleNode *source = mParent;
1563 while ((source->mDependentBits & bit) && !source->IsUsedDirectly()) {
1564 source = source->mParent;
1566 void *data = source->mStyleData.GetStyleData(sid);
1567 NS_ASSERTION(data, "unexpected null struct");
1568 mStyleData.SetStyleData(sid, mPresContext, data);
1574 void
1575 nsRuleNode::ConvertChildrenToHash(int32_t aNumKids)
1577 NS_ASSERTION(!ChildrenAreHashed() && HaveChildren(),
1578 "must have a non-empty list of children");
1579 PLDHashTable *hash = PL_NewDHashTable(&ChildrenHashOps, nullptr,
1580 sizeof(ChildrenHashEntry),
1581 aNumKids);
1582 if (!hash)
1583 return;
1584 for (nsRuleNode* curr = ChildrenList(); curr; curr = curr->mNextSibling) {
1585 // This will never fail because of the initial size we gave the table.
1586 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(
1587 PL_DHashTableOperate(hash, curr->mRule, PL_DHASH_ADD));
1588 NS_ASSERTION(!entry->mRuleNode, "duplicate entries in list");
1589 entry->mRuleNode = curr;
1591 SetChildrenHash(hash);
1594 inline void
1595 nsRuleNode::PropagateNoneBit(uint32_t aBit, nsRuleNode* aHighestNode)
1597 nsRuleNode* curr = this;
1598 for (;;) {
1599 NS_ASSERTION(!(curr->mNoneBits & aBit), "propagating too far");
1600 curr->mNoneBits |= aBit;
1601 if (curr == aHighestNode)
1602 break;
1603 curr = curr->mParent;
1607 inline void
1608 nsRuleNode::PropagateDependentBit(nsStyleStructID aSID, nsRuleNode* aHighestNode,
1609 void* aStruct)
1611 NS_ASSERTION(aStruct, "expected struct");
1613 uint32_t bit = nsCachedStyleData::GetBitForSID(aSID);
1614 for (nsRuleNode* curr = this; curr != aHighestNode; curr = curr->mParent) {
1615 if (curr->mDependentBits & bit) {
1616 #ifdef DEBUG
1617 while (curr != aHighestNode) {
1618 NS_ASSERTION(curr->mDependentBits & bit, "bit not set");
1619 curr = curr->mParent;
1621 #endif
1622 break;
1625 curr->mDependentBits |= bit;
1627 if (curr->IsUsedDirectly()) {
1628 curr->mStyleData.SetStyleData(aSID, mPresContext, aStruct);
1634 * The following "Check" functions are used for determining what type of
1635 * sharing can be used for the data on this rule node. MORE HERE...
1639 * a callback function that that can revise the result of
1640 * CheckSpecifiedProperties before finishing; aResult is the current
1641 * result, and it returns the revised one.
1643 typedef nsRuleNode::RuleDetail
1644 (* CheckCallbackFn)(const nsRuleData* aRuleData,
1645 nsRuleNode::RuleDetail aResult);
1648 * @param aValue the value being examined
1649 * @param aSpecifiedCount to be incremented by one if the value is specified
1650 * @param aInheritedCount to be incremented by one if the value is set to inherit
1651 * @param aUnsetCount to be incremented by one if the value is set to unset
1653 inline void
1654 ExamineCSSValue(const nsCSSValue& aValue,
1655 uint32_t& aSpecifiedCount,
1656 uint32_t& aInheritedCount,
1657 uint32_t& aUnsetCount)
1659 if (aValue.GetUnit() != eCSSUnit_Null) {
1660 ++aSpecifiedCount;
1661 if (aValue.GetUnit() == eCSSUnit_Inherit) {
1662 ++aInheritedCount;
1663 } else if (aValue.GetUnit() == eCSSUnit_Unset) {
1664 ++aUnsetCount;
1669 static nsRuleNode::RuleDetail
1670 CheckFontCallback(const nsRuleData* aRuleData,
1671 nsRuleNode::RuleDetail aResult)
1673 // em, ex, percent, 'larger', and 'smaller' values on font-size depend
1674 // on the parent context's font-size
1675 // Likewise, 'lighter' and 'bolder' values of 'font-weight', and 'wider'
1676 // and 'narrower' values of 'font-stretch' depend on the parent.
1677 const nsCSSValue& size = *aRuleData->ValueForFontSize();
1678 const nsCSSValue& weight = *aRuleData->ValueForFontWeight();
1679 if ((size.IsRelativeLengthUnit() && size.GetUnit() != eCSSUnit_RootEM) ||
1680 size.GetUnit() == eCSSUnit_Percent ||
1681 (size.GetUnit() == eCSSUnit_Enumerated &&
1682 (size.GetIntValue() == NS_STYLE_FONT_SIZE_SMALLER ||
1683 size.GetIntValue() == NS_STYLE_FONT_SIZE_LARGER)) ||
1684 aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Integer ||
1685 (weight.GetUnit() == eCSSUnit_Enumerated &&
1686 (weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_BOLDER ||
1687 weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_LIGHTER))) {
1688 NS_ASSERTION(aResult == nsRuleNode::eRulePartialReset ||
1689 aResult == nsRuleNode::eRuleFullReset ||
1690 aResult == nsRuleNode::eRulePartialMixed ||
1691 aResult == nsRuleNode::eRuleFullMixed,
1692 "we know we already have a reset-counted property");
1693 // Promote reset to mixed since we have something that depends on
1694 // the parent. But never promote to inherited since that could
1695 // cause inheritance of the exact value.
1696 if (aResult == nsRuleNode::eRulePartialReset)
1697 aResult = nsRuleNode::eRulePartialMixed;
1698 else if (aResult == nsRuleNode::eRuleFullReset)
1699 aResult = nsRuleNode::eRuleFullMixed;
1702 return aResult;
1705 static nsRuleNode::RuleDetail
1706 CheckColorCallback(const nsRuleData* aRuleData,
1707 nsRuleNode::RuleDetail aResult)
1709 // currentColor values for color require inheritance
1710 const nsCSSValue* colorValue = aRuleData->ValueForColor();
1711 if (colorValue->GetUnit() == eCSSUnit_EnumColor &&
1712 colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
1713 NS_ASSERTION(aResult == nsRuleNode::eRuleFullReset,
1714 "we should already be counted as full-reset");
1715 aResult = nsRuleNode::eRuleFullInherited;
1718 return aResult;
1721 static nsRuleNode::RuleDetail
1722 CheckTextCallback(const nsRuleData* aRuleData,
1723 nsRuleNode::RuleDetail aResult)
1725 const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
1726 if (textAlignValue->GetUnit() == eCSSUnit_Enumerated &&
1727 textAlignValue->GetIntValue() ==
1728 NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT) {
1729 // Promote reset to mixed since we have something that depends on
1730 // the parent.
1731 if (aResult == nsRuleNode::eRulePartialReset)
1732 aResult = nsRuleNode::eRulePartialMixed;
1733 else if (aResult == nsRuleNode::eRuleFullReset)
1734 aResult = nsRuleNode::eRuleFullMixed;
1737 return aResult;
1740 static nsRuleNode::RuleDetail
1741 CheckVariablesCallback(const nsRuleData* aRuleData,
1742 nsRuleNode::RuleDetail aResult)
1744 // We don't actually have any properties on nsStyleVariables, so we do
1745 // all of the RuleDetail calculation in here.
1746 if (aRuleData->mVariables) {
1747 return nsRuleNode::eRulePartialMixed;
1749 return nsRuleNode::eRuleNone;
1752 #define FLAG_DATA_FOR_PROPERTY(name_, id_, method_, flags_, pref_, \
1753 parsevariant_, kwtable_, stylestructoffset_, \
1754 animtype_) \
1755 flags_,
1757 // The order here must match the enums in *CheckCounter in nsCSSProps.cpp.
1759 static const uint32_t gFontFlags[] = {
1760 #define CSS_PROP_FONT FLAG_DATA_FOR_PROPERTY
1761 #include "nsCSSPropList.h"
1762 #undef CSS_PROP_FONT
1765 static const uint32_t gDisplayFlags[] = {
1766 #define CSS_PROP_DISPLAY FLAG_DATA_FOR_PROPERTY
1767 #include "nsCSSPropList.h"
1768 #undef CSS_PROP_DISPLAY
1771 static const uint32_t gVisibilityFlags[] = {
1772 #define CSS_PROP_VISIBILITY FLAG_DATA_FOR_PROPERTY
1773 #include "nsCSSPropList.h"
1774 #undef CSS_PROP_VISIBILITY
1777 static const uint32_t gMarginFlags[] = {
1778 #define CSS_PROP_MARGIN FLAG_DATA_FOR_PROPERTY
1779 #include "nsCSSPropList.h"
1780 #undef CSS_PROP_MARGIN
1783 static const uint32_t gBorderFlags[] = {
1784 #define CSS_PROP_BORDER FLAG_DATA_FOR_PROPERTY
1785 #include "nsCSSPropList.h"
1786 #undef CSS_PROP_BORDER
1789 static const uint32_t gPaddingFlags[] = {
1790 #define CSS_PROP_PADDING FLAG_DATA_FOR_PROPERTY
1791 #include "nsCSSPropList.h"
1792 #undef CSS_PROP_PADDING
1795 static const uint32_t gOutlineFlags[] = {
1796 #define CSS_PROP_OUTLINE FLAG_DATA_FOR_PROPERTY
1797 #include "nsCSSPropList.h"
1798 #undef CSS_PROP_OUTLINE
1801 static const uint32_t gListFlags[] = {
1802 #define CSS_PROP_LIST FLAG_DATA_FOR_PROPERTY
1803 #include "nsCSSPropList.h"
1804 #undef CSS_PROP_LIST
1807 static const uint32_t gColorFlags[] = {
1808 #define CSS_PROP_COLOR FLAG_DATA_FOR_PROPERTY
1809 #include "nsCSSPropList.h"
1810 #undef CSS_PROP_COLOR
1813 static const uint32_t gBackgroundFlags[] = {
1814 #define CSS_PROP_BACKGROUND FLAG_DATA_FOR_PROPERTY
1815 #include "nsCSSPropList.h"
1816 #undef CSS_PROP_BACKGROUND
1819 static const uint32_t gPositionFlags[] = {
1820 #define CSS_PROP_POSITION FLAG_DATA_FOR_PROPERTY
1821 #include "nsCSSPropList.h"
1822 #undef CSS_PROP_POSITION
1825 static const uint32_t gTableFlags[] = {
1826 #define CSS_PROP_TABLE FLAG_DATA_FOR_PROPERTY
1827 #include "nsCSSPropList.h"
1828 #undef CSS_PROP_TABLE
1831 static const uint32_t gTableBorderFlags[] = {
1832 #define CSS_PROP_TABLEBORDER FLAG_DATA_FOR_PROPERTY
1833 #include "nsCSSPropList.h"
1834 #undef CSS_PROP_TABLEBORDER
1837 static const uint32_t gContentFlags[] = {
1838 #define CSS_PROP_CONTENT FLAG_DATA_FOR_PROPERTY
1839 #include "nsCSSPropList.h"
1840 #undef CSS_PROP_CONTENT
1843 static const uint32_t gQuotesFlags[] = {
1844 #define CSS_PROP_QUOTES FLAG_DATA_FOR_PROPERTY
1845 #include "nsCSSPropList.h"
1846 #undef CSS_PROP_QUOTES
1849 static const uint32_t gTextFlags[] = {
1850 #define CSS_PROP_TEXT FLAG_DATA_FOR_PROPERTY
1851 #include "nsCSSPropList.h"
1852 #undef CSS_PROP_TEXT
1855 static const uint32_t gTextResetFlags[] = {
1856 #define CSS_PROP_TEXTRESET FLAG_DATA_FOR_PROPERTY
1857 #include "nsCSSPropList.h"
1858 #undef CSS_PROP_TEXTRESET
1861 static const uint32_t gUserInterfaceFlags[] = {
1862 #define CSS_PROP_USERINTERFACE FLAG_DATA_FOR_PROPERTY
1863 #include "nsCSSPropList.h"
1864 #undef CSS_PROP_USERINTERFACE
1867 static const uint32_t gUIResetFlags[] = {
1868 #define CSS_PROP_UIRESET FLAG_DATA_FOR_PROPERTY
1869 #include "nsCSSPropList.h"
1870 #undef CSS_PROP_UIRESET
1873 static const uint32_t gXULFlags[] = {
1874 #define CSS_PROP_XUL FLAG_DATA_FOR_PROPERTY
1875 #include "nsCSSPropList.h"
1876 #undef CSS_PROP_XUL
1879 static const uint32_t gSVGFlags[] = {
1880 #define CSS_PROP_SVG FLAG_DATA_FOR_PROPERTY
1881 #include "nsCSSPropList.h"
1882 #undef CSS_PROP_SVG
1885 static const uint32_t gSVGResetFlags[] = {
1886 #define CSS_PROP_SVGRESET FLAG_DATA_FOR_PROPERTY
1887 #include "nsCSSPropList.h"
1888 #undef CSS_PROP_SVGRESET
1891 static const uint32_t gColumnFlags[] = {
1892 #define CSS_PROP_COLUMN FLAG_DATA_FOR_PROPERTY
1893 #include "nsCSSPropList.h"
1894 #undef CSS_PROP_COLUMN
1897 // There are no properties in nsStyleVariables, but we can't have a
1898 // zero length array.
1899 static const uint32_t gVariablesFlags[] = {
1901 #define CSS_PROP_VARIABLES FLAG_DATA_FOR_PROPERTY
1902 #include "nsCSSPropList.h"
1903 #undef CSS_PROP_VARIABLES
1905 static_assert(sizeof(gVariablesFlags) == sizeof(uint32_t),
1906 "if nsStyleVariables has properties now you can remove the dummy "
1907 "gVariablesFlags entry");
1909 #undef FLAG_DATA_FOR_PROPERTY
1911 static const uint32_t* gFlagsByStruct[] = {
1913 #define STYLE_STRUCT(name, checkdata_cb) \
1914 g##name##Flags,
1915 #include "nsStyleStructList.h"
1916 #undef STYLE_STRUCT
1920 static const CheckCallbackFn gCheckCallbacks[] = {
1922 #define STYLE_STRUCT(name, checkdata_cb) \
1923 checkdata_cb,
1924 #include "nsStyleStructList.h"
1925 #undef STYLE_STRUCT
1929 #ifdef DEBUG
1930 static bool
1931 AreAllMathMLPropertiesUndefined(const nsRuleData* aRuleData)
1933 return
1934 aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Null &&
1935 aRuleData->ValueForScriptSizeMultiplier()->GetUnit() == eCSSUnit_Null &&
1936 aRuleData->ValueForScriptMinSize()->GetUnit() == eCSSUnit_Null &&
1937 aRuleData->ValueForMathVariant()->GetUnit() == eCSSUnit_Null &&
1938 aRuleData->ValueForMathDisplay()->GetUnit() == eCSSUnit_Null;
1940 #endif
1942 inline nsRuleNode::RuleDetail
1943 nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID,
1944 const nsRuleData* aRuleData)
1946 // Build a count of the:
1947 uint32_t total = 0, // total number of props in the struct
1948 specified = 0, // number that were specified for this node
1949 inherited = 0, // number that were 'inherit' (and not
1950 // eCSSUnit_Inherit) for this node
1951 unset = 0; // number that were 'unset'
1953 // See comment in nsRuleData.h above mValueOffsets.
1954 NS_ABORT_IF_FALSE(aRuleData->mValueOffsets[aSID] == 0,
1955 "we assume the value offset is zero instead of adding it");
1956 for (nsCSSValue *values = aRuleData->mValueStorage,
1957 *values_end = values + nsCSSProps::PropertyCountInStruct(aSID);
1958 values != values_end; ++values) {
1959 ++total;
1960 ExamineCSSValue(*values, specified, inherited, unset);
1963 if (!nsCachedStyleData::IsReset(aSID)) {
1964 // For inherited properties, 'unset' means the same as 'inherit'.
1965 inherited += unset;
1966 unset = 0;
1969 #if 0
1970 printf("CheckSpecifiedProperties: SID=%d total=%d spec=%d inh=%d.\n",
1971 aSID, total, specified, inherited);
1972 #endif
1974 NS_ASSERTION(aSID != eStyleStruct_Font ||
1975 mPresContext->Document()->GetMathMLEnabled() ||
1976 AreAllMathMLPropertiesUndefined(aRuleData),
1977 "MathML style property was defined even though MathML is disabled");
1980 * Return the most specific information we can: prefer None or Full
1981 * over Partial, and Reset or Inherited over Mixed, since we can
1982 * optimize based on the edge cases and not the in-between cases.
1984 nsRuleNode::RuleDetail result;
1985 if (inherited == total)
1986 result = eRuleFullInherited;
1987 else if (specified == total
1988 // MathML defines 5 properties in Font that will never be set when
1989 // MathML is not in use. Therefore if all but five
1990 // properties have been set, and MathML is not enabled, we can treat
1991 // this as fully specified. Code in nsMathMLElementFactory will
1992 // rebuild the rule tree and style data when MathML is first enabled
1993 // (see nsMathMLElement::BindToTree).
1994 || (aSID == eStyleStruct_Font && specified + 5 == total &&
1995 !mPresContext->Document()->GetMathMLEnabled())
1997 if (inherited == 0)
1998 result = eRuleFullReset;
1999 else
2000 result = eRuleFullMixed;
2001 } else if (specified == 0)
2002 result = eRuleNone;
2003 else if (specified == inherited)
2004 result = eRulePartialInherited;
2005 else if (inherited == 0)
2006 result = eRulePartialReset;
2007 else
2008 result = eRulePartialMixed;
2010 CheckCallbackFn cb = gCheckCallbacks[aSID];
2011 if (cb) {
2012 result = (*cb)(aRuleData, result);
2015 return result;
2018 // If we need to restrict which properties apply to the style context,
2019 // return the bit to check in nsCSSProp's flags table. Otherwise,
2020 // return 0.
2021 inline uint32_t
2022 GetPseudoRestriction(nsStyleContext *aContext)
2024 // This needs to match nsStyleSet::WalkRestrictionRule.
2025 uint32_t pseudoRestriction = 0;
2026 nsIAtom *pseudoType = aContext->GetPseudo();
2027 if (pseudoType) {
2028 if (pseudoType == nsCSSPseudoElements::firstLetter) {
2029 pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LETTER;
2030 } else if (pseudoType == nsCSSPseudoElements::firstLine) {
2031 pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LINE;
2032 } else if (pseudoType == nsCSSPseudoElements::mozPlaceholder) {
2033 pseudoRestriction = CSS_PROPERTY_APPLIES_TO_PLACEHOLDER;
2036 return pseudoRestriction;
2039 static void
2040 UnsetPropertiesWithoutFlags(const nsStyleStructID aSID,
2041 nsRuleData* aRuleData,
2042 uint32_t aFlags)
2044 NS_ASSERTION(aFlags != 0, "aFlags must be nonzero");
2046 const uint32_t *flagData = gFlagsByStruct[aSID];
2048 // See comment in nsRuleData.h above mValueOffsets.
2049 NS_ABORT_IF_FALSE(aRuleData->mValueOffsets[aSID] == 0,
2050 "we assume the value offset is zero instead of adding it");
2051 nsCSSValue *values = aRuleData->mValueStorage;
2053 for (size_t i = 0, i_end = nsCSSProps::PropertyCountInStruct(aSID);
2054 i != i_end; ++i) {
2055 if ((flagData[i] & aFlags) != aFlags)
2056 values[i].Reset();
2061 * We allocate arrays of CSS values with alloca. (These arrays are a
2062 * fixed size per style struct, but we don't want to waste the
2063 * allocation and construction/destruction costs of the big structs when
2064 * we're handling much smaller ones.) Since the lifetime of an alloca
2065 * allocation is the life of the calling function, the caller must call
2066 * alloca. However, to ensure that constructors and destructors are
2067 * balanced, we do the constructor and destructor calling from this RAII
2068 * class, AutoCSSValueArray.
2070 struct AutoCSSValueArray {
2072 * aStorage must be the result of alloca(aCount * sizeof(nsCSSValue))
2074 AutoCSSValueArray(void* aStorage, size_t aCount) {
2075 NS_ABORT_IF_FALSE(size_t(aStorage) % NS_ALIGNMENT_OF(nsCSSValue) == 0,
2076 "bad alignment from alloca");
2077 mCount = aCount;
2078 // Don't use placement new[], since it might store extra data
2079 // for the count (on Windows!).
2080 mArray = static_cast<nsCSSValue*>(aStorage);
2081 for (size_t i = 0; i < mCount; ++i) {
2082 new (mArray + i) nsCSSValue();
2086 ~AutoCSSValueArray() {
2087 for (size_t i = 0; i < mCount; ++i) {
2088 mArray[i].~nsCSSValue();
2092 nsCSSValue* get() { return mArray; }
2094 private:
2095 nsCSSValue *mArray;
2096 size_t mCount;
2099 /* static */ bool
2100 nsRuleNode::ResolveVariableReferences(const nsStyleStructID aSID,
2101 nsRuleData* aRuleData,
2102 nsStyleContext* aContext)
2104 MOZ_ASSERT(aSID != eStyleStruct_Variables);
2105 MOZ_ASSERT(aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(aSID));
2106 MOZ_ASSERT(aRuleData->mValueOffsets[aSID] == 0);
2108 nsCSSParser parser;
2109 bool anyTokenStreams = false;
2111 // Look at each property in the nsRuleData for the given style struct.
2112 size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
2113 for (nsCSSValue* value = aRuleData->mValueStorage,
2114 *values_end = aRuleData->mValueStorage + nprops;
2115 value != values_end; value++) {
2116 if (value->GetUnit() != eCSSUnit_TokenStream) {
2117 continue;
2120 const CSSVariableValues* variables =
2121 &aContext->StyleVariables()->mVariables;
2122 nsCSSValueTokenStream* tokenStream = value->GetTokenStreamValue();
2124 // Note that ParsePropertyWithVariableReferences relies on the fact
2125 // that the nsCSSValue in aRuleData for the property we are re-parsing
2126 // is still the token stream value. When
2127 // ParsePropertyWithVariableReferences calls
2128 // nsCSSExpandedDataBlock::MapRuleInfoInto, that function will add
2129 // the ImageValue that is created into the token stream object's
2130 // mImageValues table; see the comment above mImageValues for why.
2132 // XXX Should pass in sheet here (see bug 952338).
2133 parser.ParsePropertyWithVariableReferences(
2134 tokenStream->mPropertyID, tokenStream->mShorthandPropertyID,
2135 tokenStream->mTokenStream, variables, aRuleData,
2136 tokenStream->mSheetURI, tokenStream->mBaseURI,
2137 tokenStream->mSheetPrincipal, nullptr,
2138 tokenStream->mLineNumber, tokenStream->mLineOffset);
2139 aRuleData->mCanStoreInRuleTree = false;
2140 anyTokenStreams = true;
2143 return anyTokenStreams;
2146 const void*
2147 nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
2148 nsStyleContext* aContext)
2150 // use placement new[] on the result of alloca() to allocate a
2151 // variable-sized stack array, including execution of constructors,
2152 // and use an RAII class to run the destructors too.
2153 size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
2154 void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
2155 AutoCSSValueArray dataArray(dataStorage, nprops);
2157 nsRuleData ruleData(nsCachedStyleData::GetBitForSID(aSID),
2158 dataArray.get(), mPresContext, aContext);
2159 ruleData.mValueOffsets[aSID] = 0;
2161 // We start at the most specific rule in the tree.
2162 void* startStruct = nullptr;
2164 nsRuleNode* ruleNode = this;
2165 nsRuleNode* highestNode = nullptr; // The highest node in the rule tree
2166 // that has the same properties
2167 // specified for struct |aSID| as
2168 // |this| does.
2169 nsRuleNode* rootNode = this; // After the loop below, this will be the
2170 // highest node that we've walked without
2171 // finding cached data on the rule tree.
2172 // If we don't find any cached data, it
2173 // will be the root. (XXX misnamed)
2174 RuleDetail detail = eRuleNone;
2175 uint32_t bit = nsCachedStyleData::GetBitForSID(aSID);
2177 while (ruleNode) {
2178 // See if this rule node has cached the fact that the remaining
2179 // nodes along this path specify no data whatsoever.
2180 if (ruleNode->mNoneBits & bit)
2181 break;
2183 // If the dependent bit is set on a rule node for this struct, that
2184 // means its rule won't have any information to add, so skip it.
2185 // NOTE: If we exit the loop because of the !IsUsedDirectly() check,
2186 // then we're guaranteed to break immediately afterwards due to a
2187 // non-null startStruct.
2188 while ((ruleNode->mDependentBits & bit) && !ruleNode->IsUsedDirectly()) {
2189 NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nullptr,
2190 "dependent bit with cached data makes no sense");
2191 // Climb up to the next rule in the tree (a less specific rule).
2192 rootNode = ruleNode;
2193 ruleNode = ruleNode->mParent;
2194 NS_ASSERTION(!(ruleNode->mNoneBits & bit), "can't have both bits set");
2197 // Check for cached data after the inner loop above -- otherwise
2198 // we'll miss it.
2199 startStruct = ruleNode->mStyleData.GetStyleData(aSID);
2200 if (startStruct)
2201 break; // We found a rule with fully specified data. We don't
2202 // need to go up the tree any further, since the remainder
2203 // of this branch has already been computed.
2205 // Ask the rule to fill in the properties that it specifies.
2206 nsIStyleRule *rule = ruleNode->mRule;
2207 if (rule) {
2208 ruleData.mLevel = ruleNode->GetLevel();
2209 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
2210 rule->MapRuleInfoInto(&ruleData);
2213 // Now we check to see how many properties have been specified by
2214 // the rules we've examined so far.
2215 RuleDetail oldDetail = detail;
2216 detail = CheckSpecifiedProperties(aSID, &ruleData);
2218 if (oldDetail == eRuleNone && detail != eRuleNone)
2219 highestNode = ruleNode;
2221 if (detail == eRuleFullReset ||
2222 detail == eRuleFullMixed ||
2223 detail == eRuleFullInherited)
2224 break; // We don't need to examine any more rules. All properties
2225 // have been fully specified.
2227 // Climb up to the next rule in the tree (a less specific rule).
2228 rootNode = ruleNode;
2229 ruleNode = ruleNode->mParent;
2232 bool recomputeDetail = false;
2234 // If we are computing a style struct other than nsStyleVariables, and
2235 // ruleData has any properties with variable references (nsCSSValues of
2236 // type eCSSUnit_TokenStream), then we need to resolve these.
2237 if (aSID != eStyleStruct_Variables) {
2238 // A property's value might have became 'inherit' after resolving
2239 // variable references. (This happens when an inherited property
2240 // fails to parse its resolved value.) We need to recompute
2241 // |detail| in case this happened.
2242 recomputeDetail = ResolveVariableReferences(aSID, &ruleData, aContext);
2245 // If needed, unset the properties that don't have a flag that allows
2246 // them to be set for this style context. (For example, only some
2247 // properties apply to :first-line and :first-letter.)
2248 uint32_t pseudoRestriction = GetPseudoRestriction(aContext);
2249 if (pseudoRestriction) {
2250 UnsetPropertiesWithoutFlags(aSID, &ruleData, pseudoRestriction);
2252 // We need to recompute |detail| based on the restrictions we just applied.
2253 // We can adjust |detail| arbitrarily because of the restriction
2254 // rule added in nsStyleSet::WalkRestrictionRule.
2255 recomputeDetail = true;
2258 if (recomputeDetail) {
2259 detail = CheckSpecifiedProperties(aSID, &ruleData);
2262 NS_ASSERTION(!startStruct || (detail != eRuleFullReset &&
2263 detail != eRuleFullMixed &&
2264 detail != eRuleFullInherited),
2265 "can't have start struct and be fully specified");
2267 bool isReset = nsCachedStyleData::IsReset(aSID);
2268 if (!highestNode)
2269 highestNode = rootNode;
2271 if (!ruleData.mCanStoreInRuleTree)
2272 detail = eRulePartialMixed; // Treat as though some data is specified to avoid
2273 // the optimizations and force data computation.
2275 if (detail == eRuleNone && startStruct) {
2276 // We specified absolutely no rule information, but a parent rule in the tree
2277 // specified all the rule information. We set a bit along the branch from our
2278 // node in the tree to the node that specified the data that tells nodes on that
2279 // branch that they never need to examine their rules for this particular struct type
2280 // ever again.
2281 PropagateDependentBit(aSID, ruleNode, startStruct);
2282 return startStruct;
2284 if ((!startStruct && !isReset &&
2285 (detail == eRuleNone || detail == eRulePartialInherited)) ||
2286 detail == eRuleFullInherited) {
2287 // We specified no non-inherited information and neither did any of
2288 // our parent rules.
2290 // We set a bit along the branch from the highest node (ruleNode)
2291 // down to our node (this) indicating that no non-inherited data was
2292 // specified. This bit is guaranteed to be set already on the path
2293 // from the highest node to the root node in the case where
2294 // (detail == eRuleNone), which is the most common case here.
2295 // We must check |!isReset| because the Compute*Data functions for
2296 // reset structs wouldn't handle none bits correctly.
2297 if (highestNode != this && !isReset)
2298 PropagateNoneBit(bit, highestNode);
2300 // All information must necessarily be inherited from our parent style context.
2301 // In the absence of any computed data in the rule tree and with
2302 // no rules specified that didn't have values of 'inherit', we should check our parent.
2303 nsStyleContext* parentContext = aContext->GetParent();
2304 if (isReset) {
2305 /* Reset structs don't inherit from first-line. */
2306 /* See similar code in COMPUTE_START_RESET */
2307 while (parentContext &&
2308 parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) {
2309 parentContext = parentContext->GetParent();
2312 if (parentContext) {
2313 // We have a parent, and so we should just inherit from the parent.
2314 // Set the inherit bits on our context. These bits tell the style context that
2315 // it never has to go back to the rule tree for data. Instead the style context tree
2316 // should be walked to find the data.
2317 const void* parentStruct = parentContext->StyleData(aSID);
2318 aContext->AddStyleBit(bit); // makes const_cast OK.
2319 aContext->SetStyle(aSID, const_cast<void*>(parentStruct));
2320 return parentStruct;
2322 else
2323 // We are the root. In the case of fonts, the default values just
2324 // come from the pres context.
2325 return SetDefaultOnRoot(aSID, aContext);
2328 // We need to compute the data from the information that the rules specified.
2329 const void* res;
2330 #define STYLE_STRUCT_TEST aSID
2331 #define STYLE_STRUCT(name, checkdata_cb) \
2332 res = Compute##name##Data(startStruct, &ruleData, aContext, \
2333 highestNode, detail, ruleData.mCanStoreInRuleTree);
2334 #include "nsStyleStructList.h"
2335 #undef STYLE_STRUCT
2336 #undef STYLE_STRUCT_TEST
2338 // Now return the result.
2339 return res;
2342 const void*
2343 nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
2345 switch (aSID) {
2346 case eStyleStruct_Font:
2348 nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
2349 nscoord minimumFontSize = mPresContext->MinFontSize(fontData->mLanguage);
2351 if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
2352 fontData->mFont.size = std::max(fontData->mSize, minimumFontSize);
2354 else {
2355 fontData->mFont.size = fontData->mSize;
2357 aContext->SetStyle(eStyleStruct_Font, fontData);
2358 return fontData;
2360 case eStyleStruct_Display:
2362 nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay();
2363 aContext->SetStyle(eStyleStruct_Display, disp);
2364 return disp;
2366 case eStyleStruct_Visibility:
2368 nsStyleVisibility* vis = new (mPresContext) nsStyleVisibility(mPresContext);
2369 aContext->SetStyle(eStyleStruct_Visibility, vis);
2370 return vis;
2372 case eStyleStruct_Text:
2374 nsStyleText* text = new (mPresContext) nsStyleText();
2375 aContext->SetStyle(eStyleStruct_Text, text);
2376 return text;
2378 case eStyleStruct_TextReset:
2380 nsStyleTextReset* text = new (mPresContext) nsStyleTextReset();
2381 aContext->SetStyle(eStyleStruct_TextReset, text);
2382 return text;
2384 case eStyleStruct_Color:
2386 nsStyleColor* color = new (mPresContext) nsStyleColor(mPresContext);
2387 aContext->SetStyle(eStyleStruct_Color, color);
2388 return color;
2390 case eStyleStruct_Background:
2392 nsStyleBackground* bg = new (mPresContext) nsStyleBackground();
2393 aContext->SetStyle(eStyleStruct_Background, bg);
2394 return bg;
2396 case eStyleStruct_Margin:
2398 nsStyleMargin* margin = new (mPresContext) nsStyleMargin();
2399 aContext->SetStyle(eStyleStruct_Margin, margin);
2400 return margin;
2402 case eStyleStruct_Border:
2404 nsStyleBorder* border = new (mPresContext) nsStyleBorder(mPresContext);
2405 aContext->SetStyle(eStyleStruct_Border, border);
2406 return border;
2408 case eStyleStruct_Padding:
2410 nsStylePadding* padding = new (mPresContext) nsStylePadding();
2411 aContext->SetStyle(eStyleStruct_Padding, padding);
2412 return padding;
2414 case eStyleStruct_Outline:
2416 nsStyleOutline* outline = new (mPresContext) nsStyleOutline(mPresContext);
2417 aContext->SetStyle(eStyleStruct_Outline, outline);
2418 return outline;
2420 case eStyleStruct_List:
2422 nsStyleList* list = new (mPresContext) nsStyleList(mPresContext);
2423 aContext->SetStyle(eStyleStruct_List, list);
2424 return list;
2426 case eStyleStruct_Position:
2428 nsStylePosition* pos = new (mPresContext) nsStylePosition();
2429 aContext->SetStyle(eStyleStruct_Position, pos);
2430 return pos;
2432 case eStyleStruct_Table:
2434 nsStyleTable* table = new (mPresContext) nsStyleTable();
2435 aContext->SetStyle(eStyleStruct_Table, table);
2436 return table;
2438 case eStyleStruct_TableBorder:
2440 nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder(mPresContext);
2441 aContext->SetStyle(eStyleStruct_TableBorder, table);
2442 return table;
2444 case eStyleStruct_Content:
2446 nsStyleContent* content = new (mPresContext) nsStyleContent();
2447 aContext->SetStyle(eStyleStruct_Content, content);
2448 return content;
2450 case eStyleStruct_Quotes:
2452 nsStyleQuotes* quotes = new (mPresContext) nsStyleQuotes();
2453 aContext->SetStyle(eStyleStruct_Quotes, quotes);
2454 return quotes;
2456 case eStyleStruct_UserInterface:
2458 nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface();
2459 aContext->SetStyle(eStyleStruct_UserInterface, ui);
2460 return ui;
2462 case eStyleStruct_UIReset:
2464 nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset();
2465 aContext->SetStyle(eStyleStruct_UIReset, ui);
2466 return ui;
2468 case eStyleStruct_XUL:
2470 nsStyleXUL* xul = new (mPresContext) nsStyleXUL();
2471 aContext->SetStyle(eStyleStruct_XUL, xul);
2472 return xul;
2474 case eStyleStruct_Column:
2476 nsStyleColumn* column = new (mPresContext) nsStyleColumn(mPresContext);
2477 aContext->SetStyle(eStyleStruct_Column, column);
2478 return column;
2480 case eStyleStruct_SVG:
2482 nsStyleSVG* svg = new (mPresContext) nsStyleSVG();
2483 aContext->SetStyle(eStyleStruct_SVG, svg);
2484 return svg;
2486 case eStyleStruct_SVGReset:
2488 nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset();
2489 aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
2490 return svgReset;
2492 case eStyleStruct_Variables:
2494 nsStyleVariables* vars = new (mPresContext) nsStyleVariables();
2495 aContext->SetStyle(eStyleStruct_Variables, vars);
2496 return vars;
2498 default:
2500 * unhandled case: nsStyleStructID_Length.
2501 * last item of nsStyleStructID, to know its length.
2503 NS_ABORT_IF_FALSE(false, "unexpected SID");
2504 return nullptr;
2506 return nullptr;
2510 * This function handles cascading of *-left or *-right box properties
2511 * against *-start (which is L for LTR and R for RTL) or *-end (which is
2512 * R for LTR and L for RTL).
2514 * Cascading these properties correctly is hard because we need to
2515 * cascade two properties as one, but which two properties depends on a
2516 * third property ('direction'). We solve this by treating each of
2517 * these properties (say, 'margin-start') as a shorthand that sets a
2518 * property containing the value of the property specified
2519 * ('margin-start-value') and sets a pair of properties
2520 * ('margin-left-ltr-source' and 'margin-right-rtl-source') saying which
2521 * of the properties we use. Thus, when we want to compute the value of
2522 * 'margin-left' when 'direction' is 'ltr', we look at the value of
2523 * 'margin-left-ltr-source', which tells us whether to use the highest
2524 * 'margin-left' in the cascade or the highest 'margin-start'.
2526 * Finally, since we can compute the normal (*-left and *-right)
2527 * properties in a loop, this function works by modifying the data we
2528 * will use in that loop (which the caller must copy from the const
2529 * input).
2531 void
2532 nsRuleNode::AdjustLogicalBoxProp(nsStyleContext* aContext,
2533 const nsCSSValue& aLTRSource,
2534 const nsCSSValue& aRTLSource,
2535 const nsCSSValue& aLTRLogicalValue,
2536 const nsCSSValue& aRTLLogicalValue,
2537 mozilla::css::Side aSide,
2538 nsCSSRect& aValueRect,
2539 bool& aCanStoreInRuleTree)
2541 bool LTRlogical = aLTRSource.GetUnit() == eCSSUnit_Enumerated &&
2542 aLTRSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
2543 bool RTLlogical = aRTLSource.GetUnit() == eCSSUnit_Enumerated &&
2544 aRTLSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
2545 if (LTRlogical || RTLlogical) {
2546 // We can't cache anything on the rule tree if we use any data from
2547 // the style context, since data cached in the rule tree could be
2548 // used with a style context with a different value.
2549 aCanStoreInRuleTree = false;
2550 uint8_t dir = aContext->StyleVisibility()->mDirection;
2552 if (dir == NS_STYLE_DIRECTION_LTR) {
2553 if (LTRlogical)
2554 aValueRect.*(nsCSSRect::sides[aSide]) = aLTRLogicalValue;
2555 } else {
2556 if (RTLlogical)
2557 aValueRect.*(nsCSSRect::sides[aSide]) = aRTLLogicalValue;
2559 } else if (aLTRLogicalValue.GetUnit() == eCSSUnit_Inherit ||
2560 aRTLLogicalValue.GetUnit() == eCSSUnit_Inherit) {
2561 // It actually is valid to store this in the ruletree, since
2562 // LTRlogical and RTLlogical are both false, but doing that will
2563 // trigger asserts. Silence those.
2564 aCanStoreInRuleTree = false;
2569 * Begin an nsRuleNode::Compute*Data function for an inherited struct.
2571 * @param type_ The nsStyle* type this function computes.
2572 * @param ctorargs_ The arguments used for the default nsStyle* constructor.
2573 * @param data_ Variable (declared here) holding the result of this
2574 * function.
2575 * @param parentdata_ Variable (declared here) holding the parent style
2576 * context's data for this struct.
2578 #define COMPUTE_START_INHERITED(type_, ctorargs_, data_, parentdata_) \
2579 NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
2580 "should not have bothered calling Compute*Data"); \
2582 nsStyleContext* parentContext = aContext->GetParent(); \
2584 nsStyle##type_* data_ = nullptr; \
2585 mozilla::Maybe<nsStyle##type_> maybeFakeParentData; \
2586 const nsStyle##type_* parentdata_ = nullptr; \
2587 bool canStoreInRuleTree = aCanStoreInRuleTree; \
2589 /* If |canStoreInRuleTree| might be true by the time we're done, we */ \
2590 /* can't call parentContext->Style##type_() since it could recur into */ \
2591 /* setting the same struct on the same rule node, causing a leak. */ \
2592 if (aRuleDetail != eRuleFullReset && \
2593 (!aStartStruct || (aRuleDetail != eRulePartialReset && \
2594 aRuleDetail != eRuleNone))) { \
2595 if (parentContext) { \
2596 parentdata_ = parentContext->Style##type_(); \
2597 } else { \
2598 maybeFakeParentData.emplace ctorargs_; \
2599 parentdata_ = maybeFakeParentData.ptr(); \
2602 if (aStartStruct) \
2603 /* We only need to compute the delta between this computed data and */ \
2604 /* our computed data. */ \
2605 data_ = new (mPresContext) \
2606 nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
2607 else { \
2608 if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) { \
2609 /* No question. We will have to inherit. Go ahead and init */ \
2610 /* with inherited vals from parent. */ \
2611 canStoreInRuleTree = false; \
2612 if (parentdata_) \
2613 data_ = new (mPresContext) nsStyle##type_(*parentdata_); \
2614 else \
2615 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2617 else \
2618 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2621 if (!parentdata_) \
2622 parentdata_ = data_;
2625 * Begin an nsRuleNode::Compute*Data function for a reset struct.
2627 * @param type_ The nsStyle* type this function computes.
2628 * @param ctorargs_ The arguments used for the default nsStyle* constructor.
2629 * @param data_ Variable (declared here) holding the result of this
2630 * function.
2631 * @param parentdata_ Variable (declared here) holding the parent style
2632 * context's data for this struct.
2634 #define COMPUTE_START_RESET(type_, ctorargs_, data_, parentdata_) \
2635 NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
2636 "should not have bothered calling Compute*Data"); \
2638 nsStyleContext* parentContext = aContext->GetParent(); \
2639 /* Reset structs don't inherit from first-line */ \
2640 /* See similar code in WalkRuleTree */ \
2641 while (parentContext && \
2642 parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) { \
2643 parentContext = parentContext->GetParent(); \
2646 nsStyle##type_* data_; \
2647 if (aStartStruct) \
2648 /* We only need to compute the delta between this computed data and */ \
2649 /* our computed data. */ \
2650 data_ = new (mPresContext) \
2651 nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
2652 else \
2653 data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2655 /* If |canStoreInRuleTree| might be true by the time we're done, we */ \
2656 /* can't call parentContext->Style##type_() since it could recur into */ \
2657 /* setting the same struct on the same rule node, causing a leak. */ \
2658 mozilla::Maybe<nsStyle##type_> maybeFakeParentData; \
2659 const nsStyle##type_* parentdata_ = data_; \
2660 if (aRuleDetail != eRuleFullReset && \
2661 aRuleDetail != eRulePartialReset && \
2662 aRuleDetail != eRuleNone) { \
2663 if (parentContext) { \
2664 parentdata_ = parentContext->Style##type_(); \
2665 } else { \
2666 maybeFakeParentData.emplace ctorargs_; \
2667 parentdata_ = maybeFakeParentData.ptr(); \
2670 bool canStoreInRuleTree = aCanStoreInRuleTree;
2673 * End an nsRuleNode::Compute*Data function for an inherited struct.
2675 * @param type_ The nsStyle* type this function computes.
2676 * @param data_ Variable holding the result of this function.
2678 #define COMPUTE_END_INHERITED(type_, data_) \
2679 NS_POSTCONDITION(!canStoreInRuleTree || aRuleDetail == eRuleFullReset || \
2680 (aStartStruct && aRuleDetail == eRulePartialReset), \
2681 "canStoreInRuleTree must be false for inherited structs " \
2682 "unless all properties have been specified with values " \
2683 "other than inherit"); \
2684 if (canStoreInRuleTree) { \
2685 /* We were fully specified and can therefore be cached right on the */ \
2686 /* rule node. */ \
2687 if (!aHighestNode->mStyleData.mInheritedData) { \
2688 aHighestNode->mStyleData.mInheritedData = \
2689 new (mPresContext) nsInheritedStyleData; \
2691 NS_ASSERTION(!aHighestNode->mStyleData.mInheritedData-> \
2692 mStyleStructs[eStyleStruct_##type_], \
2693 "Going to leak style data"); \
2694 aHighestNode->mStyleData.mInheritedData-> \
2695 mStyleStructs[eStyleStruct_##type_] = data_; \
2696 /* Propagate the bit down. */ \
2697 PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_); \
2698 /* Tell the style context that it doesn't own the data */ \
2699 aContext-> \
2700 AddStyleBit(nsCachedStyleData::GetBitForSID(eStyleStruct_##type_)); \
2702 /* Always cache inherited data on the style context */ \
2703 aContext->SetStyle##type_(data_); \
2705 return data_;
2708 * End an nsRuleNode::Compute*Data function for a reset struct.
2710 * @param type_ The nsStyle* type this function computes.
2711 * @param data_ Variable holding the result of this function.
2713 #define COMPUTE_END_RESET(type_, data_) \
2714 NS_POSTCONDITION(!canStoreInRuleTree || \
2715 aRuleDetail == eRuleNone || \
2716 aRuleDetail == eRulePartialReset || \
2717 aRuleDetail == eRuleFullReset, \
2718 "canStoreInRuleTree must be false for reset structs " \
2719 "if any properties were specified as inherit"); \
2720 if (!canStoreInRuleTree) \
2721 /* We can't be cached in the rule node. We have to be put right */ \
2722 /* on the style context. */ \
2723 aContext->SetStyle(eStyleStruct_##type_, data_); \
2724 else { \
2725 /* We were fully specified and can therefore be cached right on the */ \
2726 /* rule node. */ \
2727 if (!aHighestNode->mStyleData.mResetData) { \
2728 aHighestNode->mStyleData.mResetData = \
2729 new (mPresContext) nsResetStyleData; \
2731 NS_ASSERTION(!aHighestNode->mStyleData.mResetData-> \
2732 mStyleStructs[eStyleStruct_##type_], \
2733 "Going to leak style data"); \
2734 aHighestNode->mStyleData.mResetData-> \
2735 mStyleStructs[eStyleStruct_##type_] = data_; \
2736 /* Propagate the bit down. */ \
2737 PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_); \
2740 return data_;
2742 // This function figures out how much scaling should be suppressed to
2743 // satisfy scriptminsize. This is our attempt to implement
2744 // http://www.w3.org/TR/MathML2/chapter3.html#id.3.3.4.2.2
2745 // This is called after mScriptLevel, mScriptMinSize and mScriptSizeMultiplier
2746 // have been set in aFont.
2748 // Here are the invariants we enforce:
2749 // 1) A decrease in size must not reduce the size below minscriptsize.
2750 // 2) An increase in size must not increase the size above the size we would
2751 // have if minscriptsize had not been applied anywhere.
2752 // 3) The scriptlevel-induced size change must between 1.0 and the parent's
2753 // scriptsizemultiplier^(new script level - old script level), as close to the
2754 // latter as possible subject to constraints 1 and 2.
2755 static nscoord
2756 ComputeScriptLevelSize(const nsStyleFont* aFont, const nsStyleFont* aParentFont,
2757 nsPresContext* aPresContext, nscoord* aUnconstrainedSize)
2759 int32_t scriptLevelChange =
2760 aFont->mScriptLevel - aParentFont->mScriptLevel;
2761 if (scriptLevelChange == 0) {
2762 *aUnconstrainedSize = aParentFont->mScriptUnconstrainedSize;
2763 // Constraint #3 says that we cannot change size, and #1 and #2 are always
2764 // satisfied with no change. It's important this be fast because it covers
2765 // all non-MathML content.
2766 return aParentFont->mSize;
2769 // Compute actual value of minScriptSize
2770 nscoord minScriptSize = aParentFont->mScriptMinSize;
2771 if (aFont->mAllowZoom) {
2772 minScriptSize = nsStyleFont::ZoomText(aPresContext, minScriptSize);
2775 double scriptLevelScale =
2776 pow(aParentFont->mScriptSizeMultiplier, scriptLevelChange);
2777 // Compute the size we would have had if minscriptsize had never been
2778 // applied, also prevent overflow (bug 413274)
2779 *aUnconstrainedSize =
2780 NSToCoordRoundWithClamp(aParentFont->mScriptUnconstrainedSize*scriptLevelScale);
2781 // Compute the size we could get via scriptlevel change
2782 nscoord scriptLevelSize =
2783 NSToCoordRoundWithClamp(aParentFont->mSize*scriptLevelScale);
2784 if (scriptLevelScale <= 1.0) {
2785 if (aParentFont->mSize <= minScriptSize) {
2786 // We can't decrease the font size at all, so just stick to no change
2787 // (authors are allowed to explicitly set the font size smaller than
2788 // minscriptsize)
2789 return aParentFont->mSize;
2791 // We can decrease, so apply constraint #1
2792 return std::max(minScriptSize, scriptLevelSize);
2793 } else {
2794 // scriptminsize can only make sizes larger than the unconstrained size
2795 NS_ASSERTION(*aUnconstrainedSize <= scriptLevelSize, "How can this ever happen?");
2796 // Apply constraint #2
2797 return std::min(scriptLevelSize, std::max(*aUnconstrainedSize, minScriptSize));
2802 /* static */ nscoord
2803 nsRuleNode::CalcFontPointSize(int32_t aHTMLSize, int32_t aBasePointSize,
2804 nsPresContext* aPresContext,
2805 nsFontSizeType aFontSizeType)
2807 #define sFontSizeTableMin 9
2808 #define sFontSizeTableMax 16
2810 // This table seems to be the one used by MacIE5. We hope its adoption in Mozilla
2811 // and eventually in WinIE5.5 will help to establish a standard rendering across
2812 // platforms and browsers. For now, it is used only in Strict mode. More can be read
2813 // in the document written by Todd Farhner at:
2814 // http://style.verso.com/font_size_intervals/altintervals.html
2816 static int32_t sStrictFontSizeTable[sFontSizeTableMax - sFontSizeTableMin + 1][8] =
2818 { 9, 9, 9, 9, 11, 14, 18, 27},
2819 { 9, 9, 9, 10, 12, 15, 20, 30},
2820 { 9, 9, 10, 11, 13, 17, 22, 33},
2821 { 9, 9, 10, 12, 14, 18, 24, 36},
2822 { 9, 10, 12, 13, 16, 20, 26, 39},
2823 { 9, 10, 12, 14, 17, 21, 28, 42},
2824 { 9, 10, 13, 15, 18, 23, 30, 45},
2825 { 9, 10, 13, 16, 18, 24, 32, 48}
2827 // HTML 1 2 3 4 5 6 7
2828 // CSS xxs xs s m l xl xxl
2829 // |
2830 // user pref
2832 //------------------------------------------------------------
2834 // This table gives us compatibility with WinNav4 for the default fonts only.
2835 // In WinNav4, the default fonts were:
2837 // Times/12pt == Times/16px at 96ppi
2838 // Courier/10pt == Courier/13px at 96ppi
2840 // The 2 lines below marked "anchored" have the exact pixel sizes used by
2841 // WinNav4 for Times/12pt and Courier/10pt at 96ppi. As you can see, the
2842 // HTML size 3 (user pref) for those 2 anchored lines is 13px and 16px.
2844 // All values other than the anchored values were filled in by hand, never
2845 // going below 9px, and maintaining a "diagonal" relationship. See for
2846 // example the 13s -- they follow a diagonal line through the table.
2848 static int32_t sQuirksFontSizeTable[sFontSizeTableMax - sFontSizeTableMin + 1][8] =
2850 { 9, 9, 9, 9, 11, 14, 18, 28 },
2851 { 9, 9, 9, 10, 12, 15, 20, 31 },
2852 { 9, 9, 9, 11, 13, 17, 22, 34 },
2853 { 9, 9, 10, 12, 14, 18, 24, 37 },
2854 { 9, 9, 10, 13, 16, 20, 26, 40 }, // anchored (13)
2855 { 9, 9, 11, 14, 17, 21, 28, 42 },
2856 { 9, 10, 12, 15, 17, 23, 30, 45 },
2857 { 9, 10, 13, 16, 18, 24, 32, 48 } // anchored (16)
2859 // HTML 1 2 3 4 5 6 7
2860 // CSS xxs xs s m l xl xxl
2861 // |
2862 // user pref
2864 #if 0
2866 // These are the exact pixel values used by WinIE5 at 96ppi.
2868 { ?, 8, 11, 12, 13, 16, 21, 32 }, // smallest
2869 { ?, 9, 12, 13, 16, 21, 27, 40 }, // smaller
2870 { ?, 10, 13, 16, 18, 24, 32, 48 }, // medium
2871 { ?, 13, 16, 19, 21, 27, 37, ?? }, // larger
2872 { ?, 16, 19, 21, 24, 32, 43, ?? } // largest
2874 // HTML 1 2 3 4 5 6 7
2875 // CSS ? ? ? ? ? ? ? ?
2877 // (CSS not tested yet.)
2879 #endif
2881 static int32_t sFontSizeFactors[8] = { 60,75,89,100,120,150,200,300 };
2883 static int32_t sCSSColumns[7] = {0, 1, 2, 3, 4, 5, 6}; // xxs...xxl
2884 static int32_t sHTMLColumns[7] = {1, 2, 3, 4, 5, 6, 7}; // 1...7
2886 double dFontSize;
2888 if (aFontSizeType == eFontSize_HTML) {
2889 aHTMLSize--; // input as 1-7
2892 if (aHTMLSize < 0)
2893 aHTMLSize = 0;
2894 else if (aHTMLSize > 6)
2895 aHTMLSize = 6;
2897 int32_t* column;
2898 switch (aFontSizeType)
2900 case eFontSize_HTML: column = sHTMLColumns; break;
2901 case eFontSize_CSS: column = sCSSColumns; break;
2904 // Make special call specifically for fonts (needed PrintPreview)
2905 int32_t fontSize = nsPresContext::AppUnitsToIntCSSPixels(aBasePointSize);
2907 if ((fontSize >= sFontSizeTableMin) && (fontSize <= sFontSizeTableMax))
2909 int32_t row = fontSize - sFontSizeTableMin;
2911 if (aPresContext->CompatibilityMode() == eCompatibility_NavQuirks) {
2912 dFontSize = nsPresContext::CSSPixelsToAppUnits(sQuirksFontSizeTable[row][column[aHTMLSize]]);
2913 } else {
2914 dFontSize = nsPresContext::CSSPixelsToAppUnits(sStrictFontSizeTable[row][column[aHTMLSize]]);
2917 else
2919 int32_t factor = sFontSizeFactors[column[aHTMLSize]];
2920 dFontSize = (factor * aBasePointSize) / 100;
2924 if (1.0 < dFontSize) {
2925 return (nscoord)dFontSize;
2927 return (nscoord)1;
2931 //------------------------------------------------------------------------------
2933 //------------------------------------------------------------------------------
2935 /* static */ nscoord
2936 nsRuleNode::FindNextSmallerFontSize(nscoord aFontSize, int32_t aBasePointSize,
2937 nsPresContext* aPresContext,
2938 nsFontSizeType aFontSizeType)
2940 int32_t index;
2941 int32_t indexMin;
2942 int32_t indexMax;
2943 float relativePosition;
2944 nscoord smallerSize;
2945 nscoord indexFontSize = aFontSize; // XXX initialize to quell a spurious gcc3.2 warning
2946 nscoord smallestIndexFontSize;
2947 nscoord largestIndexFontSize;
2948 nscoord smallerIndexFontSize;
2949 nscoord largerIndexFontSize;
2951 nscoord onePx = nsPresContext::CSSPixelsToAppUnits(1);
2953 if (aFontSizeType == eFontSize_HTML) {
2954 indexMin = 1;
2955 indexMax = 7;
2956 } else {
2957 indexMin = 0;
2958 indexMax = 6;
2961 smallestIndexFontSize = CalcFontPointSize(indexMin, aBasePointSize, aPresContext, aFontSizeType);
2962 largestIndexFontSize = CalcFontPointSize(indexMax, aBasePointSize, aPresContext, aFontSizeType);
2963 if (aFontSize > smallestIndexFontSize) {
2964 if (aFontSize < NSToCoordRound(float(largestIndexFontSize) * 1.5)) { // smaller will be in HTML table
2965 // find largest index smaller than current
2966 for (index = indexMax; index >= indexMin; index--) {
2967 indexFontSize = CalcFontPointSize(index, aBasePointSize, aPresContext, aFontSizeType);
2968 if (indexFontSize < aFontSize)
2969 break;
2971 // set up points beyond table for interpolation purposes
2972 if (indexFontSize == smallestIndexFontSize) {
2973 smallerIndexFontSize = indexFontSize - onePx;
2974 largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
2975 } else if (indexFontSize == largestIndexFontSize) {
2976 smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
2977 largerIndexFontSize = NSToCoordRound(float(largestIndexFontSize) * 1.5);
2978 } else {
2979 smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
2980 largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
2982 // compute the relative position of the parent size between the two closest indexed sizes
2983 relativePosition = float(aFontSize - indexFontSize) / float(largerIndexFontSize - indexFontSize);
2984 // set the new size to have the same relative position between the next smallest two indexed sizes
2985 smallerSize = smallerIndexFontSize + NSToCoordRound(relativePosition * (indexFontSize - smallerIndexFontSize));
2987 else { // larger than HTML table, drop by 33%
2988 smallerSize = NSToCoordRound(float(aFontSize) / 1.5);
2991 else { // smaller than HTML table, drop by 1px
2992 smallerSize = std::max(aFontSize - onePx, onePx);
2994 return smallerSize;
2997 //------------------------------------------------------------------------------
2999 //------------------------------------------------------------------------------
3001 /* static */ nscoord
3002 nsRuleNode::FindNextLargerFontSize(nscoord aFontSize, int32_t aBasePointSize,
3003 nsPresContext* aPresContext,
3004 nsFontSizeType aFontSizeType)
3006 int32_t index;
3007 int32_t indexMin;
3008 int32_t indexMax;
3009 float relativePosition;
3010 nscoord adjustment;
3011 nscoord largerSize;
3012 nscoord indexFontSize = aFontSize; // XXX initialize to quell a spurious gcc3.2 warning
3013 nscoord smallestIndexFontSize;
3014 nscoord largestIndexFontSize;
3015 nscoord smallerIndexFontSize;
3016 nscoord largerIndexFontSize;
3018 nscoord onePx = nsPresContext::CSSPixelsToAppUnits(1);
3020 if (aFontSizeType == eFontSize_HTML) {
3021 indexMin = 1;
3022 indexMax = 7;
3023 } else {
3024 indexMin = 0;
3025 indexMax = 6;
3028 smallestIndexFontSize = CalcFontPointSize(indexMin, aBasePointSize, aPresContext, aFontSizeType);
3029 largestIndexFontSize = CalcFontPointSize(indexMax, aBasePointSize, aPresContext, aFontSizeType);
3030 if (aFontSize > (smallestIndexFontSize - onePx)) {
3031 if (aFontSize < largestIndexFontSize) { // larger will be in HTML table
3032 // find smallest index larger than current
3033 for (index = indexMin; index <= indexMax; index++) {
3034 indexFontSize = CalcFontPointSize(index, aBasePointSize, aPresContext, aFontSizeType);
3035 if (indexFontSize > aFontSize)
3036 break;
3038 // set up points beyond table for interpolation purposes
3039 if (indexFontSize == smallestIndexFontSize) {
3040 smallerIndexFontSize = indexFontSize - onePx;
3041 largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
3042 } else if (indexFontSize == largestIndexFontSize) {
3043 smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
3044 largerIndexFontSize = NSCoordSaturatingMultiply(largestIndexFontSize, 1.5);
3045 } else {
3046 smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType);
3047 largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType);
3049 // compute the relative position of the parent size between the two closest indexed sizes
3050 relativePosition = float(aFontSize - smallerIndexFontSize) / float(indexFontSize - smallerIndexFontSize);
3051 // set the new size to have the same relative position between the next largest two indexed sizes
3052 adjustment = NSCoordSaturatingNonnegativeMultiply(largerIndexFontSize - indexFontSize, relativePosition);
3053 largerSize = NSCoordSaturatingAdd(indexFontSize, adjustment);
3055 else { // larger than HTML table, increase by 50%
3056 largerSize = NSCoordSaturatingMultiply(aFontSize, 1.5);
3059 else { // smaller than HTML table, increase by 1px
3060 largerSize = NSCoordSaturatingAdd(aFontSize, onePx);
3062 return largerSize;
3065 struct SetFontSizeCalcOps : public css::BasicCoordCalcOps,
3066 public css::NumbersAlreadyNormalizedOps
3068 // The parameters beyond aValue that we need for CalcLengthWith.
3069 const nscoord mParentSize;
3070 const nsStyleFont* const mParentFont;
3071 nsPresContext* const mPresContext;
3072 const bool mAtRoot;
3073 bool& mCanStoreInRuleTree;
3075 SetFontSizeCalcOps(nscoord aParentSize, const nsStyleFont* aParentFont,
3076 nsPresContext* aPresContext, bool aAtRoot,
3077 bool& aCanStoreInRuleTree)
3078 : mParentSize(aParentSize),
3079 mParentFont(aParentFont),
3080 mPresContext(aPresContext),
3081 mAtRoot(aAtRoot),
3082 mCanStoreInRuleTree(aCanStoreInRuleTree)
3086 result_type ComputeLeafValue(const nsCSSValue& aValue)
3088 nscoord size;
3089 if (aValue.IsLengthUnit()) {
3090 // Note that font-based length units use the parent's size
3091 // unadjusted for scriptlevel changes. A scriptlevel change
3092 // between us and the parent is simply ignored.
3093 size = CalcLengthWith(aValue, mParentSize,
3094 mParentFont,
3095 nullptr, mPresContext, mAtRoot,
3096 true, mCanStoreInRuleTree);
3097 if (!aValue.IsRelativeLengthUnit() && mParentFont->mAllowZoom) {
3098 size = nsStyleFont::ZoomText(mPresContext, size);
3101 else if (eCSSUnit_Percent == aValue.GetUnit()) {
3102 mCanStoreInRuleTree = false;
3103 // Note that % units use the parent's size unadjusted for scriptlevel
3104 // changes. A scriptlevel change between us and the parent is simply
3105 // ignored.
3106 // aValue.GetPercentValue() may be negative for, e.g., calc(-50%)
3107 size = NSCoordSaturatingMultiply(mParentSize, aValue.GetPercentValue());
3108 } else {
3109 NS_ABORT_IF_FALSE(false, "unexpected value");
3110 size = mParentSize;
3113 return size;
3117 /* static */ void
3118 nsRuleNode::SetFontSize(nsPresContext* aPresContext,
3119 const nsRuleData* aRuleData,
3120 const nsStyleFont* aFont,
3121 const nsStyleFont* aParentFont,
3122 nscoord* aSize,
3123 const nsFont& aSystemFont,
3124 nscoord aParentSize,
3125 nscoord aScriptLevelAdjustedParentSize,
3126 bool aUsedStartStruct,
3127 bool aAtRoot,
3128 bool& aCanStoreInRuleTree)
3130 // If false, means that *aSize has not been zoomed. If true, means that
3131 // *aSize has been zoomed iff aParentFont->mAllowZoom is true.
3132 bool sizeIsZoomedAccordingToParent = false;
3134 int32_t baseSize = (int32_t) aPresContext->
3135 GetDefaultFont(aFont->mGenericID, aFont->mLanguage)->size;
3136 const nsCSSValue* sizeValue = aRuleData->ValueForFontSize();
3137 if (eCSSUnit_Enumerated == sizeValue->GetUnit()) {
3138 int32_t value = sizeValue->GetIntValue();
3140 if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) &&
3141 (value <= NS_STYLE_FONT_SIZE_XXLARGE)) {
3142 *aSize = CalcFontPointSize(value, baseSize,
3143 aPresContext, eFontSize_CSS);
3145 else if (NS_STYLE_FONT_SIZE_XXXLARGE == value) {
3146 // <font size="7"> is not specified in CSS, so we don't use eFontSize_CSS.
3147 *aSize = CalcFontPointSize(value, baseSize, aPresContext);
3149 else if (NS_STYLE_FONT_SIZE_LARGER == value ||
3150 NS_STYLE_FONT_SIZE_SMALLER == value) {
3151 aCanStoreInRuleTree = false;
3153 // Un-zoom so we use the tables correctly. We'll then rezoom due
3154 // to the |zoom = true| above.
3155 // Note that relative units here use the parent's size unadjusted
3156 // for scriptlevel changes. A scriptlevel change between us and the parent
3157 // is simply ignored.
3158 nscoord parentSize = aParentSize;
3159 if (aParentFont->mAllowZoom) {
3160 parentSize = nsStyleFont::UnZoomText(aPresContext, parentSize);
3163 if (NS_STYLE_FONT_SIZE_LARGER == value) {
3164 *aSize = FindNextLargerFontSize(parentSize,
3165 baseSize, aPresContext, eFontSize_CSS);
3167 NS_ASSERTION(*aSize >= parentSize,
3168 "FindNextLargerFontSize failed");
3170 else {
3171 *aSize = FindNextSmallerFontSize(parentSize,
3172 baseSize, aPresContext, eFontSize_CSS);
3173 NS_ASSERTION(*aSize < parentSize ||
3174 parentSize <= nsPresContext::CSSPixelsToAppUnits(1),
3175 "FindNextSmallerFontSize failed");
3177 } else {
3178 NS_NOTREACHED("unexpected value");
3181 else if (sizeValue->IsLengthUnit() ||
3182 sizeValue->GetUnit() == eCSSUnit_Percent ||
3183 sizeValue->IsCalcUnit()) {
3184 SetFontSizeCalcOps ops(aParentSize, aParentFont,
3185 aPresContext, aAtRoot,
3186 aCanStoreInRuleTree);
3187 *aSize = css::ComputeCalc(*sizeValue, ops);
3188 if (*aSize < 0) {
3189 NS_ABORT_IF_FALSE(sizeValue->IsCalcUnit(),
3190 "negative lengths and percents should be rejected "
3191 "by parser");
3192 *aSize = 0;
3194 // The calc ops will always zoom its result according to the value
3195 // of aParentFont->mAllowZoom.
3196 sizeIsZoomedAccordingToParent = true;
3198 else if (eCSSUnit_System_Font == sizeValue->GetUnit()) {
3199 // this becomes our cascading size
3200 *aSize = aSystemFont.size;
3202 else if (eCSSUnit_Inherit == sizeValue->GetUnit() ||
3203 eCSSUnit_Unset == sizeValue->GetUnit()) {
3204 aCanStoreInRuleTree = false;
3205 // We apply scriptlevel change for this case, because the default is
3206 // to inherit and we don't want explicit "inherit" to differ from the
3207 // default.
3208 *aSize = aScriptLevelAdjustedParentSize;
3209 sizeIsZoomedAccordingToParent = true;
3211 else if (eCSSUnit_Initial == sizeValue->GetUnit()) {
3212 // The initial value is 'medium', which has magical sizing based on
3213 // the generic font family, so do that here too.
3214 *aSize = baseSize;
3215 } else {
3216 NS_ASSERTION(eCSSUnit_Null == sizeValue->GetUnit(),
3217 "What kind of font-size value is this?");
3218 // if aUsedStartStruct is true, then every single property in the
3219 // font struct is being set all at once. This means scriptlevel is not
3220 // going to have any influence on the font size; there is no need to
3221 // do anything here.
3222 if (!aUsedStartStruct && aParentSize != aScriptLevelAdjustedParentSize) {
3223 // There was no rule affecting the size but the size has been
3224 // affected by the parent's size via scriptlevel change. So we cannot
3225 // store the data in the rule tree.
3226 aCanStoreInRuleTree = false;
3227 *aSize = aScriptLevelAdjustedParentSize;
3228 sizeIsZoomedAccordingToParent = true;
3229 } else {
3230 return;
3234 // We want to zoom the cascaded size so that em-based measurements,
3235 // line-heights, etc., work.
3236 bool currentlyZoomed = sizeIsZoomedAccordingToParent &&
3237 aParentFont->mAllowZoom;
3238 if (!currentlyZoomed && aFont->mAllowZoom) {
3239 *aSize = nsStyleFont::ZoomText(aPresContext, *aSize);
3240 } else if (currentlyZoomed && !aFont->mAllowZoom) {
3241 *aSize = nsStyleFont::UnZoomText(aPresContext, *aSize);
3245 static int8_t ClampTo8Bit(int32_t aValue) {
3246 if (aValue < -128)
3247 return -128;
3248 if (aValue > 127)
3249 return 127;
3250 return int8_t(aValue);
3253 /* static */ void
3254 nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
3255 uint8_t aGenericFontID, const nsRuleData* aRuleData,
3256 const nsStyleFont* aParentFont,
3257 nsStyleFont* aFont, bool aUsedStartStruct,
3258 bool& aCanStoreInRuleTree)
3260 bool atRoot = !aContext->GetParent();
3262 // -x-text-zoom: none, inherit, initial
3263 bool allowZoom;
3264 const nsCSSValue* textZoomValue = aRuleData->ValueForTextZoom();
3265 if (eCSSUnit_Null != textZoomValue->GetUnit()) {
3266 if (eCSSUnit_Inherit == textZoomValue->GetUnit()) {
3267 allowZoom = aParentFont->mAllowZoom;
3268 } else if (eCSSUnit_None == textZoomValue->GetUnit()) {
3269 allowZoom = false;
3270 } else {
3271 MOZ_ASSERT(eCSSUnit_Initial == textZoomValue->GetUnit(),
3272 "unexpected unit");
3273 allowZoom = true;
3275 aFont->EnableZoom(aPresContext, allowZoom);
3278 // mLanguage must be set before before any of the CalcLengthWith calls
3279 // (direct calls or calls via SetFontSize) for the cases where |aParentFont|
3280 // is the same as |aFont|.
3282 // -x-lang: string, inherit
3283 // This is not a real CSS property, it is an HTML attribute mapped to CSS.
3284 const nsCSSValue* langValue = aRuleData->ValueForLang();
3285 if (eCSSUnit_Ident == langValue->GetUnit()) {
3286 nsAutoString lang;
3287 langValue->GetStringValue(lang);
3289 nsContentUtils::ASCIIToLower(lang);
3290 aFont->mLanguage = do_GetAtom(lang);
3291 aFont->mExplicitLanguage = true;
3294 const nsFont* defaultVariableFont =
3295 aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
3296 aFont->mLanguage);
3298 // -moz-system-font: enum (never inherit!)
3299 static_assert(
3300 NS_STYLE_FONT_CAPTION == LookAndFeel::eFont_Caption &&
3301 NS_STYLE_FONT_ICON == LookAndFeel::eFont_Icon &&
3302 NS_STYLE_FONT_MENU == LookAndFeel::eFont_Menu &&
3303 NS_STYLE_FONT_MESSAGE_BOX == LookAndFeel::eFont_MessageBox &&
3304 NS_STYLE_FONT_SMALL_CAPTION == LookAndFeel::eFont_SmallCaption &&
3305 NS_STYLE_FONT_STATUS_BAR == LookAndFeel::eFont_StatusBar &&
3306 NS_STYLE_FONT_WINDOW == LookAndFeel::eFont_Window &&
3307 NS_STYLE_FONT_DOCUMENT == LookAndFeel::eFont_Document &&
3308 NS_STYLE_FONT_WORKSPACE == LookAndFeel::eFont_Workspace &&
3309 NS_STYLE_FONT_DESKTOP == LookAndFeel::eFont_Desktop &&
3310 NS_STYLE_FONT_INFO == LookAndFeel::eFont_Info &&
3311 NS_STYLE_FONT_DIALOG == LookAndFeel::eFont_Dialog &&
3312 NS_STYLE_FONT_BUTTON == LookAndFeel::eFont_Button &&
3313 NS_STYLE_FONT_PULL_DOWN_MENU == LookAndFeel::eFont_PullDownMenu &&
3314 NS_STYLE_FONT_LIST == LookAndFeel::eFont_List &&
3315 NS_STYLE_FONT_FIELD == LookAndFeel::eFont_Field,
3316 "LookAndFeel.h system-font constants out of sync with nsStyleConsts.h");
3318 // Fall back to defaultVariableFont.
3319 nsFont systemFont = *defaultVariableFont;
3320 const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
3321 if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
3322 gfxFontStyle fontStyle;
3323 LookAndFeel::FontID fontID =
3324 (LookAndFeel::FontID)systemFontValue->GetIntValue();
3325 float devPerCSS =
3326 (float)nsPresContext::AppUnitsPerCSSPixel() /
3327 aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
3328 nsAutoString systemFontName;
3329 if (LookAndFeel::GetFont(fontID, systemFontName, fontStyle, devPerCSS)) {
3330 systemFontName.Trim("\"'");
3331 systemFont.fontlist = FontFamilyList(systemFontName, eUnquotedName);
3332 systemFont.fontlist.SetDefaultFontType(eFamily_none);
3333 systemFont.style = fontStyle.style;
3334 systemFont.systemFont = fontStyle.systemFont;
3335 systemFont.weight = fontStyle.weight;
3336 systemFont.stretch = fontStyle.stretch;
3337 systemFont.decorations = NS_FONT_DECORATION_NONE;
3338 systemFont.size = NSFloatPixelsToAppUnits(fontStyle.size,
3339 aPresContext->DeviceContext()->
3340 UnscaledAppUnitsPerDevPixel());
3341 //systemFont.langGroup = fontStyle.langGroup;
3342 systemFont.sizeAdjust = fontStyle.sizeAdjust;
3344 #ifdef XP_WIN
3345 // XXXldb This platform-specific stuff should be in the
3346 // LookAndFeel implementation, not here.
3347 // XXXzw Should we even still *have* this code? It looks to be making
3348 // old, probably obsolete assumptions.
3350 if (fontID == LookAndFeel::eFont_Field ||
3351 fontID == LookAndFeel::eFont_Button ||
3352 fontID == LookAndFeel::eFont_List) {
3353 // As far as I can tell the system default fonts and sizes
3354 // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
3355 // all pre-determined and cannot be changed by either the control panel
3356 // or programmatically.
3357 // Fields (text fields)
3358 // Button and Selects (listboxes/comboboxes)
3359 // We use whatever font is defined by the system. Which it appears
3360 // (and the assumption is) it is always a proportional font. Then we
3361 // always use 2 points smaller than what the browser has defined as
3362 // the default proportional font.
3363 // Assumption: system defined font is proportional
3364 systemFont.size =
3365 std::max(defaultVariableFont->size -
3366 nsPresContext::CSSPointsToAppUnits(2), 0);
3368 #endif
3372 // font-family: font family list, enum, inherit
3373 const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
3374 NS_ASSERTION(eCSSUnit_Enumerated != familyValue->GetUnit(),
3375 "system fonts should not be in mFamily anymore");
3376 if (eCSSUnit_FontFamilyList == familyValue->GetUnit()) {
3377 // set the correct font if we are using DocumentFonts OR we are overriding for XUL
3378 // MJA: bug 31816
3379 if (aGenericFontID == kGenericFont_NONE) {
3380 uint32_t len = defaultVariableFont->fontlist.Length();
3381 FontFamilyType generic = defaultVariableFont->fontlist.FirstGeneric();
3382 NS_ASSERTION(len == 1 &&
3383 (generic == eFamily_serif || generic == eFamily_sans_serif),
3384 "default variable font must be a single serif or sans-serif");
3385 if (len == 1 && generic != eFamily_none) {
3386 aFont->mFont.fontlist.SetDefaultFontType(generic);
3388 } else {
3389 aFont->mFont.fontlist.SetDefaultFontType(eFamily_none);
3391 aFont->mFont.systemFont = false;
3392 // Technically this is redundant with the code below, but it's good
3393 // to have since we'll still want it once we get rid of
3394 // SetGenericFont (bug 380915).
3395 aFont->mGenericID = aGenericFontID;
3397 else if (eCSSUnit_System_Font == familyValue->GetUnit()) {
3398 aFont->mFont.fontlist = systemFont.fontlist;
3399 aFont->mFont.systemFont = true;
3400 aFont->mGenericID = kGenericFont_NONE;
3402 else if (eCSSUnit_Inherit == familyValue->GetUnit() ||
3403 eCSSUnit_Unset == familyValue->GetUnit()) {
3404 aCanStoreInRuleTree = false;
3405 aFont->mFont.fontlist = aParentFont->mFont.fontlist;
3406 aFont->mFont.systemFont = aParentFont->mFont.systemFont;
3407 aFont->mGenericID = aParentFont->mGenericID;
3409 else if (eCSSUnit_Initial == familyValue->GetUnit()) {
3410 aFont->mFont.fontlist = defaultVariableFont->fontlist;
3411 aFont->mFont.systemFont = defaultVariableFont->systemFont;
3412 aFont->mGenericID = kGenericFont_NONE;
3415 // When we're in the loop in SetGenericFont, we must ensure that we
3416 // always keep aFont->mFlags set to the correct generic. But we have
3417 // to be careful not to touch it when we're called directly from
3418 // ComputeFontData, because we could have a start struct.
3419 if (aGenericFontID != kGenericFont_NONE) {
3420 aFont->mGenericID = aGenericFontID;
3423 // -moz-math-variant: enum, inherit, initial
3424 SetDiscrete(*aRuleData->ValueForMathVariant(), aFont->mMathVariant,
3425 aCanStoreInRuleTree,
3426 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
3427 aParentFont->mMathVariant, NS_MATHML_MATHVARIANT_NONE,
3428 0, 0, 0, 0);
3430 // -moz-math-display: enum, inherit, initial
3431 SetDiscrete(*aRuleData->ValueForMathDisplay(), aFont->mMathDisplay,
3432 aCanStoreInRuleTree,
3433 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
3434 aParentFont->mMathDisplay, NS_MATHML_DISPLAYSTYLE_INLINE,
3435 0, 0, 0, 0);
3437 // font-smoothing: enum, inherit, initial
3438 SetDiscrete(*aRuleData->ValueForOSXFontSmoothing(),
3439 aFont->mFont.smoothing, aCanStoreInRuleTree,
3440 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
3441 aParentFont->mFont.smoothing,
3442 defaultVariableFont->smoothing,
3443 0, 0, 0, 0);
3445 // font-style: enum, inherit, initial, -moz-system-font
3446 if (aFont->mMathVariant != NS_MATHML_MATHVARIANT_NONE) {
3447 // -moz-math-variant overrides font-style
3448 aFont->mFont.style = NS_FONT_STYLE_NORMAL;
3449 } else {
3450 SetDiscrete(*aRuleData->ValueForFontStyle(),
3451 aFont->mFont.style, aCanStoreInRuleTree,
3452 SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
3453 aParentFont->mFont.style,
3454 defaultVariableFont->style,
3455 0, 0, 0, systemFont.style);
3458 // font-weight: int, enum, inherit, initial, -moz-system-font
3459 // special handling for enum
3460 const nsCSSValue* weightValue = aRuleData->ValueForFontWeight();
3461 if (aFont->mMathVariant != NS_MATHML_MATHVARIANT_NONE) {
3462 // -moz-math-variant overrides font-weight
3463 aFont->mFont.weight = NS_FONT_WEIGHT_NORMAL;
3464 } else if (eCSSUnit_Enumerated == weightValue->GetUnit()) {
3465 int32_t value = weightValue->GetIntValue();
3466 switch (value) {
3467 case NS_STYLE_FONT_WEIGHT_NORMAL:
3468 case NS_STYLE_FONT_WEIGHT_BOLD:
3469 aFont->mFont.weight = value;
3470 break;
3471 case NS_STYLE_FONT_WEIGHT_BOLDER: {
3472 aCanStoreInRuleTree = false;
3473 int32_t inheritedValue = aParentFont->mFont.weight;
3474 if (inheritedValue <= 300) {
3475 aFont->mFont.weight = 400;
3476 } else if (inheritedValue <= 500) {
3477 aFont->mFont.weight = 700;
3478 } else {
3479 aFont->mFont.weight = 900;
3481 break;
3483 case NS_STYLE_FONT_WEIGHT_LIGHTER: {
3484 aCanStoreInRuleTree = false;
3485 int32_t inheritedValue = aParentFont->mFont.weight;
3486 if (inheritedValue < 600) {
3487 aFont->mFont.weight = 100;
3488 } else if (inheritedValue < 800) {
3489 aFont->mFont.weight = 400;
3490 } else {
3491 aFont->mFont.weight = 700;
3493 break;
3496 } else
3497 SetDiscrete(*weightValue, aFont->mFont.weight, aCanStoreInRuleTree,
3498 SETDSC_INTEGER | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
3499 aParentFont->mFont.weight,
3500 defaultVariableFont->weight,
3501 0, 0, 0, systemFont.weight);
3503 // font-stretch: enum, inherit, initial, -moz-system-font
3504 SetDiscrete(*aRuleData->ValueForFontStretch(),
3505 aFont->mFont.stretch, aCanStoreInRuleTree,
3506 SETDSC_SYSTEM_FONT | SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
3507 aParentFont->mFont.stretch,
3508 defaultVariableFont->stretch,
3509 0, 0, 0, systemFont.stretch);
3511 // Compute scriptlevel, scriptminsize and scriptsizemultiplier now so
3512 // they're available for font-size computation.
3514 // -moz-script-min-size: length
3515 const nsCSSValue* scriptMinSizeValue = aRuleData->ValueForScriptMinSize();
3516 if (scriptMinSizeValue->IsLengthUnit()) {
3517 // scriptminsize in font units (em, ex) has to be interpreted relative
3518 // to the parent font, or the size definitions are circular and we
3520 aFont->mScriptMinSize =
3521 CalcLengthWith(*scriptMinSizeValue, aParentFont->mSize,
3522 aParentFont,
3523 nullptr, aPresContext, atRoot, true,
3524 aCanStoreInRuleTree);
3527 // -moz-script-size-multiplier: factor, inherit, initial
3528 SetFactor(*aRuleData->ValueForScriptSizeMultiplier(),
3529 aFont->mScriptSizeMultiplier,
3530 aCanStoreInRuleTree, aParentFont->mScriptSizeMultiplier,
3531 NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER,
3532 SETFCT_POSITIVE | SETFCT_UNSET_INHERIT);
3534 // -moz-script-level: integer, number, inherit
3535 const nsCSSValue* scriptLevelValue = aRuleData->ValueForScriptLevel();
3536 if (eCSSUnit_Integer == scriptLevelValue->GetUnit()) {
3537 // "relative"
3538 aCanStoreInRuleTree = false;
3539 aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel + scriptLevelValue->GetIntValue());
3541 else if (eCSSUnit_Number == scriptLevelValue->GetUnit()) {
3542 // "absolute"
3543 aFont->mScriptLevel = ClampTo8Bit(int32_t(scriptLevelValue->GetFloatValue()));
3545 else if (eCSSUnit_Auto == scriptLevelValue->GetUnit()) {
3546 // auto
3547 aCanStoreInRuleTree = false;
3548 aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel +
3549 (aParentFont->mMathDisplay ==
3550 NS_MATHML_DISPLAYSTYLE_INLINE ? 1 : 0));
3552 else if (eCSSUnit_Inherit == scriptLevelValue->GetUnit() ||
3553 eCSSUnit_Unset == scriptLevelValue->GetUnit()) {
3554 aCanStoreInRuleTree = false;
3555 aFont->mScriptLevel = aParentFont->mScriptLevel;
3557 else if (eCSSUnit_Initial == scriptLevelValue->GetUnit()) {
3558 aFont->mScriptLevel = 0;
3561 // font-kerning: none, enum, inherit, initial, -moz-system-font
3562 SetDiscrete(*aRuleData->ValueForFontKerning(),
3563 aFont->mFont.kerning, aCanStoreInRuleTree,
3564 SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
3565 aParentFont->mFont.kerning,
3566 defaultVariableFont->kerning,
3567 0, 0, 0, systemFont.kerning);
3569 // font-synthesis: none, enum (bit field), inherit, initial, -moz-system-font
3570 SetDiscrete(*aRuleData->ValueForFontSynthesis(),
3571 aFont->mFont.synthesis, aCanStoreInRuleTree,
3572 SETDSC_NONE | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
3573 SETDSC_UNSET_INHERIT,
3574 aParentFont->mFont.synthesis,
3575 defaultVariableFont->synthesis,
3576 0, 0, 0, systemFont.synthesis);
3578 // font-variant-alternates: normal, enum (bit field) + functions, inherit,
3579 // initial, -moz-system-font
3580 const nsCSSValue* variantAlternatesValue =
3581 aRuleData->ValueForFontVariantAlternates();
3582 int32_t variantAlternates = 0;
3584 switch (variantAlternatesValue->GetUnit()) {
3585 case eCSSUnit_Inherit:
3586 case eCSSUnit_Unset:
3587 aFont->mFont.CopyAlternates(aParentFont->mFont);
3588 aCanStoreInRuleTree = false;
3589 break;
3591 case eCSSUnit_Initial:
3592 case eCSSUnit_Normal:
3593 aFont->mFont.variantAlternates = 0;
3594 aFont->mFont.alternateValues.Clear();
3595 aFont->mFont.featureValueLookup = nullptr;
3596 break;
3598 case eCSSUnit_Pair:
3599 NS_ASSERTION(variantAlternatesValue->GetPairValue().mXValue.GetUnit() ==
3600 eCSSUnit_Enumerated, "strange unit for variantAlternates");
3601 variantAlternates =
3602 variantAlternatesValue->GetPairValue().mXValue.GetIntValue();
3603 aFont->mFont.variantAlternates = variantAlternates;
3605 if (variantAlternates & NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK) {
3606 // fetch the feature lookup object from the styleset
3607 aFont->mFont.featureValueLookup =
3608 aPresContext->StyleSet()->GetFontFeatureValuesLookup();
3610 NS_ASSERTION(variantAlternatesValue->GetPairValue().mYValue.GetUnit() ==
3611 eCSSUnit_List, "function list not a list value");
3612 nsStyleUtil::ComputeFunctionalAlternates(
3613 variantAlternatesValue->GetPairValue().mYValue.GetListValue(),
3614 aFont->mFont.alternateValues);
3616 break;
3618 default:
3619 break;
3622 // font-variant-caps: normal, enum, inherit, initial, -moz-system-font
3623 SetDiscrete(*aRuleData->ValueForFontVariantCaps(),
3624 aFont->mFont.variantCaps, aCanStoreInRuleTree,
3625 SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
3626 SETDSC_UNSET_INHERIT,
3627 aParentFont->mFont.variantCaps,
3628 defaultVariableFont->variantCaps,
3629 0, 0, 0, systemFont.variantCaps);
3631 // font-variant-east-asian: normal, enum (bit field), inherit, initial,
3632 // -moz-system-font
3633 SetDiscrete(*aRuleData->ValueForFontVariantEastAsian(),
3634 aFont->mFont.variantEastAsian, aCanStoreInRuleTree,
3635 SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
3636 SETDSC_UNSET_INHERIT,
3637 aParentFont->mFont.variantEastAsian,
3638 defaultVariableFont->variantEastAsian,
3639 0, 0, 0, systemFont.variantEastAsian);
3641 // font-variant-ligatures: normal, none, enum (bit field), inherit, initial,
3642 // -moz-system-font
3643 SetDiscrete(*aRuleData->ValueForFontVariantLigatures(),
3644 aFont->mFont.variantLigatures, aCanStoreInRuleTree,
3645 SETDSC_NORMAL | SETDSC_NONE | SETDSC_ENUMERATED |
3646 SETDSC_SYSTEM_FONT | SETDSC_UNSET_INHERIT,
3647 aParentFont->mFont.variantLigatures,
3648 defaultVariableFont->variantLigatures,
3649 0, NS_FONT_VARIANT_LIGATURES_NONE, 0, systemFont.variantLigatures);
3651 // font-variant-numeric: normal, enum (bit field), inherit, initial,
3652 // -moz-system-font
3653 SetDiscrete(*aRuleData->ValueForFontVariantNumeric(),
3654 aFont->mFont.variantNumeric, aCanStoreInRuleTree,
3655 SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
3656 SETDSC_UNSET_INHERIT,
3657 aParentFont->mFont.variantNumeric,
3658 defaultVariableFont->variantNumeric,
3659 0, 0, 0, systemFont.variantNumeric);
3661 // font-variant-position: normal, enum, inherit, initial,
3662 // -moz-system-font
3663 SetDiscrete(*aRuleData->ValueForFontVariantPosition(),
3664 aFont->mFont.variantPosition, aCanStoreInRuleTree,
3665 SETDSC_NORMAL | SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT |
3666 SETDSC_UNSET_INHERIT,
3667 aParentFont->mFont.variantPosition,
3668 defaultVariableFont->variantPosition,
3669 0, 0, 0, systemFont.variantPosition);
3671 // font-feature-settings
3672 const nsCSSValue* featureSettingsValue =
3673 aRuleData->ValueForFontFeatureSettings();
3675 switch (featureSettingsValue->GetUnit()) {
3676 case eCSSUnit_Null:
3677 break;
3679 case eCSSUnit_Normal:
3680 case eCSSUnit_Initial:
3681 aFont->mFont.fontFeatureSettings.Clear();
3682 break;
3684 case eCSSUnit_Inherit:
3685 case eCSSUnit_Unset:
3686 aCanStoreInRuleTree = false;
3687 aFont->mFont.fontFeatureSettings = aParentFont->mFont.fontFeatureSettings;
3688 break;
3690 case eCSSUnit_System_Font:
3691 aFont->mFont.fontFeatureSettings = systemFont.fontFeatureSettings;
3692 break;
3694 case eCSSUnit_PairList:
3695 case eCSSUnit_PairListDep:
3696 ComputeFontFeatures(featureSettingsValue->GetPairListValue(),
3697 aFont->mFont.fontFeatureSettings);
3698 break;
3700 default:
3701 NS_ABORT_IF_FALSE(false, "unexpected value unit");
3702 break;
3705 // font-language-override
3706 const nsCSSValue* languageOverrideValue =
3707 aRuleData->ValueForFontLanguageOverride();
3708 if (eCSSUnit_Inherit == languageOverrideValue->GetUnit() ||
3709 eCSSUnit_Unset == languageOverrideValue->GetUnit()) {
3710 aCanStoreInRuleTree = false;
3711 aFont->mFont.languageOverride = aParentFont->mFont.languageOverride;
3712 } else if (eCSSUnit_Normal == languageOverrideValue->GetUnit() ||
3713 eCSSUnit_Initial == languageOverrideValue->GetUnit()) {
3714 aFont->mFont.languageOverride.Truncate();
3715 } else if (eCSSUnit_System_Font == languageOverrideValue->GetUnit()) {
3716 aFont->mFont.languageOverride = systemFont.languageOverride;
3717 } else if (eCSSUnit_String == languageOverrideValue->GetUnit()) {
3718 languageOverrideValue->GetStringValue(aFont->mFont.languageOverride);
3721 // font-size: enum, length, percent, inherit
3722 nscoord scriptLevelAdjustedParentSize = aParentFont->mSize;
3723 nscoord scriptLevelAdjustedUnconstrainedParentSize;
3724 scriptLevelAdjustedParentSize =
3725 ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
3726 &scriptLevelAdjustedUnconstrainedParentSize);
3727 NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
3728 "If we have a start struct, we should have reset everything coming in here");
3729 SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
3730 &aFont->mSize,
3731 systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
3732 aUsedStartStruct, atRoot, aCanStoreInRuleTree);
3733 if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize &&
3734 scriptLevelAdjustedParentSize == scriptLevelAdjustedUnconstrainedParentSize) {
3735 // Fast path: we have not been affected by scriptminsize so we don't
3736 // need to call SetFontSize again to compute the
3737 // scriptminsize-unconstrained size. This is OK even if we have a
3738 // start struct, because if we have a start struct then 'font-size'
3739 // was specified and so scriptminsize has no effect.
3740 aFont->mScriptUnconstrainedSize = aFont->mSize;
3741 } else {
3742 SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
3743 &aFont->mScriptUnconstrainedSize,
3744 systemFont, aParentFont->mScriptUnconstrainedSize,
3745 scriptLevelAdjustedUnconstrainedParentSize,
3746 aUsedStartStruct, atRoot, aCanStoreInRuleTree);
3748 NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
3749 "scriptminsize should never be making things bigger");
3751 nscoord fontSize = aFont->mSize;
3753 // enforce the user' specified minimum font-size on the value that we expose
3754 // (but don't change font-size:0, since that would unhide hidden text)
3755 if (fontSize > 0) {
3756 nscoord minFontSize = aPresContext->MinFontSize(aFont->mLanguage);
3757 if (minFontSize < 0) {
3758 minFontSize = 0;
3760 if (fontSize < minFontSize && !aPresContext->IsChrome()) {
3761 // override the minimum font-size constraint
3762 fontSize = minFontSize;
3765 aFont->mFont.size = fontSize;
3767 // font-size-adjust: number, none, inherit, initial, -moz-system-font
3768 const nsCSSValue* sizeAdjustValue = aRuleData->ValueForFontSizeAdjust();
3769 if (eCSSUnit_System_Font == sizeAdjustValue->GetUnit()) {
3770 aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
3771 } else
3772 SetFactor(*sizeAdjustValue, aFont->mFont.sizeAdjust,
3773 aCanStoreInRuleTree, aParentFont->mFont.sizeAdjust, 0.0f,
3774 SETFCT_NONE | SETFCT_UNSET_INHERIT);
3777 /* static */ void
3778 nsRuleNode::ComputeFontFeatures(const nsCSSValuePairList *aFeaturesList,
3779 nsTArray<gfxFontFeature>& aFeatureSettings)
3781 aFeatureSettings.Clear();
3782 for (const nsCSSValuePairList* p = aFeaturesList; p; p = p->mNext) {
3783 gfxFontFeature feat = {0, 0};
3785 NS_ABORT_IF_FALSE(aFeaturesList->mXValue.GetUnit() == eCSSUnit_String,
3786 "unexpected value unit");
3788 // tag is a 4-byte ASCII sequence
3789 nsAutoString tag;
3790 p->mXValue.GetStringValue(tag);
3791 if (tag.Length() != 4) {
3792 continue;
3794 // parsing validates that these are ASCII chars
3795 // tags are always big-endian
3796 feat.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8) | tag[3];
3798 // value
3799 NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Integer,
3800 "should have found an integer unit");
3801 feat.mValue = p->mYValue.GetIntValue();
3803 aFeatureSettings.AppendElement(feat);
3807 // This should die (bug 380915).
3809 // SetGenericFont:
3810 // - backtrack to an ancestor with the same generic font name (possibly
3811 // up to the root where default values come from the presentation context)
3812 // - re-apply cascading rules from there without caching intermediate values
3813 /* static */ void
3814 nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
3815 nsStyleContext* aContext,
3816 uint8_t aGenericFontID,
3817 nsStyleFont* aFont)
3819 // walk up the contexts until a context with the desired generic font
3820 nsAutoTArray<nsStyleContext*, 8> contextPath;
3821 contextPath.AppendElement(aContext);
3822 nsStyleContext* higherContext = aContext->GetParent();
3823 while (higherContext) {
3824 if (higherContext->StyleFont()->mGenericID == aGenericFontID) {
3825 // done walking up the higher contexts
3826 break;
3828 contextPath.AppendElement(higherContext);
3829 higherContext = higherContext->GetParent();
3832 // re-apply the cascading rules, starting from the higher context
3834 // If we stopped earlier because we reached the root of the style tree,
3835 // we will start with the default generic font from the presentation
3836 // context. Otherwise we start with the higher context.
3837 const nsFont* defaultFont =
3838 aPresContext->GetDefaultFont(aGenericFontID, aFont->mLanguage);
3839 nsStyleFont parentFont(*defaultFont, aPresContext);
3840 if (higherContext) {
3841 const nsStyleFont* tmpFont = higherContext->StyleFont();
3842 parentFont = *tmpFont;
3844 *aFont = parentFont;
3846 bool dummy;
3847 uint32_t fontBit = nsCachedStyleData::GetBitForSID(eStyleStruct_Font);
3849 // use placement new[] on the result of alloca() to allocate a
3850 // variable-sized stack array, including execution of constructors,
3851 // and use an RAII class to run the destructors too.
3852 size_t nprops = nsCSSProps::PropertyCountInStruct(eStyleStruct_Font);
3853 void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
3855 for (int32_t i = contextPath.Length() - 1; i >= 0; --i) {
3856 nsStyleContext* context = contextPath[i];
3857 AutoCSSValueArray dataArray(dataStorage, nprops);
3859 nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), dataArray.get(),
3860 aPresContext, context);
3861 ruleData.mValueOffsets[eStyleStruct_Font] = 0;
3863 // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
3864 // Note that we *do* need to do this for our own data, since what is
3865 // in |fontData| in ComputeFontData is only for the rules below
3866 // aStartStruct.
3867 for (nsRuleNode* ruleNode = context->RuleNode(); ruleNode;
3868 ruleNode = ruleNode->GetParent()) {
3869 if (ruleNode->mNoneBits & fontBit)
3870 // no more font rules on this branch, get out
3871 break;
3873 nsIStyleRule *rule = ruleNode->GetRule();
3874 if (rule) {
3875 ruleData.mLevel = ruleNode->GetLevel();
3876 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
3877 rule->MapRuleInfoInto(&ruleData);
3881 // Compute the delta from the information that the rules specified
3883 // Avoid unnecessary operations in SetFont(). But we care if it's
3884 // the final value that we're computing.
3885 if (i != 0)
3886 ruleData.ValueForFontFamily()->Reset();
3888 ResolveVariableReferences(eStyleStruct_Font, &ruleData, aContext);
3890 nsRuleNode::SetFont(aPresContext, context,
3891 aGenericFontID, &ruleData, &parentFont, aFont,
3892 false, dummy);
3894 parentFont = *aFont;
3898 const void*
3899 nsRuleNode::ComputeFontData(void* aStartStruct,
3900 const nsRuleData* aRuleData,
3901 nsStyleContext* aContext,
3902 nsRuleNode* aHighestNode,
3903 const RuleDetail aRuleDetail,
3904 const bool aCanStoreInRuleTree)
3906 COMPUTE_START_INHERITED(Font, (mPresContext), font, parentFont)
3908 // NOTE: The |aRuleDetail| passed in is a little bit conservative due
3909 // to the -moz-system-font property. We really don't need to consider
3910 // it here in determining whether to cache in the rule tree. However,
3911 // we do need to consider it in WalkRuleTree when deciding whether to
3912 // walk further up the tree. So this means that when the font struct
3913 // is fully specified using *longhand* properties (excluding
3914 // -moz-system-font), we won't cache in the rule tree even though we
3915 // could. However, it's pretty unlikely authors will do that
3916 // (although there is a pretty good chance they'll fully specify it
3917 // using the 'font' shorthand).
3919 bool useDocumentFonts =
3920 mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
3922 // See if we are in the chrome
3923 // We only need to know this to determine if we have to use the
3924 // document fonts (overriding the useDocumentFonts flag).
3925 if (!useDocumentFonts && mPresContext->IsChrome()) {
3926 // if we are not using document fonts, but this is a XUL document,
3927 // then we use the document fonts anyway
3928 useDocumentFonts = true;
3931 // Figure out if we are a generic font
3932 uint8_t generic = kGenericFont_NONE;
3933 // XXXldb What if we would have had a string if we hadn't been doing
3934 // the optimization with a non-null aStartStruct?
3935 const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
3936 if (eCSSUnit_FontFamilyList == familyValue->GetUnit()) {
3937 const FontFamilyList* fontlist = familyValue->GetFontFamilyListValue();
3938 FontFamilyList& fl = font->mFont.fontlist;
3939 fl = *fontlist;
3941 // extract the first generic in the fontlist, if exists
3942 FontFamilyType fontType = fontlist->FirstGeneric();
3944 // if only a single generic, set the generic type
3945 if (fontlist->Length() == 1) {
3946 switch (fontType) {
3947 case eFamily_serif:
3948 generic = kGenericFont_serif;
3949 break;
3950 case eFamily_sans_serif:
3951 generic = kGenericFont_sans_serif;
3952 break;
3953 case eFamily_monospace:
3954 generic = kGenericFont_monospace;
3955 break;
3956 case eFamily_cursive:
3957 generic = kGenericFont_cursive;
3958 break;
3959 case eFamily_fantasy:
3960 generic = kGenericFont_fantasy;
3961 break;
3962 case eFamily_moz_fixed:
3963 generic = kGenericFont_moz_fixed;
3964 break;
3965 default:
3966 break;
3970 // If we aren't allowed to use document fonts, then we are only entitled
3971 // to use the user's default variable-width font and fixed-width font
3972 if (!useDocumentFonts) {
3973 switch (fontType) {
3974 case eFamily_monospace:
3975 fl = FontFamilyList(eFamily_monospace);
3976 generic = kGenericFont_monospace;
3977 break;
3978 case eFamily_moz_fixed:
3979 fl = FontFamilyList(eFamily_moz_fixed);
3980 generic = kGenericFont_moz_fixed;
3981 break;
3982 default:
3983 fl.Clear();
3984 generic = kGenericFont_NONE;
3985 break;
3990 // Now compute our font struct
3991 if (generic == kGenericFont_NONE) {
3992 // continue the normal processing
3993 nsRuleNode::SetFont(mPresContext, aContext, generic,
3994 aRuleData, parentFont, font,
3995 aStartStruct != nullptr, canStoreInRuleTree);
3997 else {
3998 // re-calculate the font as a generic font
3999 canStoreInRuleTree = false;
4000 nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
4001 font);
4004 COMPUTE_END_INHERITED(Font, font)
4007 template <typename T>
4008 inline uint32_t ListLength(const T* aList)
4010 uint32_t len = 0;
4011 while (aList) {
4012 len++;
4013 aList = aList->mNext;
4015 return len;
4020 already_AddRefed<nsCSSShadowArray>
4021 nsRuleNode::GetShadowData(const nsCSSValueList* aList,
4022 nsStyleContext* aContext,
4023 bool aIsBoxShadow,
4024 bool& aCanStoreInRuleTree)
4026 uint32_t arrayLength = ListLength(aList);
4028 NS_ABORT_IF_FALSE(arrayLength > 0,
4029 "Non-null text-shadow list, yet we counted 0 items.");
4030 nsRefPtr<nsCSSShadowArray> shadowList =
4031 new(arrayLength) nsCSSShadowArray(arrayLength);
4033 if (!shadowList)
4034 return nullptr;
4036 nsStyleCoord tempCoord;
4037 DebugOnly<bool> unitOK;
4038 for (nsCSSShadowItem* item = shadowList->ShadowAt(0);
4039 aList;
4040 aList = aList->mNext, ++item) {
4041 NS_ABORT_IF_FALSE(aList->mValue.GetUnit() == eCSSUnit_Array,
4042 "expecting a plain array value");
4043 nsCSSValue::Array *arr = aList->mValue.GetArrayValue();
4044 // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
4045 unitOK = SetCoord(arr->Item(0), tempCoord, nsStyleCoord(),
4046 SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
4047 aContext, mPresContext, aCanStoreInRuleTree);
4048 NS_ASSERTION(unitOK, "unexpected unit");
4049 item->mXOffset = tempCoord.GetCoordValue();
4051 unitOK = SetCoord(arr->Item(1), tempCoord, nsStyleCoord(),
4052 SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
4053 aContext, mPresContext, aCanStoreInRuleTree);
4054 NS_ASSERTION(unitOK, "unexpected unit");
4055 item->mYOffset = tempCoord.GetCoordValue();
4057 // Blur radius is optional in the current box-shadow spec
4058 if (arr->Item(2).GetUnit() != eCSSUnit_Null) {
4059 unitOK = SetCoord(arr->Item(2), tempCoord, nsStyleCoord(),
4060 SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY |
4061 SETCOORD_CALC_CLAMP_NONNEGATIVE,
4062 aContext, mPresContext, aCanStoreInRuleTree);
4063 NS_ASSERTION(unitOK, "unexpected unit");
4064 item->mRadius = tempCoord.GetCoordValue();
4065 } else {
4066 item->mRadius = 0;
4069 // Find the spread radius
4070 if (aIsBoxShadow && arr->Item(3).GetUnit() != eCSSUnit_Null) {
4071 unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(),
4072 SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
4073 aContext, mPresContext, aCanStoreInRuleTree);
4074 NS_ASSERTION(unitOK, "unexpected unit");
4075 item->mSpread = tempCoord.GetCoordValue();
4076 } else {
4077 item->mSpread = 0;
4080 if (arr->Item(4).GetUnit() != eCSSUnit_Null) {
4081 item->mHasColor = true;
4082 // 2nd argument can be bogus since inherit is not a valid color
4083 unitOK = SetColor(arr->Item(4), 0, mPresContext, aContext, item->mColor,
4084 aCanStoreInRuleTree);
4085 NS_ASSERTION(unitOK, "unexpected unit");
4088 if (aIsBoxShadow && arr->Item(5).GetUnit() == eCSSUnit_Enumerated) {
4089 NS_ASSERTION(arr->Item(5).GetIntValue() == NS_STYLE_BOX_SHADOW_INSET,
4090 "invalid keyword type for box shadow");
4091 item->mInset = true;
4092 } else {
4093 item->mInset = false;
4097 return shadowList.forget();
4100 const void*
4101 nsRuleNode::ComputeTextData(void* aStartStruct,
4102 const nsRuleData* aRuleData,
4103 nsStyleContext* aContext,
4104 nsRuleNode* aHighestNode,
4105 const RuleDetail aRuleDetail,
4106 const bool aCanStoreInRuleTree)
4108 COMPUTE_START_INHERITED(Text, (), text, parentText)
4110 // tab-size: integer, inherit
4111 SetDiscrete(*aRuleData->ValueForTabSize(),
4112 text->mTabSize, canStoreInRuleTree,
4113 SETDSC_INTEGER | SETDSC_UNSET_INHERIT, parentText->mTabSize,
4114 NS_STYLE_TABSIZE_INITIAL, 0, 0, 0, 0);
4116 // letter-spacing: normal, length, inherit
4117 SetCoord(*aRuleData->ValueForLetterSpacing(),
4118 text->mLetterSpacing, parentText->mLetterSpacing,
4119 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
4120 SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INHERIT,
4121 aContext, mPresContext, canStoreInRuleTree);
4123 // text-shadow: none, list, inherit, initial
4124 const nsCSSValue* textShadowValue = aRuleData->ValueForTextShadow();
4125 if (textShadowValue->GetUnit() != eCSSUnit_Null) {
4126 text->mTextShadow = nullptr;
4128 // Don't need to handle none/initial explicitly: The above assignment
4129 // takes care of that
4130 if (textShadowValue->GetUnit() == eCSSUnit_Inherit ||
4131 textShadowValue->GetUnit() == eCSSUnit_Unset) {
4132 canStoreInRuleTree = false;
4133 text->mTextShadow = parentText->mTextShadow;
4134 } else if (textShadowValue->GetUnit() == eCSSUnit_List ||
4135 textShadowValue->GetUnit() == eCSSUnit_ListDep) {
4136 // List of arrays
4137 text->mTextShadow = GetShadowData(textShadowValue->GetListValue(),
4138 aContext, false, canStoreInRuleTree);
4142 // line-height: normal, number, length, percent, inherit
4143 const nsCSSValue* lineHeightValue = aRuleData->ValueForLineHeight();
4144 if (eCSSUnit_Percent == lineHeightValue->GetUnit()) {
4145 canStoreInRuleTree = false;
4146 // Use |mFont.size| to pick up minimum font size.
4147 text->mLineHeight.SetCoordValue(
4148 NSToCoordRound(float(aContext->StyleFont()->mFont.size) *
4149 lineHeightValue->GetPercentValue()));
4151 else if (eCSSUnit_Initial == lineHeightValue->GetUnit() ||
4152 eCSSUnit_System_Font == lineHeightValue->GetUnit()) {
4153 text->mLineHeight.SetNormalValue();
4155 else {
4156 SetCoord(*lineHeightValue, text->mLineHeight, parentText->mLineHeight,
4157 SETCOORD_LEH | SETCOORD_FACTOR | SETCOORD_NORMAL |
4158 SETCOORD_UNSET_INHERIT,
4159 aContext, mPresContext, canStoreInRuleTree);
4160 if (lineHeightValue->IsLengthUnit() &&
4161 !lineHeightValue->IsRelativeLengthUnit()) {
4162 nscoord lh = nsStyleFont::ZoomText(mPresContext,
4163 text->mLineHeight.GetCoordValue());
4165 canStoreInRuleTree = false;
4166 const nsStyleFont *font = aContext->StyleFont();
4167 nscoord minimumFontSize = mPresContext->MinFontSize(font->mLanguage);
4169 if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
4170 if (font->mSize != 0) {
4171 lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
4172 } else {
4173 lh = minimumFontSize;
4176 text->mLineHeight.SetCoordValue(lh);
4181 // text-align: enum, string, pair(enum|string), inherit, initial
4182 // NOTE: string is not implemented yet.
4183 const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
4184 text->mTextAlignTrue = false;
4185 if (eCSSUnit_String == textAlignValue->GetUnit()) {
4186 NS_NOTYETIMPLEMENTED("align string");
4187 } else if (eCSSUnit_Enumerated == textAlignValue->GetUnit() &&
4188 NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT ==
4189 textAlignValue->GetIntValue()) {
4190 canStoreInRuleTree = false;
4191 uint8_t parentAlign = parentText->mTextAlign;
4192 text->mTextAlign = (NS_STYLE_TEXT_ALIGN_DEFAULT == parentAlign) ?
4193 NS_STYLE_TEXT_ALIGN_CENTER : parentAlign;
4194 } else {
4195 if (eCSSUnit_Pair == textAlignValue->GetUnit()) {
4196 // Two values were specified, one must be 'true'.
4197 text->mTextAlignTrue = true;
4198 const nsCSSValuePair& textAlignValuePair = textAlignValue->GetPairValue();
4199 textAlignValue = &textAlignValuePair.mXValue;
4200 if (eCSSUnit_Enumerated == textAlignValue->GetUnit()) {
4201 if (textAlignValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
4202 textAlignValue = &textAlignValuePair.mYValue;
4204 } else if (eCSSUnit_String == textAlignValue->GetUnit()) {
4205 NS_NOTYETIMPLEMENTED("align string");
4207 } else if (eCSSUnit_Inherit == textAlignValue->GetUnit() ||
4208 eCSSUnit_Unset == textAlignValue->GetUnit()) {
4209 text->mTextAlignTrue = parentText->mTextAlignTrue;
4211 SetDiscrete(*textAlignValue, text->mTextAlign, canStoreInRuleTree,
4212 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4213 parentText->mTextAlign,
4214 NS_STYLE_TEXT_ALIGN_DEFAULT, 0, 0, 0, 0);
4217 // text-align-last: enum, pair(enum), inherit, initial
4218 const nsCSSValue* textAlignLastValue = aRuleData->ValueForTextAlignLast();
4219 text->mTextAlignLastTrue = false;
4220 if (eCSSUnit_Pair == textAlignLastValue->GetUnit()) {
4221 // Two values were specified, one must be 'true'.
4222 text->mTextAlignLastTrue = true;
4223 const nsCSSValuePair& textAlignLastValuePair = textAlignLastValue->GetPairValue();
4224 textAlignLastValue = &textAlignLastValuePair.mXValue;
4225 if (eCSSUnit_Enumerated == textAlignLastValue->GetUnit()) {
4226 if (textAlignLastValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) {
4227 textAlignLastValue = &textAlignLastValuePair.mYValue;
4230 } else if (eCSSUnit_Inherit == textAlignLastValue->GetUnit() ||
4231 eCSSUnit_Unset == textAlignLastValue->GetUnit()) {
4232 text->mTextAlignLastTrue = parentText->mTextAlignLastTrue;
4234 SetDiscrete(*textAlignLastValue, text->mTextAlignLast,
4235 canStoreInRuleTree,
4236 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4237 parentText->mTextAlignLast,
4238 NS_STYLE_TEXT_ALIGN_AUTO, 0, 0, 0, 0);
4240 // text-indent: length, percent, calc, inherit, initial
4241 SetCoord(*aRuleData->ValueForTextIndent(), text->mTextIndent, parentText->mTextIndent,
4242 SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
4243 SETCOORD_UNSET_INHERIT,
4244 aContext, mPresContext, canStoreInRuleTree);
4246 // text-transform: enum, inherit, initial
4247 SetDiscrete(*aRuleData->ValueForTextTransform(), text->mTextTransform, canStoreInRuleTree,
4248 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4249 parentText->mTextTransform,
4250 NS_STYLE_TEXT_TRANSFORM_NONE, 0, 0, 0, 0);
4252 // white-space: enum, inherit, initial
4253 SetDiscrete(*aRuleData->ValueForWhiteSpace(), text->mWhiteSpace, canStoreInRuleTree,
4254 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4255 parentText->mWhiteSpace,
4256 NS_STYLE_WHITESPACE_NORMAL, 0, 0, 0, 0);
4258 // word-break: enum, inherit, initial
4259 SetDiscrete(*aRuleData->ValueForWordBreak(), text->mWordBreak, canStoreInRuleTree,
4260 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4261 parentText->mWordBreak,
4262 NS_STYLE_WORDBREAK_NORMAL, 0, 0, 0, 0);
4264 // word-spacing: normal, length, inherit
4265 nsStyleCoord tempCoord;
4266 const nsCSSValue* wordSpacingValue = aRuleData->ValueForWordSpacing();
4267 if (SetCoord(*wordSpacingValue, tempCoord,
4268 nsStyleCoord(parentText->mWordSpacing,
4269 nsStyleCoord::CoordConstructor),
4270 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
4271 SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INHERIT,
4272 aContext, mPresContext, canStoreInRuleTree)) {
4273 if (tempCoord.GetUnit() == eStyleUnit_Coord) {
4274 text->mWordSpacing = tempCoord.GetCoordValue();
4275 } else if (tempCoord.GetUnit() == eStyleUnit_Normal) {
4276 text->mWordSpacing = 0;
4277 } else {
4278 NS_NOTREACHED("unexpected unit");
4280 } else {
4281 NS_ASSERTION(wordSpacingValue->GetUnit() == eCSSUnit_Null,
4282 "unexpected unit");
4285 // word-wrap: enum, inherit, initial
4286 SetDiscrete(*aRuleData->ValueForWordWrap(), text->mWordWrap, canStoreInRuleTree,
4287 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4288 parentText->mWordWrap,
4289 NS_STYLE_WORDWRAP_NORMAL, 0, 0, 0, 0);
4291 // hyphens: enum, inherit, initial
4292 SetDiscrete(*aRuleData->ValueForHyphens(), text->mHyphens, canStoreInRuleTree,
4293 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4294 parentText->mHyphens,
4295 NS_STYLE_HYPHENS_MANUAL, 0, 0, 0, 0);
4297 // text-size-adjust: none, auto, inherit, initial
4298 SetDiscrete(*aRuleData->ValueForTextSizeAdjust(), text->mTextSizeAdjust,
4299 canStoreInRuleTree,
4300 SETDSC_NONE | SETDSC_AUTO | SETDSC_UNSET_INHERIT,
4301 parentText->mTextSizeAdjust,
4302 NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // initial value
4303 NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // auto value
4304 NS_STYLE_TEXT_SIZE_ADJUST_NONE, // none value
4305 0, 0);
4307 // -moz-text-discard: enum, inherit, initial
4308 SetDiscrete(*aRuleData->ValueForControlCharacterVisibility(),
4309 text->mControlCharacterVisibility,
4310 canStoreInRuleTree,
4311 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4312 parentText->mControlCharacterVisibility,
4313 NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN, 0, 0, 0, 0);
4315 // text-orientation: enum, inherit, initial
4316 SetDiscrete(*aRuleData->ValueForTextOrientation(), text->mTextOrientation,
4317 canStoreInRuleTree,
4318 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4319 parentText->mTextOrientation,
4320 NS_STYLE_TEXT_ORIENTATION_AUTO, 0, 0, 0, 0);
4322 // text-combine-upright: enum, inherit, initial
4323 SetDiscrete(*aRuleData->ValueForTextCombineUpright(),
4324 text->mTextCombineUpright,
4325 canStoreInRuleTree,
4326 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4327 parentText->mTextCombineUpright,
4328 NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE, 0, 0, 0, 0);
4330 COMPUTE_END_INHERITED(Text, text)
4333 const void*
4334 nsRuleNode::ComputeTextResetData(void* aStartStruct,
4335 const nsRuleData* aRuleData,
4336 nsStyleContext* aContext,
4337 nsRuleNode* aHighestNode,
4338 const RuleDetail aRuleDetail,
4339 const bool aCanStoreInRuleTree)
4341 COMPUTE_START_RESET(TextReset, (), text, parentText)
4343 // vertical-align: enum, length, percent, calc, inherit
4344 const nsCSSValue* verticalAlignValue = aRuleData->ValueForVerticalAlign();
4345 if (!SetCoord(*verticalAlignValue, text->mVerticalAlign,
4346 parentText->mVerticalAlign,
4347 SETCOORD_LPH | SETCOORD_ENUMERATED | SETCOORD_STORE_CALC,
4348 aContext, mPresContext, canStoreInRuleTree)) {
4349 if (eCSSUnit_Initial == verticalAlignValue->GetUnit() ||
4350 eCSSUnit_Unset == verticalAlignValue->GetUnit()) {
4351 text->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE,
4352 eStyleUnit_Enumerated);
4356 // text-decoration-line: enum (bit field), inherit, initial
4357 const nsCSSValue* decorationLineValue =
4358 aRuleData->ValueForTextDecorationLine();
4359 if (eCSSUnit_Enumerated == decorationLineValue->GetUnit()) {
4360 int32_t td = decorationLineValue->GetIntValue();
4361 text->mTextDecorationLine = td;
4362 if (td & NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS) {
4363 bool underlineLinks =
4364 mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
4365 if (underlineLinks) {
4366 text->mTextDecorationLine |= NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
4368 else {
4369 text->mTextDecorationLine &= ~NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
4372 } else if (eCSSUnit_Inherit == decorationLineValue->GetUnit()) {
4373 canStoreInRuleTree = false;
4374 text->mTextDecorationLine = parentText->mTextDecorationLine;
4375 } else if (eCSSUnit_Initial == decorationLineValue->GetUnit() ||
4376 eCSSUnit_Unset == decorationLineValue->GetUnit()) {
4377 text->mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
4380 // text-decoration-color: color, string, enum, inherit, initial
4381 const nsCSSValue* decorationColorValue =
4382 aRuleData->ValueForTextDecorationColor();
4383 nscolor decorationColor;
4384 if (eCSSUnit_Inherit == decorationColorValue->GetUnit()) {
4385 canStoreInRuleTree = false;
4386 if (parentContext) {
4387 bool isForeground;
4388 parentText->GetDecorationColor(decorationColor, isForeground);
4389 if (isForeground) {
4390 text->SetDecorationColor(parentContext->StyleColor()->mColor);
4391 } else {
4392 text->SetDecorationColor(decorationColor);
4394 } else {
4395 text->SetDecorationColorToForeground();
4398 else if (eCSSUnit_EnumColor == decorationColorValue->GetUnit() &&
4399 decorationColorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
4400 text->SetDecorationColorToForeground();
4402 else if (SetColor(*decorationColorValue, 0, mPresContext, aContext,
4403 decorationColor, canStoreInRuleTree)) {
4404 text->SetDecorationColor(decorationColor);
4406 else if (eCSSUnit_Initial == decorationColorValue->GetUnit() ||
4407 eCSSUnit_Unset == decorationColorValue->GetUnit() ||
4408 eCSSUnit_Enumerated == decorationColorValue->GetUnit()) {
4409 NS_ABORT_IF_FALSE(eCSSUnit_Enumerated != decorationColorValue->GetUnit() ||
4410 decorationColorValue->GetIntValue() ==
4411 NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,
4412 "unexpected enumerated value");
4413 text->SetDecorationColorToForeground();
4416 // text-decoration-style: enum, inherit, initial
4417 const nsCSSValue* decorationStyleValue =
4418 aRuleData->ValueForTextDecorationStyle();
4419 if (eCSSUnit_Enumerated == decorationStyleValue->GetUnit()) {
4420 text->SetDecorationStyle(decorationStyleValue->GetIntValue());
4421 } else if (eCSSUnit_Inherit == decorationStyleValue->GetUnit()) {
4422 text->SetDecorationStyle(parentText->GetDecorationStyle());
4423 canStoreInRuleTree = false;
4424 } else if (eCSSUnit_Initial == decorationStyleValue->GetUnit() ||
4425 eCSSUnit_Unset == decorationStyleValue->GetUnit()) {
4426 text->SetDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID);
4429 // text-overflow: enum, string, pair(enum|string), inherit, initial
4430 const nsCSSValue* textOverflowValue =
4431 aRuleData->ValueForTextOverflow();
4432 if (eCSSUnit_Initial == textOverflowValue->GetUnit() ||
4433 eCSSUnit_Unset == textOverflowValue->GetUnit()) {
4434 text->mTextOverflow = nsStyleTextOverflow();
4435 } else if (eCSSUnit_Inherit == textOverflowValue->GetUnit()) {
4436 canStoreInRuleTree = false;
4437 text->mTextOverflow = parentText->mTextOverflow;
4438 } else if (eCSSUnit_Enumerated == textOverflowValue->GetUnit()) {
4439 // A single enumerated value.
4440 SetDiscrete(*textOverflowValue, text->mTextOverflow.mRight.mType,
4441 canStoreInRuleTree,
4442 SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
4443 NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
4444 text->mTextOverflow.mRight.mString.Truncate();
4445 text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
4446 text->mTextOverflow.mLeft.mString.Truncate();
4447 text->mTextOverflow.mLogicalDirections = true;
4448 } else if (eCSSUnit_String == textOverflowValue->GetUnit()) {
4449 // A single string value.
4450 text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
4451 textOverflowValue->GetStringValue(text->mTextOverflow.mRight.mString);
4452 text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
4453 text->mTextOverflow.mLeft.mString.Truncate();
4454 text->mTextOverflow.mLogicalDirections = true;
4455 } else if (eCSSUnit_Pair == textOverflowValue->GetUnit()) {
4456 // Two values were specified.
4457 text->mTextOverflow.mLogicalDirections = false;
4458 const nsCSSValuePair& textOverflowValuePair =
4459 textOverflowValue->GetPairValue();
4461 const nsCSSValue *textOverflowLeftValue = &textOverflowValuePair.mXValue;
4462 if (eCSSUnit_Enumerated == textOverflowLeftValue->GetUnit()) {
4463 SetDiscrete(*textOverflowLeftValue, text->mTextOverflow.mLeft.mType,
4464 canStoreInRuleTree,
4465 SETDSC_ENUMERATED, parentText->mTextOverflow.mLeft.mType,
4466 NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
4467 text->mTextOverflow.mLeft.mString.Truncate();
4468 } else if (eCSSUnit_String == textOverflowLeftValue->GetUnit()) {
4469 textOverflowLeftValue->GetStringValue(text->mTextOverflow.mLeft.mString);
4470 text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
4473 const nsCSSValue *textOverflowRightValue = &textOverflowValuePair.mYValue;
4474 if (eCSSUnit_Enumerated == textOverflowRightValue->GetUnit()) {
4475 SetDiscrete(*textOverflowRightValue, text->mTextOverflow.mRight.mType,
4476 canStoreInRuleTree,
4477 SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
4478 NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
4479 text->mTextOverflow.mRight.mString.Truncate();
4480 } else if (eCSSUnit_String == textOverflowRightValue->GetUnit()) {
4481 textOverflowRightValue->GetStringValue(text->mTextOverflow.mRight.mString);
4482 text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
4486 // unicode-bidi: enum, inherit, initial
4487 SetDiscrete(*aRuleData->ValueForUnicodeBidi(), text->mUnicodeBidi, canStoreInRuleTree,
4488 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
4489 parentText->mUnicodeBidi,
4490 NS_STYLE_UNICODE_BIDI_NORMAL, 0, 0, 0, 0);
4492 COMPUTE_END_RESET(TextReset, text)
4495 const void*
4496 nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
4497 const nsRuleData* aRuleData,
4498 nsStyleContext* aContext,
4499 nsRuleNode* aHighestNode,
4500 const RuleDetail aRuleDetail,
4501 const bool aCanStoreInRuleTree)
4503 COMPUTE_START_INHERITED(UserInterface, (), ui, parentUI)
4505 // cursor: enum, url, inherit
4506 const nsCSSValue* cursorValue = aRuleData->ValueForCursor();
4507 nsCSSUnit cursorUnit = cursorValue->GetUnit();
4508 if (cursorUnit != eCSSUnit_Null) {
4509 delete [] ui->mCursorArray;
4510 ui->mCursorArray = nullptr;
4511 ui->mCursorArrayLength = 0;
4513 if (cursorUnit == eCSSUnit_Inherit ||
4514 cursorUnit == eCSSUnit_Unset) {
4515 canStoreInRuleTree = false;
4516 ui->mCursor = parentUI->mCursor;
4517 ui->CopyCursorArrayFrom(*parentUI);
4519 else if (cursorUnit == eCSSUnit_Initial) {
4520 ui->mCursor = NS_STYLE_CURSOR_AUTO;
4522 else {
4523 // The parser will never create a list that is *all* URL values --
4524 // that's invalid.
4525 NS_ABORT_IF_FALSE(cursorUnit == eCSSUnit_List ||
4526 cursorUnit == eCSSUnit_ListDep,
4527 nsPrintfCString("unrecognized cursor unit %d",
4528 cursorUnit).get());
4529 const nsCSSValueList* list = cursorValue->GetListValue();
4530 const nsCSSValueList* list2 = list;
4531 nsIDocument* doc = aContext->PresContext()->Document();
4532 uint32_t arrayLength = 0;
4533 for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext)
4534 if (list->mValue.GetArrayValue()->Item(0).GetImageValue(doc))
4535 ++arrayLength;
4537 if (arrayLength != 0) {
4538 ui->mCursorArray = new nsCursorImage[arrayLength];
4539 if (ui->mCursorArray) {
4540 ui->mCursorArrayLength = arrayLength;
4542 for (nsCursorImage *item = ui->mCursorArray;
4543 list2->mValue.GetUnit() == eCSSUnit_Array;
4544 list2 = list2->mNext) {
4545 nsCSSValue::Array *arr = list2->mValue.GetArrayValue();
4546 imgIRequest *req = arr->Item(0).GetImageValue(doc);
4547 if (req) {
4548 item->SetImage(req);
4549 if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
4550 item->mHaveHotspot = true;
4551 item->mHotspotX = arr->Item(1).GetFloatValue(),
4552 item->mHotspotY = arr->Item(2).GetFloatValue();
4554 ++item;
4560 NS_ASSERTION(list, "Must have non-array value at the end");
4561 NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated,
4562 "Unexpected fallback value at end of cursor list");
4563 ui->mCursor = list->mValue.GetIntValue();
4567 // user-input: enum, inherit, initial
4568 SetDiscrete(*aRuleData->ValueForUserInput(),
4569 ui->mUserInput, canStoreInRuleTree,
4570 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4571 parentUI->mUserInput,
4572 NS_STYLE_USER_INPUT_AUTO, 0, 0, 0, 0);
4574 // user-modify: enum, inherit, initial
4575 SetDiscrete(*aRuleData->ValueForUserModify(),
4576 ui->mUserModify, canStoreInRuleTree,
4577 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4578 parentUI->mUserModify,
4579 NS_STYLE_USER_MODIFY_READ_ONLY,
4580 0, 0, 0, 0);
4582 // user-focus: enum, inherit, initial
4583 SetDiscrete(*aRuleData->ValueForUserFocus(),
4584 ui->mUserFocus, canStoreInRuleTree,
4585 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
4586 parentUI->mUserFocus,
4587 NS_STYLE_USER_FOCUS_NONE, 0, 0, 0, 0);
4589 COMPUTE_END_INHERITED(UserInterface, ui)
4592 const void*
4593 nsRuleNode::ComputeUIResetData(void* aStartStruct,
4594 const nsRuleData* aRuleData,
4595 nsStyleContext* aContext,
4596 nsRuleNode* aHighestNode,
4597 const RuleDetail aRuleDetail,
4598 const bool aCanStoreInRuleTree)
4600 COMPUTE_START_RESET(UIReset, (), ui, parentUI)
4602 // user-select: enum, inherit, initial
4603 SetDiscrete(*aRuleData->ValueForUserSelect(),
4604 ui->mUserSelect, canStoreInRuleTree,
4605 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
4606 parentUI->mUserSelect,
4607 NS_STYLE_USER_SELECT_AUTO, 0, 0, 0, 0);
4609 // ime-mode: enum, inherit, initial
4610 SetDiscrete(*aRuleData->ValueForImeMode(),
4611 ui->mIMEMode, canStoreInRuleTree,
4612 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
4613 parentUI->mIMEMode,
4614 NS_STYLE_IME_MODE_AUTO, 0, 0, 0, 0);
4616 // force-broken-image-icons: integer, inherit, initial
4617 SetDiscrete(*aRuleData->ValueForForceBrokenImageIcon(),
4618 ui->mForceBrokenImageIcon,
4619 canStoreInRuleTree,
4620 SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
4621 parentUI->mForceBrokenImageIcon,
4622 0, 0, 0, 0, 0);
4624 // -moz-window-shadow: enum, inherit, initial
4625 SetDiscrete(*aRuleData->ValueForWindowShadow(),
4626 ui->mWindowShadow, canStoreInRuleTree,
4627 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
4628 parentUI->mWindowShadow,
4629 NS_STYLE_WINDOW_SHADOW_DEFAULT, 0, 0, 0, 0);
4631 COMPUTE_END_RESET(UIReset, ui)
4634 // Information about each transition or animation property that is
4635 // constant.
4636 struct TransitionPropInfo {
4637 nsCSSProperty property;
4638 // Location of the count of the property's computed value.
4639 uint32_t nsStyleDisplay::* sdCount;
4642 // Each property's index in this array must match its index in the
4643 // mutable array |transitionPropData| below.
4644 static const TransitionPropInfo transitionPropInfo[4] = {
4645 { eCSSProperty_transition_delay,
4646 &nsStyleDisplay::mTransitionDelayCount },
4647 { eCSSProperty_transition_duration,
4648 &nsStyleDisplay::mTransitionDurationCount },
4649 { eCSSProperty_transition_property,
4650 &nsStyleDisplay::mTransitionPropertyCount },
4651 { eCSSProperty_transition_timing_function,
4652 &nsStyleDisplay::mTransitionTimingFunctionCount },
4655 // Each property's index in this array must match its index in the
4656 // mutable array |animationPropData| below.
4657 static const TransitionPropInfo animationPropInfo[8] = {
4658 { eCSSProperty_animation_delay,
4659 &nsStyleDisplay::mAnimationDelayCount },
4660 { eCSSProperty_animation_duration,
4661 &nsStyleDisplay::mAnimationDurationCount },
4662 { eCSSProperty_animation_name,
4663 &nsStyleDisplay::mAnimationNameCount },
4664 { eCSSProperty_animation_timing_function,
4665 &nsStyleDisplay::mAnimationTimingFunctionCount },
4666 { eCSSProperty_animation_direction,
4667 &nsStyleDisplay::mAnimationDirectionCount },
4668 { eCSSProperty_animation_fill_mode,
4669 &nsStyleDisplay::mAnimationFillModeCount },
4670 { eCSSProperty_animation_play_state,
4671 &nsStyleDisplay::mAnimationPlayStateCount },
4672 { eCSSProperty_animation_iteration_count,
4673 &nsStyleDisplay::mAnimationIterationCountCount },
4676 // Information about each transition or animation property that changes
4677 // during ComputeDisplayData.
4678 struct TransitionPropData {
4679 const nsCSSValueList *list;
4680 nsCSSUnit unit;
4681 uint32_t num;
4684 static uint32_t
4685 CountTransitionProps(const TransitionPropInfo* aInfo,
4686 TransitionPropData* aData,
4687 size_t aLength,
4688 nsStyleDisplay* aDisplay,
4689 const nsStyleDisplay* aParentDisplay,
4690 const nsRuleData* aRuleData,
4691 bool& aCanStoreInRuleTree)
4693 // The four transition properties or eight animation properties are
4694 // stored in nsCSSDisplay in a single array for all properties. The
4695 // number of transitions is equal to the number of items in the
4696 // longest property's value. Properties that have fewer values than
4697 // the longest are filled in by repeating the list. However, this
4698 // repetition does not extend the computed value of that particular
4699 // property (for purposes of inheritance, or, in our code, for when
4700 // other properties are overridden by a more specific rule).
4702 // But actually, since the spec isn't clear yet, we'll fully compute
4703 // all of them (so we can switch easily later), but only care about
4704 // the ones up to the number of items for 'transition-property', per
4705 // http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html .
4707 // Transitions are difficult to handle correctly because of this. For
4708 // example, we need to handle scenarios such as:
4709 // * a more general rule specifies transition-property: a, b, c;
4710 // * a more specific rule overrides as transition-property: d;
4712 // If only the general rule applied, we would fill in the extra
4713 // properties (duration, delay, etc) with initial values to create 3
4714 // fully-specified transitions. But when the more specific rule
4715 // applies, we should only create a single transition. In order to do
4716 // this we need to remember which properties were explicitly specified
4717 // and which ones were just filled in with initial values to get a
4718 // fully-specified transition, which we do by remembering the number
4719 // of values for each property.
4721 uint32_t numTransitions = 0;
4722 for (size_t i = 0; i < aLength; ++i) {
4723 const TransitionPropInfo& info = aInfo[i];
4724 TransitionPropData& data = aData[i];
4726 // cache whether any of the properties are specified as 'inherit' so
4727 // we can use it below
4729 const nsCSSValue& value = *aRuleData->ValueFor(info.property);
4730 data.unit = value.GetUnit();
4731 data.list = (value.GetUnit() == eCSSUnit_List ||
4732 value.GetUnit() == eCSSUnit_ListDep)
4733 ? value.GetListValue() : nullptr;
4735 // General algorithm to determine how many total transitions we need
4736 // to build. For each property:
4737 // - if there is no value specified in for the property in
4738 // displayData, use the values from the start struct, but only if
4739 // they were explicitly specified
4740 // - if there is a value specified for the property in displayData:
4741 // - if the value is 'inherit', count the number of values for
4742 // that property are specified by the parent, but only those
4743 // that were explicitly specified
4744 // - otherwise, count the number of values specified in displayData
4747 // calculate number of elements
4748 if (data.unit == eCSSUnit_Inherit) {
4749 data.num = aParentDisplay->*(info.sdCount);
4750 aCanStoreInRuleTree = false;
4751 } else if (data.list) {
4752 data.num = ListLength(data.list);
4753 } else {
4754 data.num = aDisplay->*(info.sdCount);
4756 if (data.num > numTransitions)
4757 numTransitions = data.num;
4760 return numTransitions;
4763 static void
4764 ComputeTimingFunction(const nsCSSValue& aValue, nsTimingFunction& aResult)
4766 switch (aValue.GetUnit()) {
4767 case eCSSUnit_Enumerated:
4768 aResult = nsTimingFunction(aValue.GetIntValue());
4769 break;
4770 case eCSSUnit_Cubic_Bezier:
4772 nsCSSValue::Array* array = aValue.GetArrayValue();
4773 NS_ASSERTION(array && array->Count() == 4,
4774 "Need 4 control points");
4775 aResult = nsTimingFunction(array->Item(0).GetFloatValue(),
4776 array->Item(1).GetFloatValue(),
4777 array->Item(2).GetFloatValue(),
4778 array->Item(3).GetFloatValue());
4780 break;
4781 case eCSSUnit_Steps:
4783 nsCSSValue::Array* array = aValue.GetArrayValue();
4784 NS_ASSERTION(array && array->Count() == 2,
4785 "Need 2 items");
4786 NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
4787 "unexpected first value");
4788 NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
4789 (array->Item(1).GetIntValue() ==
4790 NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START ||
4791 array->Item(1).GetIntValue() ==
4792 NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END),
4793 "unexpected second value");
4794 nsTimingFunction::Type type =
4795 (array->Item(1).GetIntValue() ==
4796 NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END)
4797 ? nsTimingFunction::StepEnd : nsTimingFunction::StepStart;
4798 aResult = nsTimingFunction(type, array->Item(0).GetIntValue());
4800 break;
4801 default:
4802 NS_NOTREACHED("Invalid transition property unit");
4806 const void*
4807 nsRuleNode::ComputeDisplayData(void* aStartStruct,
4808 const nsRuleData* aRuleData,
4809 nsStyleContext* aContext,
4810 nsRuleNode* aHighestNode,
4811 const RuleDetail aRuleDetail,
4812 const bool aCanStoreInRuleTree)
4814 COMPUTE_START_RESET(Display, (), display, parentDisplay)
4816 // We may have ended up with aStartStruct's values of mDisplay and
4817 // mFloats, but those may not be correct if our style data overrides
4818 // its position or float properties. Reset to mOriginalDisplay and
4819 // mOriginalFloats; it if turns out we still need the display/floats
4820 // adjustments we'll do them below.
4821 display->mDisplay = display->mOriginalDisplay;
4822 display->mFloats = display->mOriginalFloats;
4824 // Each property's index in this array must match its index in the
4825 // const array |transitionPropInfo| above.
4826 TransitionPropData transitionPropData[4];
4827 TransitionPropData& delay = transitionPropData[0];
4828 TransitionPropData& duration = transitionPropData[1];
4829 TransitionPropData& property = transitionPropData[2];
4830 TransitionPropData& timingFunction = transitionPropData[3];
4832 #define FOR_ALL_TRANSITION_PROPS(var_) \
4833 for (uint32_t var_ = 0; var_ < 4; ++var_)
4835 // CSS Transitions
4836 uint32_t numTransitions =
4837 CountTransitionProps(transitionPropInfo, transitionPropData,
4838 ArrayLength(transitionPropData),
4839 display, parentDisplay, aRuleData,
4840 canStoreInRuleTree);
4842 display->mTransitions.SetLength(numTransitions);
4844 FOR_ALL_TRANSITION_PROPS(p) {
4845 const TransitionPropInfo& i = transitionPropInfo[p];
4846 TransitionPropData& d = transitionPropData[p];
4848 display->*(i.sdCount) = d.num;
4851 // Fill in the transitions we just allocated with the appropriate values.
4852 for (uint32_t i = 0; i < numTransitions; ++i) {
4853 StyleTransition *transition = &display->mTransitions[i];
4855 if (i >= delay.num) {
4856 transition->SetDelay(display->mTransitions[i % delay.num].GetDelay());
4857 } else if (delay.unit == eCSSUnit_Inherit) {
4858 // FIXME (Bug 522599) (for all transition properties): write a test that
4859 // detects when this was wrong for i >= delay.num if parent had
4860 // count for this property not equal to length
4861 NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionDelayCount,
4862 "delay.num computed incorrectly");
4863 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4864 "should have made canStoreInRuleTree false above");
4865 transition->SetDelay(parentDisplay->mTransitions[i].GetDelay());
4866 } else if (delay.unit == eCSSUnit_Initial ||
4867 delay.unit == eCSSUnit_Unset) {
4868 transition->SetDelay(0.0);
4869 } else if (delay.list) {
4870 switch (delay.list->mValue.GetUnit()) {
4871 case eCSSUnit_Seconds:
4872 transition->SetDelay(PR_MSEC_PER_SEC *
4873 delay.list->mValue.GetFloatValue());
4874 break;
4875 case eCSSUnit_Milliseconds:
4876 transition->SetDelay(delay.list->mValue.GetFloatValue());
4877 break;
4878 default:
4879 NS_NOTREACHED("Invalid delay unit");
4883 if (i >= duration.num) {
4884 transition->SetDuration(
4885 display->mTransitions[i % duration.num].GetDuration());
4886 } else if (duration.unit == eCSSUnit_Inherit) {
4887 NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionDurationCount,
4888 "duration.num computed incorrectly");
4889 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4890 "should have made canStoreInRuleTree false above");
4891 transition->SetDuration(parentDisplay->mTransitions[i].GetDuration());
4892 } else if (duration.unit == eCSSUnit_Initial ||
4893 duration.unit == eCSSUnit_Unset) {
4894 transition->SetDuration(0.0);
4895 } else if (duration.list) {
4896 switch (duration.list->mValue.GetUnit()) {
4897 case eCSSUnit_Seconds:
4898 transition->SetDuration(PR_MSEC_PER_SEC *
4899 duration.list->mValue.GetFloatValue());
4900 break;
4901 case eCSSUnit_Milliseconds:
4902 transition->SetDuration(duration.list->mValue.GetFloatValue());
4903 break;
4904 default:
4905 NS_NOTREACHED("Invalid duration unit");
4909 if (i >= property.num) {
4910 transition->CopyPropertyFrom(display->mTransitions[i % property.num]);
4911 } else if (property.unit == eCSSUnit_Inherit) {
4912 NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionPropertyCount,
4913 "property.num computed incorrectly");
4914 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4915 "should have made canStoreInRuleTree false above");
4916 transition->CopyPropertyFrom(parentDisplay->mTransitions[i]);
4917 } else if (property.unit == eCSSUnit_Initial ||
4918 property.unit == eCSSUnit_Unset) {
4919 transition->SetProperty(eCSSPropertyExtra_all_properties);
4920 } else if (property.unit == eCSSUnit_None) {
4921 transition->SetProperty(eCSSPropertyExtra_no_properties);
4922 } else if (property.list) {
4923 const nsCSSValue &val = property.list->mValue;
4925 if (val.GetUnit() == eCSSUnit_Ident) {
4926 nsDependentString
4927 propertyStr(property.list->mValue.GetStringBufferValue());
4928 nsCSSProperty prop =
4929 nsCSSProps::LookupProperty(propertyStr,
4930 nsCSSProps::eEnabledForAllContent);
4931 if (prop == eCSSProperty_UNKNOWN) {
4932 transition->SetUnknownProperty(propertyStr);
4933 } else {
4934 transition->SetProperty(prop);
4936 } else {
4937 NS_ABORT_IF_FALSE(val.GetUnit() == eCSSUnit_All,
4938 nsPrintfCString("Invalid transition property unit %d",
4939 val.GetUnit()).get());
4940 transition->SetProperty(eCSSPropertyExtra_all_properties);
4944 if (i >= timingFunction.num) {
4945 transition->SetTimingFunction(
4946 display->mTransitions[i % timingFunction.num].GetTimingFunction());
4947 } else if (timingFunction.unit == eCSSUnit_Inherit) {
4948 NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionTimingFunctionCount,
4949 "timingFunction.num computed incorrectly");
4950 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4951 "should have made canStoreInRuleTree false above");
4952 transition->SetTimingFunction(
4953 parentDisplay->mTransitions[i].GetTimingFunction());
4954 } else if (timingFunction.unit == eCSSUnit_Initial ||
4955 timingFunction.unit == eCSSUnit_Unset) {
4956 transition->SetTimingFunction(
4957 nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
4958 } else if (timingFunction.list) {
4959 ComputeTimingFunction(timingFunction.list->mValue,
4960 transition->TimingFunctionSlot());
4963 FOR_ALL_TRANSITION_PROPS(p) {
4964 const TransitionPropInfo& info = transitionPropInfo[p];
4965 TransitionPropData& d = transitionPropData[p];
4967 // if we're at the end of the list, start at the beginning and repeat
4968 // until we're out of transitions to populate
4969 if (d.list) {
4970 d.list = d.list->mNext ? d.list->mNext :
4971 aRuleData->ValueFor(info.property)->GetListValue();
4976 // Each property's index in this array must match its index in the
4977 // const array |animationPropInfo| above.
4978 TransitionPropData animationPropData[8];
4979 TransitionPropData& animDelay = animationPropData[0];
4980 TransitionPropData& animDuration = animationPropData[1];
4981 TransitionPropData& animName = animationPropData[2];
4982 TransitionPropData& animTimingFunction = animationPropData[3];
4983 TransitionPropData& animDirection = animationPropData[4];
4984 TransitionPropData& animFillMode = animationPropData[5];
4985 TransitionPropData& animPlayState = animationPropData[6];
4986 TransitionPropData& animIterationCount = animationPropData[7];
4988 #define FOR_ALL_ANIMATION_PROPS(var_) \
4989 for (uint32_t var_ = 0; var_ < 8; ++var_)
4991 // CSS Animations.
4993 uint32_t numAnimations =
4994 CountTransitionProps(animationPropInfo, animationPropData,
4995 ArrayLength(animationPropData),
4996 display, parentDisplay, aRuleData,
4997 canStoreInRuleTree);
4999 display->mAnimations.SetLength(numAnimations);
5001 FOR_ALL_ANIMATION_PROPS(p) {
5002 const TransitionPropInfo& i = animationPropInfo[p];
5003 TransitionPropData& d = animationPropData[p];
5005 display->*(i.sdCount) = d.num;
5008 // Fill in the animations we just allocated with the appropriate values.
5009 for (uint32_t i = 0; i < numAnimations; ++i) {
5010 StyleAnimation *animation = &display->mAnimations[i];
5012 if (i >= animDelay.num) {
5013 animation->SetDelay(display->mAnimations[i % animDelay.num].GetDelay());
5014 } else if (animDelay.unit == eCSSUnit_Inherit) {
5015 // FIXME (Bug 522599) (for all animation properties): write a test that
5016 // detects when this was wrong for i >= animDelay.num if parent had
5017 // count for this property not equal to length
5018 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDelayCount,
5019 "animDelay.num computed incorrectly");
5020 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
5021 "should have made canStoreInRuleTree false above");
5022 animation->SetDelay(parentDisplay->mAnimations[i].GetDelay());
5023 } else if (animDelay.unit == eCSSUnit_Initial ||
5024 animDelay.unit == eCSSUnit_Unset) {
5025 animation->SetDelay(0.0);
5026 } else if (animDelay.list) {
5027 switch (animDelay.list->mValue.GetUnit()) {
5028 case eCSSUnit_Seconds:
5029 animation->SetDelay(PR_MSEC_PER_SEC *
5030 animDelay.list->mValue.GetFloatValue());
5031 break;
5032 case eCSSUnit_Milliseconds:
5033 animation->SetDelay(animDelay.list->mValue.GetFloatValue());
5034 break;
5035 default:
5036 NS_NOTREACHED("Invalid delay unit");
5040 if (i >= animDuration.num) {
5041 animation->SetDuration(
5042 display->mAnimations[i % animDuration.num].GetDuration());
5043 } else if (animDuration.unit == eCSSUnit_Inherit) {
5044 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDurationCount,
5045 "animDuration.num computed incorrectly");
5046 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
5047 "should have made canStoreInRuleTree false above");
5048 animation->SetDuration(parentDisplay->mAnimations[i].GetDuration());
5049 } else if (animDuration.unit == eCSSUnit_Initial ||
5050 animDuration.unit == eCSSUnit_Unset) {
5051 animation->SetDuration(0.0);
5052 } else if (animDuration.list) {
5053 switch (animDuration.list->mValue.GetUnit()) {
5054 case eCSSUnit_Seconds:
5055 animation->SetDuration(PR_MSEC_PER_SEC *
5056 animDuration.list->mValue.GetFloatValue());
5057 break;
5058 case eCSSUnit_Milliseconds:
5059 animation->SetDuration(animDuration.list->mValue.GetFloatValue());
5060 break;
5061 default:
5062 NS_NOTREACHED("Invalid duration unit");
5066 if (i >= animName.num) {
5067 animation->SetName(display->mAnimations[i % animName.num].GetName());
5068 } else if (animName.unit == eCSSUnit_Inherit) {
5069 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationNameCount,
5070 "animName.num computed incorrectly");
5071 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
5072 "should have made canStoreInRuleTree false above");
5073 animation->SetName(parentDisplay->mAnimations[i].GetName());
5074 } else if (animName.unit == eCSSUnit_Initial ||
5075 animName.unit == eCSSUnit_Unset) {
5076 animation->SetName(EmptyString());
5077 } else if (animName.list) {
5078 switch (animName.list->mValue.GetUnit()) {
5079 case eCSSUnit_Ident: {
5080 nsDependentString
5081 nameStr(animName.list->mValue.GetStringBufferValue());
5082 animation->SetName(nameStr);
5083 break;
5085 case eCSSUnit_None: {
5086 animation->SetName(EmptyString());
5087 break;
5089 default:
5090 NS_ABORT_IF_FALSE(false,
5091 nsPrintfCString("Invalid animation-name unit %d",
5092 animName.list->mValue.GetUnit()).get());
5096 if (i >= animTimingFunction.num) {
5097 animation->SetTimingFunction(
5098 display->mAnimations[i % animTimingFunction.num].GetTimingFunction());
5099 } else if (animTimingFunction.unit == eCSSUnit_Inherit) {
5100 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationTimingFunctionCount,
5101 "animTimingFunction.num computed incorrectly");
5102 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
5103 "should have made canStoreInRuleTree false above");
5104 animation->SetTimingFunction(
5105 parentDisplay->mAnimations[i].GetTimingFunction());
5106 } else if (animTimingFunction.unit == eCSSUnit_Initial ||
5107 animTimingFunction.unit == eCSSUnit_Unset) {
5108 animation->SetTimingFunction(
5109 nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
5110 } else if (animTimingFunction.list) {
5111 ComputeTimingFunction(animTimingFunction.list->mValue,
5112 animation->TimingFunctionSlot());
5115 if (i >= animDirection.num) {
5116 animation->SetDirection(display->mAnimations[i % animDirection.num].GetDirection());
5117 } else if (animDirection.unit == eCSSUnit_Inherit) {
5118 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDirectionCount,
5119 "animDirection.num computed incorrectly");
5120 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
5121 "should have made canStoreInRuleTree false above");
5122 animation->SetDirection(parentDisplay->mAnimations[i].GetDirection());
5123 } else if (animDirection.unit == eCSSUnit_Initial ||
5124 animDirection.unit == eCSSUnit_Unset) {
5125 animation->SetDirection(NS_STYLE_ANIMATION_DIRECTION_NORMAL);
5126 } else if (animDirection.list) {
5127 NS_ABORT_IF_FALSE(animDirection.list->mValue.GetUnit() == eCSSUnit_Enumerated,
5128 nsPrintfCString("Invalid animation-direction unit %d",
5129 animDirection.list->mValue.GetUnit()).get());
5131 animation->SetDirection(animDirection.list->mValue.GetIntValue());
5134 if (i >= animFillMode.num) {
5135 animation->SetFillMode(display->mAnimations[i % animFillMode.num].GetFillMode());
5136 } else if (animFillMode.unit == eCSSUnit_Inherit) {
5137 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationFillModeCount,
5138 "animFillMode.num computed incorrectly");
5139 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
5140 "should have made canStoreInRuleTree false above");
5141 animation->SetFillMode(parentDisplay->mAnimations[i].GetFillMode());
5142 } else if (animFillMode.unit == eCSSUnit_Initial ||
5143 animFillMode.unit == eCSSUnit_Unset) {
5144 animation->SetFillMode(NS_STYLE_ANIMATION_FILL_MODE_NONE);
5145 } else if (animFillMode.list) {
5146 NS_ABORT_IF_FALSE(animFillMode.list->mValue.GetUnit() == eCSSUnit_Enumerated,
5147 nsPrintfCString("Invalid animation-fill-mode unit %d",
5148 animFillMode.list->mValue.GetUnit()).get());
5150 animation->SetFillMode(animFillMode.list->mValue.GetIntValue());
5153 if (i >= animPlayState.num) {
5154 animation->SetPlayState(display->mAnimations[i % animPlayState.num].GetPlayState());
5155 } else if (animPlayState.unit == eCSSUnit_Inherit) {
5156 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationPlayStateCount,
5157 "animPlayState.num computed incorrectly");
5158 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
5159 "should have made canStoreInRuleTree false above");
5160 animation->SetPlayState(parentDisplay->mAnimations[i].GetPlayState());
5161 } else if (animPlayState.unit == eCSSUnit_Initial ||
5162 animPlayState.unit == eCSSUnit_Unset) {
5163 animation->SetPlayState(NS_STYLE_ANIMATION_PLAY_STATE_RUNNING);
5164 } else if (animPlayState.list) {
5165 NS_ABORT_IF_FALSE(animPlayState.list->mValue.GetUnit() == eCSSUnit_Enumerated,
5166 nsPrintfCString("Invalid animation-play-state unit %d",
5167 animPlayState.list->mValue.GetUnit()).get());
5169 animation->SetPlayState(animPlayState.list->mValue.GetIntValue());
5172 if (i >= animIterationCount.num) {
5173 animation->SetIterationCount(display->mAnimations[i % animIterationCount.num].GetIterationCount());
5174 } else if (animIterationCount.unit == eCSSUnit_Inherit) {
5175 NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationIterationCountCount,
5176 "animIterationCount.num computed incorrectly");
5177 NS_ABORT_IF_FALSE(!canStoreInRuleTree,
5178 "should have made canStoreInRuleTree false above");
5179 animation->SetIterationCount(parentDisplay->mAnimations[i].GetIterationCount());
5180 } else if (animIterationCount.unit == eCSSUnit_Initial ||
5181 animIterationCount.unit == eCSSUnit_Unset) {
5182 animation->SetIterationCount(1.0f);
5183 } else if (animIterationCount.list) {
5184 switch (animIterationCount.list->mValue.GetUnit()) {
5185 case eCSSUnit_Enumerated:
5186 NS_ABORT_IF_FALSE(animIterationCount.list->mValue.GetIntValue() ==
5187 NS_STYLE_ANIMATION_ITERATION_COUNT_INFINITE,
5188 "unexpected value");
5189 animation->SetIterationCount(NS_IEEEPositiveInfinity());
5190 break;
5191 case eCSSUnit_Number:
5192 animation->SetIterationCount(
5193 animIterationCount.list->mValue.GetFloatValue());
5194 break;
5195 default:
5196 NS_ABORT_IF_FALSE(false,
5197 "unexpected animation-iteration-count unit");
5201 FOR_ALL_ANIMATION_PROPS(p) {
5202 const TransitionPropInfo& info = animationPropInfo[p];
5203 TransitionPropData& d = animationPropData[p];
5205 // if we're at the end of the list, start at the beginning and repeat
5206 // until we're out of animations to populate
5207 if (d.list) {
5208 d.list = d.list->mNext ? d.list->mNext :
5209 aRuleData->ValueFor(info.property)->GetListValue();
5214 // opacity: factor, inherit, initial
5215 SetFactor(*aRuleData->ValueForOpacity(), display->mOpacity, canStoreInRuleTree,
5216 parentDisplay->mOpacity, 1.0f,
5217 SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
5219 // display: enum, inherit, initial
5220 SetDiscrete(*aRuleData->ValueForDisplay(), display->mDisplay, canStoreInRuleTree,
5221 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5222 parentDisplay->mDisplay,
5223 NS_STYLE_DISPLAY_INLINE, 0, 0, 0, 0);
5225 // mix-blend-mode: enum, inherit, initial
5226 SetDiscrete(*aRuleData->ValueForMixBlendMode(), display->mMixBlendMode,
5227 canStoreInRuleTree,
5228 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5229 parentDisplay->mMixBlendMode, NS_STYLE_BLEND_NORMAL,
5230 0, 0, 0, 0);
5232 // Backup original display value for calculation of a hypothetical
5233 // box (CSS2 10.6.4/10.6.5), in addition to getting our style data right later.
5234 // See nsHTMLReflowState::CalculateHypotheticalBox
5235 display->mOriginalDisplay = display->mDisplay;
5237 // appearance: enum, inherit, initial
5238 SetDiscrete(*aRuleData->ValueForAppearance(),
5239 display->mAppearance, canStoreInRuleTree,
5240 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5241 parentDisplay->mAppearance,
5242 NS_THEME_NONE, 0, 0, 0, 0);
5244 // binding: url, none, inherit
5245 const nsCSSValue* bindingValue = aRuleData->ValueForBinding();
5246 if (eCSSUnit_URL == bindingValue->GetUnit()) {
5247 mozilla::css::URLValue* url = bindingValue->GetURLStructValue();
5248 NS_ASSERTION(url, "What's going on here?");
5250 if (MOZ_LIKELY(url->GetURI())) {
5251 display->mBinding = url;
5252 } else {
5253 display->mBinding = nullptr;
5256 else if (eCSSUnit_None == bindingValue->GetUnit() ||
5257 eCSSUnit_Initial == bindingValue->GetUnit() ||
5258 eCSSUnit_Unset == bindingValue->GetUnit()) {
5259 display->mBinding = nullptr;
5261 else if (eCSSUnit_Inherit == bindingValue->GetUnit()) {
5262 canStoreInRuleTree = false;
5263 display->mBinding = parentDisplay->mBinding;
5266 // position: enum, inherit, initial
5267 SetDiscrete(*aRuleData->ValueForPosition(), display->mPosition, canStoreInRuleTree,
5268 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5269 parentDisplay->mPosition,
5270 NS_STYLE_POSITION_STATIC, 0, 0, 0, 0);
5272 // clear: enum, inherit, initial
5273 SetDiscrete(*aRuleData->ValueForClear(), display->mBreakType, canStoreInRuleTree,
5274 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5275 parentDisplay->mBreakType,
5276 NS_STYLE_CLEAR_NONE, 0, 0, 0, 0);
5278 // temp fix for bug 24000
5279 // Map 'auto' and 'avoid' to false, and 'always', 'left', and
5280 // 'right' to true.
5281 // "A conforming user agent may interpret the values 'left' and
5282 // 'right' as 'always'." - CSS2.1, section 13.3.1
5283 const nsCSSValue* breakBeforeValue = aRuleData->ValueForPageBreakBefore();
5284 if (eCSSUnit_Enumerated == breakBeforeValue->GetUnit()) {
5285 display->mBreakBefore =
5286 (NS_STYLE_PAGE_BREAK_AVOID != breakBeforeValue->GetIntValue() &&
5287 NS_STYLE_PAGE_BREAK_AUTO != breakBeforeValue->GetIntValue());
5289 else if (eCSSUnit_Initial == breakBeforeValue->GetUnit() ||
5290 eCSSUnit_Unset == breakBeforeValue->GetUnit()) {
5291 display->mBreakBefore = false;
5293 else if (eCSSUnit_Inherit == breakBeforeValue->GetUnit()) {
5294 canStoreInRuleTree = false;
5295 display->mBreakBefore = parentDisplay->mBreakBefore;
5298 const nsCSSValue* breakAfterValue = aRuleData->ValueForPageBreakAfter();
5299 if (eCSSUnit_Enumerated == breakAfterValue->GetUnit()) {
5300 display->mBreakAfter =
5301 (NS_STYLE_PAGE_BREAK_AVOID != breakAfterValue->GetIntValue() &&
5302 NS_STYLE_PAGE_BREAK_AUTO != breakAfterValue->GetIntValue());
5304 else if (eCSSUnit_Initial == breakAfterValue->GetUnit() ||
5305 eCSSUnit_Unset == breakAfterValue->GetUnit()) {
5306 display->mBreakAfter = false;
5308 else if (eCSSUnit_Inherit == breakAfterValue->GetUnit()) {
5309 canStoreInRuleTree = false;
5310 display->mBreakAfter = parentDisplay->mBreakAfter;
5312 // end temp fix
5314 // page-break-inside: enum, inherit, initial
5315 SetDiscrete(*aRuleData->ValueForPageBreakInside(),
5316 display->mBreakInside, canStoreInRuleTree,
5317 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5318 parentDisplay->mBreakInside,
5319 NS_STYLE_PAGE_BREAK_AUTO, 0, 0, 0, 0);
5321 // touch-action: none, auto, enum, inherit, initial
5322 SetDiscrete(*aRuleData->ValueForTouchAction(), display->mTouchAction,
5323 canStoreInRuleTree,
5324 SETDSC_ENUMERATED | SETDSC_AUTO | SETDSC_NONE |
5325 SETDSC_UNSET_INITIAL,
5326 parentDisplay->mTouchAction,
5327 NS_STYLE_TOUCH_ACTION_AUTO,
5328 NS_STYLE_TOUCH_ACTION_AUTO,
5329 NS_STYLE_TOUCH_ACTION_NONE, 0, 0);
5331 // float: enum, inherit, initial
5332 SetDiscrete(*aRuleData->ValueForFloat(),
5333 display->mFloats, canStoreInRuleTree,
5334 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5335 parentDisplay->mFloats,
5336 NS_STYLE_FLOAT_NONE, 0, 0, 0, 0);
5337 // Save mFloats in mOriginalFloats in case we need it later
5338 display->mOriginalFloats = display->mFloats;
5340 // overflow-x: enum, inherit, initial
5341 SetDiscrete(*aRuleData->ValueForOverflowX(),
5342 display->mOverflowX, canStoreInRuleTree,
5343 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5344 parentDisplay->mOverflowX,
5345 NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
5347 // overflow-y: enum, inherit, initial
5348 SetDiscrete(*aRuleData->ValueForOverflowY(),
5349 display->mOverflowY, canStoreInRuleTree,
5350 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5351 parentDisplay->mOverflowY,
5352 NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
5354 // CSS3 overflow-x and overflow-y require some fixup as well in some
5355 // cases. NS_STYLE_OVERFLOW_VISIBLE and NS_STYLE_OVERFLOW_CLIP are
5356 // meaningful only when used in both dimensions.
5357 if (display->mOverflowX != display->mOverflowY &&
5358 (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE ||
5359 display->mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
5360 display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE ||
5361 display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)) {
5362 // We can't store in the rule tree since a more specific rule might
5363 // change these conditions.
5364 canStoreInRuleTree = false;
5366 // NS_STYLE_OVERFLOW_CLIP is a deprecated value, so if it's specified
5367 // in only one dimension, convert it to NS_STYLE_OVERFLOW_HIDDEN.
5368 if (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
5369 display->mOverflowX = NS_STYLE_OVERFLOW_HIDDEN;
5370 if (display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)
5371 display->mOverflowY = NS_STYLE_OVERFLOW_HIDDEN;
5373 // If 'visible' is specified but doesn't match the other dimension, it
5374 // turns into 'auto'.
5375 if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
5376 display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
5377 if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
5378 display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
5381 SetDiscrete(*aRuleData->ValueForOverflowClipBox(), display->mOverflowClipBox,
5382 canStoreInRuleTree,
5383 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5384 parentDisplay->mOverflowClipBox,
5385 NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX, 0, 0, 0, 0);
5387 SetDiscrete(*aRuleData->ValueForResize(), display->mResize, canStoreInRuleTree,
5388 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5389 parentDisplay->mResize,
5390 NS_STYLE_RESIZE_NONE, 0, 0, 0, 0);
5392 // clip property: length, auto, inherit
5393 const nsCSSValue* clipValue = aRuleData->ValueForClip();
5394 switch (clipValue->GetUnit()) {
5395 case eCSSUnit_Inherit:
5396 canStoreInRuleTree = false;
5397 display->mClipFlags = parentDisplay->mClipFlags;
5398 display->mClip = parentDisplay->mClip;
5399 break;
5401 case eCSSUnit_Initial:
5402 case eCSSUnit_Unset:
5403 case eCSSUnit_Auto:
5404 display->mClipFlags = NS_STYLE_CLIP_AUTO;
5405 display->mClip.SetRect(0,0,0,0);
5406 break;
5408 case eCSSUnit_Null:
5409 break;
5411 case eCSSUnit_Rect: {
5412 const nsCSSRect& clipRect = clipValue->GetRectValue();
5414 display->mClipFlags = NS_STYLE_CLIP_RECT;
5416 if (clipRect.mTop.GetUnit() == eCSSUnit_Auto) {
5417 display->mClip.y = 0;
5418 display->mClipFlags |= NS_STYLE_CLIP_TOP_AUTO;
5420 else if (clipRect.mTop.IsLengthUnit()) {
5421 display->mClip.y = CalcLength(clipRect.mTop, aContext,
5422 mPresContext, canStoreInRuleTree);
5425 if (clipRect.mBottom.GetUnit() == eCSSUnit_Auto) {
5426 // Setting to NS_MAXSIZE for the 'auto' case ensures that
5427 // the clip rect is nonempty. It is important that mClip be
5428 // nonempty if the actual clip rect could be nonempty.
5429 display->mClip.height = NS_MAXSIZE;
5430 display->mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO;
5432 else if (clipRect.mBottom.IsLengthUnit()) {
5433 display->mClip.height = CalcLength(clipRect.mBottom, aContext,
5434 mPresContext, canStoreInRuleTree) -
5435 display->mClip.y;
5438 if (clipRect.mLeft.GetUnit() == eCSSUnit_Auto) {
5439 display->mClip.x = 0;
5440 display->mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO;
5442 else if (clipRect.mLeft.IsLengthUnit()) {
5443 display->mClip.x = CalcLength(clipRect.mLeft, aContext,
5444 mPresContext, canStoreInRuleTree);
5447 if (clipRect.mRight.GetUnit() == eCSSUnit_Auto) {
5448 // Setting to NS_MAXSIZE for the 'auto' case ensures that
5449 // the clip rect is nonempty. It is important that mClip be
5450 // nonempty if the actual clip rect could be nonempty.
5451 display->mClip.width = NS_MAXSIZE;
5452 display->mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO;
5454 else if (clipRect.mRight.IsLengthUnit()) {
5455 display->mClip.width = CalcLength(clipRect.mRight, aContext,
5456 mPresContext, canStoreInRuleTree) -
5457 display->mClip.x;
5459 break;
5462 default:
5463 NS_ABORT_IF_FALSE(false, "unrecognized clip unit");
5466 if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
5467 // CSS2 9.7 specifies display type corrections dealing with 'float'
5468 // and 'position'. Since generated content can't be floated or
5469 // positioned, we can deal with it here.
5471 if (nsCSSPseudoElements::firstLetter == aContext->GetPseudo()) {
5472 // a non-floating first-letter must be inline
5473 // XXX this fix can go away once bug 103189 is fixed correctly
5474 // Note that we reset mOriginalDisplay to enforce the invariant that it equals mDisplay if we're not positioned or floating.
5475 display->mOriginalDisplay = display->mDisplay = NS_STYLE_DISPLAY_INLINE;
5477 // We can't cache the data in the rule tree since if a more specific
5478 // rule has 'float: left' we'll end up with the wrong 'display'
5479 // property.
5480 canStoreInRuleTree = false;
5483 if (display->IsAbsolutelyPositionedStyle()) {
5484 // 1) if position is 'absolute' or 'fixed' then display must be
5485 // block-level and float must be 'none'
5486 EnsureBlockDisplay(display->mDisplay);
5487 display->mFloats = NS_STYLE_FLOAT_NONE;
5489 // Note that it's OK to cache this struct in the ruletree
5490 // because it's fine as-is for any style context that points to
5491 // it directly, and any use of it as aStartStruct (e.g. if a
5492 // more specific rule sets "position: static") will use
5493 // mOriginalDisplay and mOriginalFloats, which we have carefully
5494 // not changed.
5495 } else if (display->mFloats != NS_STYLE_FLOAT_NONE) {
5496 // 2) if float is not none, and display is not none, then we must
5497 // set a block-level 'display' type per CSS2.1 section 9.7.
5498 EnsureBlockDisplay(display->mDisplay);
5500 // Note that it's OK to cache this struct in the ruletree
5501 // because it's fine as-is for any style context that points to
5502 // it directly, and any use of it as aStartStruct (e.g. if a
5503 // more specific rule sets "float: none") will use
5504 // mOriginalDisplay, which we have carefully not changed.
5509 /* Convert the nsCSSValueList into an nsTArray<nsTransformFunction *>. */
5510 const nsCSSValue* transformValue = aRuleData->ValueForTransform();
5511 switch (transformValue->GetUnit()) {
5512 case eCSSUnit_Null:
5513 break;
5515 case eCSSUnit_Initial:
5516 case eCSSUnit_Unset:
5517 case eCSSUnit_None:
5518 display->mSpecifiedTransform = nullptr;
5519 break;
5521 case eCSSUnit_Inherit:
5522 display->mSpecifiedTransform = parentDisplay->mSpecifiedTransform;
5523 canStoreInRuleTree = false;
5524 break;
5526 case eCSSUnit_SharedList: {
5527 nsCSSValueSharedList* list = transformValue->GetSharedListValue();
5528 nsCSSValueList* head = list->mHead;
5529 MOZ_ASSERT(head, "transform list must have at least one item");
5530 // can get a _None in here from transform animation
5531 if (head->mValue.GetUnit() == eCSSUnit_None) {
5532 NS_ABORT_IF_FALSE(head->mNext == nullptr, "none must be alone");
5533 display->mSpecifiedTransform = nullptr;
5534 } else {
5535 display->mSpecifiedTransform = list;
5537 break;
5540 default:
5541 NS_ABORT_IF_FALSE(false, "unrecognized transform unit");
5544 /* Convert the nsCSSValueList into a will-change bitfield for fast lookup */
5545 const nsCSSValue* willChangeValue = aRuleData->ValueForWillChange();
5546 switch (willChangeValue->GetUnit()) {
5547 case eCSSUnit_Null:
5548 break;
5550 case eCSSUnit_List:
5551 case eCSSUnit_ListDep: {
5552 display->mWillChange.Clear();
5553 display->mWillChangeBitField = 0;
5554 for (const nsCSSValueList* item = willChangeValue->GetListValue();
5555 item; item = item->mNext)
5557 if (item->mValue.UnitHasStringValue()) {
5558 nsAutoString buffer;
5559 item->mValue.GetStringValue(buffer);
5560 display->mWillChange.AppendElement(buffer);
5562 if (buffer.EqualsLiteral("transform")) {
5563 display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_TRANSFORM;
5565 if (buffer.EqualsLiteral("opacity")) {
5566 display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_OPACITY;
5568 if (buffer.EqualsLiteral("scroll-position")) {
5569 display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_SCROLL;
5572 nsCSSProperty prop =
5573 nsCSSProps::LookupProperty(buffer,
5574 nsCSSProps::eEnabledForAllContent);
5575 if (prop != eCSSProperty_UNKNOWN &&
5576 nsCSSProps::PropHasFlags(prop,
5577 CSS_PROPERTY_CREATES_STACKING_CONTEXT))
5579 display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_STACKING_CONTEXT;
5583 break;
5586 case eCSSUnit_Inherit:
5587 display->mWillChange = parentDisplay->mWillChange;
5588 display->mWillChangeBitField = parentDisplay->mWillChangeBitField;
5589 canStoreInRuleTree = false;
5590 break;
5592 case eCSSUnit_Initial:
5593 case eCSSUnit_Unset:
5594 case eCSSUnit_Auto:
5595 display->mWillChange.Clear();
5596 display->mWillChangeBitField = 0;
5597 break;
5599 default:
5600 MOZ_ASSERT(false, "unrecognized will-change unit");
5603 /* Convert -moz-transform-origin. */
5604 const nsCSSValue* transformOriginValue =
5605 aRuleData->ValueForTransformOrigin();
5606 if (transformOriginValue->GetUnit() != eCSSUnit_Null) {
5607 const nsCSSValue& valX =
5608 transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
5609 transformOriginValue->GetTripletValue().mXValue : *transformOriginValue;
5610 const nsCSSValue& valY =
5611 transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
5612 transformOriginValue->GetTripletValue().mYValue : *transformOriginValue;
5613 const nsCSSValue& valZ =
5614 transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
5615 transformOriginValue->GetTripletValue().mZValue : *transformOriginValue;
5617 mozilla::DebugOnly<bool> cX =
5618 SetCoord(valX, display->mTransformOrigin[0],
5619 parentDisplay->mTransformOrigin[0],
5620 SETCOORD_LPH | SETCOORD_INITIAL_HALF |
5621 SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
5622 SETCOORD_UNSET_INITIAL,
5623 aContext, mPresContext, canStoreInRuleTree);
5625 mozilla::DebugOnly<bool> cY =
5626 SetCoord(valY, display->mTransformOrigin[1],
5627 parentDisplay->mTransformOrigin[1],
5628 SETCOORD_LPH | SETCOORD_INITIAL_HALF |
5629 SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
5630 SETCOORD_UNSET_INITIAL,
5631 aContext, mPresContext, canStoreInRuleTree);
5633 if (valZ.GetUnit() == eCSSUnit_Null) {
5634 // Null for the z component means a 0 translation, not
5635 // unspecified, as we have already checked the triplet
5636 // value for Null.
5637 display->mTransformOrigin[2].SetCoordValue(0);
5638 } else {
5639 mozilla::DebugOnly<bool> cZ =
5640 SetCoord(valZ, display->mTransformOrigin[2],
5641 parentDisplay->mTransformOrigin[2],
5642 SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
5643 SETCOORD_UNSET_INITIAL,
5644 aContext, mPresContext, canStoreInRuleTree);
5645 NS_ABORT_IF_FALSE(cY == cZ, "changed one but not the other");
5647 NS_ABORT_IF_FALSE(cX == cY, "changed one but not the other");
5648 NS_ASSERTION(cX, "Malformed -moz-transform-origin parse!");
5651 const nsCSSValue* perspectiveOriginValue =
5652 aRuleData->ValueForPerspectiveOrigin();
5653 if (perspectiveOriginValue->GetUnit() != eCSSUnit_Null) {
5654 mozilla::DebugOnly<bool> result =
5655 SetPairCoords(*perspectiveOriginValue,
5656 display->mPerspectiveOrigin[0],
5657 display->mPerspectiveOrigin[1],
5658 parentDisplay->mPerspectiveOrigin[0],
5659 parentDisplay->mPerspectiveOrigin[1],
5660 SETCOORD_LPH | SETCOORD_INITIAL_HALF |
5661 SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
5662 SETCOORD_UNSET_INITIAL,
5663 aContext, mPresContext, canStoreInRuleTree);
5664 NS_ASSERTION(result, "Malformed -moz-perspective-origin parse!");
5667 SetCoord(*aRuleData->ValueForPerspective(),
5668 display->mChildPerspective, parentDisplay->mChildPerspective,
5669 SETCOORD_LAH | SETCOORD_INITIAL_NONE | SETCOORD_NONE |
5670 SETCOORD_UNSET_INITIAL,
5671 aContext, mPresContext, canStoreInRuleTree);
5673 SetDiscrete(*aRuleData->ValueForBackfaceVisibility(),
5674 display->mBackfaceVisibility, canStoreInRuleTree,
5675 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5676 parentDisplay->mBackfaceVisibility,
5677 NS_STYLE_BACKFACE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
5679 // transform-style: enum, inherit, initial
5680 SetDiscrete(*aRuleData->ValueForTransformStyle(),
5681 display->mTransformStyle, canStoreInRuleTree,
5682 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5683 parentDisplay->mTransformStyle,
5684 NS_STYLE_TRANSFORM_STYLE_FLAT, 0, 0, 0, 0);
5686 // orient: enum, inherit, initial
5687 SetDiscrete(*aRuleData->ValueForOrient(),
5688 display->mOrient, canStoreInRuleTree,
5689 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
5690 parentDisplay->mOrient,
5691 NS_STYLE_ORIENT_AUTO, 0, 0, 0, 0);
5693 COMPUTE_END_RESET(Display, display)
5696 const void*
5697 nsRuleNode::ComputeVisibilityData(void* aStartStruct,
5698 const nsRuleData* aRuleData,
5699 nsStyleContext* aContext,
5700 nsRuleNode* aHighestNode,
5701 const RuleDetail aRuleDetail,
5702 const bool aCanStoreInRuleTree)
5704 COMPUTE_START_INHERITED(Visibility, (mPresContext),
5705 visibility, parentVisibility)
5707 // IMPORTANT: No properties in this struct have lengths in them. We
5708 // depend on this since CalcLengthWith can call StyleVisibility()
5709 // to get the language for resolving fonts!
5711 // direction: enum, inherit, initial
5712 SetDiscrete(*aRuleData->ValueForDirection(), visibility->mDirection,
5713 canStoreInRuleTree,
5714 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
5715 parentVisibility->mDirection,
5716 (GET_BIDI_OPTION_DIRECTION(mPresContext->GetBidi())
5717 == IBMBIDI_TEXTDIRECTION_RTL)
5718 ? NS_STYLE_DIRECTION_RTL : NS_STYLE_DIRECTION_LTR,
5719 0, 0, 0, 0);
5721 // visibility: enum, inherit, initial
5722 SetDiscrete(*aRuleData->ValueForVisibility(), visibility->mVisible,
5723 canStoreInRuleTree,
5724 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
5725 parentVisibility->mVisible,
5726 NS_STYLE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
5728 // pointer-events: enum, inherit, initial
5729 SetDiscrete(*aRuleData->ValueForPointerEvents(), visibility->mPointerEvents,
5730 canStoreInRuleTree,
5731 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
5732 parentVisibility->mPointerEvents,
5733 NS_STYLE_POINTER_EVENTS_AUTO, 0, 0, 0, 0);
5735 // writing-mode: enum, inherit, initial
5736 SetDiscrete(*aRuleData->ValueForWritingMode(), visibility->mWritingMode,
5737 canStoreInRuleTree,
5738 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
5739 parentVisibility->mWritingMode,
5740 NS_STYLE_WRITING_MODE_HORIZONTAL_TB, 0, 0, 0, 0);
5742 // image-orientation: enum, inherit, initial
5743 const nsCSSValue* orientation = aRuleData->ValueForImageOrientation();
5744 if (orientation->GetUnit() == eCSSUnit_Inherit ||
5745 orientation->GetUnit() == eCSSUnit_Unset) {
5746 canStoreInRuleTree = false;
5747 visibility->mImageOrientation = parentVisibility->mImageOrientation;
5748 } else if (orientation->GetUnit() == eCSSUnit_Initial) {
5749 visibility->mImageOrientation = nsStyleImageOrientation();
5750 } else if (orientation->IsAngularUnit()) {
5751 double angle = orientation->GetAngleValueInRadians();
5752 visibility->mImageOrientation =
5753 nsStyleImageOrientation::CreateAsAngleAndFlip(angle, false);
5754 } else if (orientation->GetUnit() == eCSSUnit_Array) {
5755 const nsCSSValue::Array* array = orientation->GetArrayValue();
5756 MOZ_ASSERT(array->Item(0).IsAngularUnit(),
5757 "First image-orientation value is not an angle");
5758 MOZ_ASSERT(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
5759 array->Item(1).GetIntValue() == NS_STYLE_IMAGE_ORIENTATION_FLIP,
5760 "Second image-orientation value is not 'flip'");
5761 double angle = array->Item(0).GetAngleValueInRadians();
5762 visibility->mImageOrientation =
5763 nsStyleImageOrientation::CreateAsAngleAndFlip(angle, true);
5765 } else if (orientation->GetUnit() == eCSSUnit_Enumerated) {
5766 switch (orientation->GetIntValue()) {
5767 case NS_STYLE_IMAGE_ORIENTATION_FLIP:
5768 visibility->mImageOrientation = nsStyleImageOrientation::CreateAsFlip();
5769 break;
5770 case NS_STYLE_IMAGE_ORIENTATION_FROM_IMAGE:
5771 visibility->mImageOrientation = nsStyleImageOrientation::CreateAsFromImage();
5772 break;
5773 default:
5774 NS_NOTREACHED("Invalid image-orientation enumerated value");
5776 } else {
5777 MOZ_ASSERT(orientation->GetUnit() == eCSSUnit_Null, "Should be null unit");
5780 COMPUTE_END_INHERITED(Visibility, visibility)
5783 const void*
5784 nsRuleNode::ComputeColorData(void* aStartStruct,
5785 const nsRuleData* aRuleData,
5786 nsStyleContext* aContext,
5787 nsRuleNode* aHighestNode,
5788 const RuleDetail aRuleDetail,
5789 const bool aCanStoreInRuleTree)
5791 COMPUTE_START_INHERITED(Color, (mPresContext), color, parentColor)
5793 // color: color, string, inherit
5794 // Special case for currentColor. According to CSS3, setting color to 'currentColor'
5795 // should behave as if it is inherited
5796 const nsCSSValue* colorValue = aRuleData->ValueForColor();
5797 if ((colorValue->GetUnit() == eCSSUnit_EnumColor &&
5798 colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) ||
5799 colorValue->GetUnit() == eCSSUnit_Unset) {
5800 color->mColor = parentColor->mColor;
5801 canStoreInRuleTree = false;
5803 else if (colorValue->GetUnit() == eCSSUnit_Initial) {
5804 color->mColor = mPresContext->DefaultColor();
5806 else {
5807 SetColor(*colorValue, parentColor->mColor, mPresContext, aContext,
5808 color->mColor, canStoreInRuleTree);
5811 COMPUTE_END_INHERITED(Color, color)
5814 // information about how to compute values for background-* properties
5815 template <class SpecifiedValueItem, class ComputedValueItem>
5816 struct BackgroundItemComputer {
5819 template <>
5820 struct BackgroundItemComputer<nsCSSValueList, uint8_t>
5822 static void ComputeValue(nsStyleContext* aStyleContext,
5823 const nsCSSValueList* aSpecifiedValue,
5824 uint8_t& aComputedValue,
5825 bool& aCanStoreInRuleTree)
5827 SetDiscrete(aSpecifiedValue->mValue, aComputedValue, aCanStoreInRuleTree,
5828 SETDSC_ENUMERATED, uint8_t(0), 0, 0, 0, 0, 0);
5832 template <>
5833 struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Repeat>
5835 static void ComputeValue(nsStyleContext* aStyleContext,
5836 const nsCSSValuePairList* aSpecifiedValue,
5837 nsStyleBackground::Repeat& aComputedValue,
5838 bool& aCanStoreInRuleTree)
5840 NS_ASSERTION(aSpecifiedValue->mXValue.GetUnit() == eCSSUnit_Enumerated &&
5841 (aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Enumerated ||
5842 aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null),
5843 "Invalid unit");
5845 bool hasContraction = true;
5846 uint8_t value = aSpecifiedValue->mXValue.GetIntValue();
5847 switch (value) {
5848 case NS_STYLE_BG_REPEAT_REPEAT_X:
5849 aComputedValue.mXRepeat = NS_STYLE_BG_REPEAT_REPEAT;
5850 aComputedValue.mYRepeat = NS_STYLE_BG_REPEAT_NO_REPEAT;
5851 break;
5852 case NS_STYLE_BG_REPEAT_REPEAT_Y:
5853 aComputedValue.mXRepeat = NS_STYLE_BG_REPEAT_NO_REPEAT;
5854 aComputedValue.mYRepeat = NS_STYLE_BG_REPEAT_REPEAT;
5855 break;
5856 default:
5857 aComputedValue.mXRepeat = value;
5858 hasContraction = false;
5859 break;
5862 if (hasContraction) {
5863 NS_ASSERTION(aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null,
5864 "Invalid unit.");
5865 return;
5868 switch (aSpecifiedValue->mYValue.GetUnit()) {
5869 case eCSSUnit_Null:
5870 aComputedValue.mYRepeat = aComputedValue.mXRepeat;
5871 break;
5872 case eCSSUnit_Enumerated:
5873 value = aSpecifiedValue->mYValue.GetIntValue();
5874 NS_ASSERTION(value == NS_STYLE_BG_REPEAT_NO_REPEAT ||
5875 value == NS_STYLE_BG_REPEAT_REPEAT, "Unexpected value");
5876 aComputedValue.mYRepeat = value;
5877 break;
5878 default:
5879 NS_NOTREACHED("Unexpected CSS value");
5880 break;
5885 template <>
5886 struct BackgroundItemComputer<nsCSSValueList, nsStyleImage>
5888 static void ComputeValue(nsStyleContext* aStyleContext,
5889 const nsCSSValueList* aSpecifiedValue,
5890 nsStyleImage& aComputedValue,
5891 bool& aCanStoreInRuleTree)
5893 SetStyleImage(aStyleContext, aSpecifiedValue->mValue, aComputedValue,
5894 aCanStoreInRuleTree);
5898 /* Helper function for
5899 * BackgroundItemComputer<nsCSSValue, nsStyleBackground::Position>
5900 * It computes a single PositionCoord from an nsCSSValue object
5901 * (contained in a list).
5903 typedef nsStyleBackground::Position::PositionCoord PositionCoord;
5904 static void
5905 ComputeBackgroundPositionCoord(nsStyleContext* aStyleContext,
5906 const nsCSSValue& aEdge,
5907 const nsCSSValue& aOffset,
5908 PositionCoord* aResult,
5909 bool& aCanStoreInRuleTree)
5911 if (eCSSUnit_Percent == aOffset.GetUnit()) {
5912 aResult->mLength = 0;
5913 aResult->mPercent = aOffset.GetPercentValue();
5914 aResult->mHasPercent = true;
5915 } else if (aOffset.IsLengthUnit()) {
5916 aResult->mLength = CalcLength(aOffset, aStyleContext,
5917 aStyleContext->PresContext(),
5918 aCanStoreInRuleTree);
5919 aResult->mPercent = 0.0f;
5920 aResult->mHasPercent = false;
5921 } else if (aOffset.IsCalcUnit()) {
5922 LengthPercentPairCalcOps ops(aStyleContext,
5923 aStyleContext->PresContext(),
5924 aCanStoreInRuleTree);
5925 nsRuleNode::ComputedCalc vals = ComputeCalc(aOffset, ops);
5926 aResult->mLength = vals.mLength;
5927 aResult->mPercent = vals.mPercent;
5928 aResult->mHasPercent = ops.mHasPercent;
5929 } else {
5930 aResult->mLength = 0;
5931 aResult->mPercent = 0.0f;
5932 aResult->mHasPercent = false;
5933 NS_ASSERTION(aOffset.GetUnit() == eCSSUnit_Null, "unexpected unit");
5936 if (eCSSUnit_Enumerated == aEdge.GetUnit()) {
5937 int sign;
5938 if (aEdge.GetIntValue() & (NS_STYLE_BG_POSITION_BOTTOM |
5939 NS_STYLE_BG_POSITION_RIGHT)) {
5940 sign = -1;
5941 } else {
5942 sign = 1;
5944 aResult->mPercent = GetFloatFromBoxPosition(aEdge.GetIntValue()) +
5945 sign * aResult->mPercent;
5946 aResult->mLength = sign * aResult->mLength;
5947 aResult->mHasPercent = true;
5948 } else {
5949 NS_ASSERTION(eCSSUnit_Null == aEdge.GetUnit(), "unexpected unit");
5953 template <>
5954 struct BackgroundItemComputer<nsCSSValueList, nsStyleBackground::Position>
5956 static void ComputeValue(nsStyleContext* aStyleContext,
5957 const nsCSSValueList* aSpecifiedValue,
5958 nsStyleBackground::Position& aComputedValue,
5959 bool& aCanStoreInRuleTree)
5961 NS_ASSERTION(aSpecifiedValue->mValue.GetUnit() == eCSSUnit_Array, "bg-position not an array");
5963 nsRefPtr<nsCSSValue::Array> bgPositionArray =
5964 aSpecifiedValue->mValue.GetArrayValue();
5965 const nsCSSValue &xEdge = bgPositionArray->Item(0);
5966 const nsCSSValue &xOffset = bgPositionArray->Item(1);
5967 const nsCSSValue &yEdge = bgPositionArray->Item(2);
5968 const nsCSSValue &yOffset = bgPositionArray->Item(3);
5970 NS_ASSERTION((eCSSUnit_Enumerated == xEdge.GetUnit() ||
5971 eCSSUnit_Null == xEdge.GetUnit()) &&
5972 (eCSSUnit_Enumerated == yEdge.GetUnit() ||
5973 eCSSUnit_Null == yEdge.GetUnit()) &&
5974 eCSSUnit_Enumerated != xOffset.GetUnit() &&
5975 eCSSUnit_Enumerated != yOffset.GetUnit(),
5976 "Invalid background position");
5978 ComputeBackgroundPositionCoord(aStyleContext, xEdge, xOffset,
5979 &aComputedValue.mXPosition,
5980 aCanStoreInRuleTree);
5982 ComputeBackgroundPositionCoord(aStyleContext, yEdge, yOffset,
5983 &aComputedValue.mYPosition,
5984 aCanStoreInRuleTree);
5989 struct BackgroundSizeAxis {
5990 nsCSSValue nsCSSValuePairList::* specified;
5991 nsStyleBackground::Size::Dimension nsStyleBackground::Size::* result;
5992 uint8_t nsStyleBackground::Size::* type;
5995 static const BackgroundSizeAxis gBGSizeAxes[] = {
5996 { &nsCSSValuePairList::mXValue,
5997 &nsStyleBackground::Size::mWidth,
5998 &nsStyleBackground::Size::mWidthType },
5999 { &nsCSSValuePairList::mYValue,
6000 &nsStyleBackground::Size::mHeight,
6001 &nsStyleBackground::Size::mHeightType }
6004 template <>
6005 struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Size>
6007 static void ComputeValue(nsStyleContext* aStyleContext,
6008 const nsCSSValuePairList* aSpecifiedValue,
6009 nsStyleBackground::Size& aComputedValue,
6010 bool& aCanStoreInRuleTree)
6012 nsStyleBackground::Size &size = aComputedValue;
6013 for (const BackgroundSizeAxis *axis = gBGSizeAxes,
6014 *axis_end = ArrayEnd(gBGSizeAxes);
6015 axis < axis_end; ++axis) {
6016 const nsCSSValue &specified = aSpecifiedValue->*(axis->specified);
6017 if (eCSSUnit_Auto == specified.GetUnit()) {
6018 size.*(axis->type) = nsStyleBackground::Size::eAuto;
6020 else if (eCSSUnit_Enumerated == specified.GetUnit()) {
6021 static_assert(nsStyleBackground::Size::eContain ==
6022 NS_STYLE_BG_SIZE_CONTAIN &&
6023 nsStyleBackground::Size::eCover ==
6024 NS_STYLE_BG_SIZE_COVER,
6025 "background size constants out of sync");
6026 NS_ABORT_IF_FALSE(specified.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
6027 specified.GetIntValue() == NS_STYLE_BG_SIZE_COVER,
6028 "invalid enumerated value for size coordinate");
6029 size.*(axis->type) = specified.GetIntValue();
6031 else if (eCSSUnit_Null == specified.GetUnit()) {
6032 NS_ABORT_IF_FALSE(axis == gBGSizeAxes + 1,
6033 "null allowed only as height value, and only "
6034 "for contain/cover/initial/inherit");
6035 #ifdef DEBUG
6037 const nsCSSValue &widthValue = aSpecifiedValue->mXValue;
6038 NS_ABORT_IF_FALSE(widthValue.GetUnit() != eCSSUnit_Inherit &&
6039 widthValue.GetUnit() != eCSSUnit_Initial &&
6040 widthValue.GetUnit() != eCSSUnit_Unset,
6041 "initial/inherit/unset should already have been handled");
6042 NS_ABORT_IF_FALSE(widthValue.GetUnit() == eCSSUnit_Enumerated &&
6043 (widthValue.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
6044 widthValue.GetIntValue() == NS_STYLE_BG_SIZE_COVER),
6045 "null height value not corresponding to allowable "
6046 "non-null width value");
6048 #endif
6049 size.*(axis->type) = size.mWidthType;
6051 else if (eCSSUnit_Percent == specified.GetUnit()) {
6052 (size.*(axis->result)).mLength = 0;
6053 (size.*(axis->result)).mPercent = specified.GetPercentValue();
6054 (size.*(axis->result)).mHasPercent = true;
6055 size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
6057 else if (specified.IsLengthUnit()) {
6058 (size.*(axis->result)).mLength =
6059 CalcLength(specified, aStyleContext, aStyleContext->PresContext(),
6060 aCanStoreInRuleTree);
6061 (size.*(axis->result)).mPercent = 0.0f;
6062 (size.*(axis->result)).mHasPercent = false;
6063 size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
6064 } else {
6065 NS_ABORT_IF_FALSE(specified.IsCalcUnit(), "unexpected unit");
6066 LengthPercentPairCalcOps ops(aStyleContext,
6067 aStyleContext->PresContext(),
6068 aCanStoreInRuleTree);
6069 nsRuleNode::ComputedCalc vals = ComputeCalc(specified, ops);
6070 (size.*(axis->result)).mLength = vals.mLength;
6071 (size.*(axis->result)).mPercent = vals.mPercent;
6072 (size.*(axis->result)).mHasPercent = ops.mHasPercent;
6073 size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
6077 NS_ABORT_IF_FALSE(size.mWidthType < nsStyleBackground::Size::eDimensionType_COUNT,
6078 "bad width type");
6079 NS_ABORT_IF_FALSE(size.mHeightType < nsStyleBackground::Size::eDimensionType_COUNT,
6080 "bad height type");
6081 NS_ABORT_IF_FALSE((size.mWidthType != nsStyleBackground::Size::eContain &&
6082 size.mWidthType != nsStyleBackground::Size::eCover) ||
6083 size.mWidthType == size.mHeightType,
6084 "contain/cover apply to both dimensions or to neither");
6088 template <class ComputedValueItem>
6089 static void
6090 SetBackgroundList(nsStyleContext* aStyleContext,
6091 const nsCSSValue& aValue,
6092 nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
6093 const nsAutoTArray<nsStyleBackground::Layer, 1> &aParentLayers,
6094 ComputedValueItem nsStyleBackground::Layer::* aResultLocation,
6095 ComputedValueItem aInitialValue,
6096 uint32_t aParentItemCount,
6097 uint32_t& aItemCount,
6098 uint32_t& aMaxItemCount,
6099 bool& aRebuild,
6100 bool& aCanStoreInRuleTree)
6102 switch (aValue.GetUnit()) {
6103 case eCSSUnit_Null:
6104 break;
6106 case eCSSUnit_Inherit:
6107 aRebuild = true;
6108 aCanStoreInRuleTree = false;
6109 aLayers.EnsureLengthAtLeast(aParentItemCount);
6110 aItemCount = aParentItemCount;
6111 for (uint32_t i = 0; i < aParentItemCount; ++i) {
6112 aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
6114 break;
6116 case eCSSUnit_Initial:
6117 case eCSSUnit_Unset:
6118 aRebuild = true;
6119 aItemCount = 1;
6120 aLayers[0].*aResultLocation = aInitialValue;
6121 break;
6123 case eCSSUnit_List:
6124 case eCSSUnit_ListDep: {
6125 aRebuild = true;
6126 aItemCount = 0;
6127 const nsCSSValueList* item = aValue.GetListValue();
6128 do {
6129 NS_ASSERTION(item->mValue.GetUnit() != eCSSUnit_Null &&
6130 item->mValue.GetUnit() != eCSSUnit_Inherit &&
6131 item->mValue.GetUnit() != eCSSUnit_Initial &&
6132 item->mValue.GetUnit() != eCSSUnit_Unset,
6133 "unexpected unit");
6134 ++aItemCount;
6135 aLayers.EnsureLengthAtLeast(aItemCount);
6136 BackgroundItemComputer<nsCSSValueList, ComputedValueItem>
6137 ::ComputeValue(aStyleContext, item,
6138 aLayers[aItemCount-1].*aResultLocation,
6139 aCanStoreInRuleTree);
6140 item = item->mNext;
6141 } while (item);
6142 break;
6145 default:
6146 NS_ABORT_IF_FALSE(false,
6147 nsPrintfCString("unexpected unit %d",
6148 aValue.GetUnit()).get());
6151 if (aItemCount > aMaxItemCount)
6152 aMaxItemCount = aItemCount;
6155 template <class ComputedValueItem>
6156 static void
6157 SetBackgroundPairList(nsStyleContext* aStyleContext,
6158 const nsCSSValue& aValue,
6159 nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
6160 const nsAutoTArray<nsStyleBackground::Layer, 1>
6161 &aParentLayers,
6162 ComputedValueItem nsStyleBackground::Layer::*
6163 aResultLocation,
6164 ComputedValueItem aInitialValue,
6165 uint32_t aParentItemCount,
6166 uint32_t& aItemCount,
6167 uint32_t& aMaxItemCount,
6168 bool& aRebuild,
6169 bool& aCanStoreInRuleTree)
6171 switch (aValue.GetUnit()) {
6172 case eCSSUnit_Null:
6173 break;
6175 case eCSSUnit_Inherit:
6176 aRebuild = true;
6177 aCanStoreInRuleTree = false;
6178 aLayers.EnsureLengthAtLeast(aParentItemCount);
6179 aItemCount = aParentItemCount;
6180 for (uint32_t i = 0; i < aParentItemCount; ++i) {
6181 aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
6183 break;
6185 case eCSSUnit_Initial:
6186 case eCSSUnit_Unset:
6187 aRebuild = true;
6188 aItemCount = 1;
6189 aLayers[0].*aResultLocation = aInitialValue;
6190 break;
6192 case eCSSUnit_PairList:
6193 case eCSSUnit_PairListDep: {
6194 aRebuild = true;
6195 aItemCount = 0;
6196 const nsCSSValuePairList* item = aValue.GetPairListValue();
6197 do {
6198 NS_ASSERTION(item->mXValue.GetUnit() != eCSSUnit_Inherit &&
6199 item->mXValue.GetUnit() != eCSSUnit_Initial &&
6200 item->mXValue.GetUnit() != eCSSUnit_Unset &&
6201 item->mYValue.GetUnit() != eCSSUnit_Inherit &&
6202 item->mYValue.GetUnit() != eCSSUnit_Initial &&
6203 item->mYValue.GetUnit() != eCSSUnit_Unset,
6204 "unexpected unit");
6205 ++aItemCount;
6206 aLayers.EnsureLengthAtLeast(aItemCount);
6207 BackgroundItemComputer<nsCSSValuePairList, ComputedValueItem>
6208 ::ComputeValue(aStyleContext, item,
6209 aLayers[aItemCount-1].*aResultLocation,
6210 aCanStoreInRuleTree);
6211 item = item->mNext;
6212 } while (item);
6213 break;
6216 default:
6217 NS_ABORT_IF_FALSE(false,
6218 nsPrintfCString("unexpected unit %d",
6219 aValue.GetUnit()).get());
6222 if (aItemCount > aMaxItemCount)
6223 aMaxItemCount = aItemCount;
6226 template <class ComputedValueItem>
6227 static void
6228 FillBackgroundList(nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
6229 ComputedValueItem nsStyleBackground::Layer::* aResultLocation,
6230 uint32_t aItemCount, uint32_t aFillCount)
6232 NS_PRECONDITION(aFillCount <= aLayers.Length(), "unexpected array length");
6233 for (uint32_t sourceLayer = 0, destLayer = aItemCount;
6234 destLayer < aFillCount;
6235 ++sourceLayer, ++destLayer) {
6236 aLayers[destLayer].*aResultLocation =
6237 aLayers[sourceLayer].*aResultLocation;
6241 const void*
6242 nsRuleNode::ComputeBackgroundData(void* aStartStruct,
6243 const nsRuleData* aRuleData,
6244 nsStyleContext* aContext,
6245 nsRuleNode* aHighestNode,
6246 const RuleDetail aRuleDetail,
6247 const bool aCanStoreInRuleTree)
6249 COMPUTE_START_RESET(Background, (), bg, parentBG)
6251 // background-color: color, string, inherit
6252 const nsCSSValue* backColorValue = aRuleData->ValueForBackgroundColor();
6253 if (eCSSUnit_Initial == backColorValue->GetUnit() ||
6254 eCSSUnit_Unset == backColorValue->GetUnit()) {
6255 bg->mBackgroundColor = NS_RGBA(0, 0, 0, 0);
6256 } else if (!SetColor(*backColorValue, parentBG->mBackgroundColor,
6257 mPresContext, aContext, bg->mBackgroundColor,
6258 canStoreInRuleTree)) {
6259 NS_ASSERTION(eCSSUnit_Null == backColorValue->GetUnit(),
6260 "unexpected color unit");
6263 uint32_t maxItemCount = 1;
6264 bool rebuild = false;
6266 // background-image: url (stored as image), none, inherit [list]
6267 nsStyleImage initialImage;
6268 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundImage(),
6269 bg->mLayers,
6270 parentBG->mLayers, &nsStyleBackground::Layer::mImage,
6271 initialImage, parentBG->mImageCount, bg->mImageCount,
6272 maxItemCount, rebuild, canStoreInRuleTree);
6274 // background-repeat: enum, inherit, initial [pair list]
6275 nsStyleBackground::Repeat initialRepeat;
6276 initialRepeat.SetInitialValues();
6277 SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundRepeat(),
6278 bg->mLayers,
6279 parentBG->mLayers, &nsStyleBackground::Layer::mRepeat,
6280 initialRepeat, parentBG->mRepeatCount,
6281 bg->mRepeatCount, maxItemCount, rebuild,
6282 canStoreInRuleTree);
6284 // background-attachment: enum, inherit, initial [list]
6285 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundAttachment(),
6286 bg->mLayers, parentBG->mLayers,
6287 &nsStyleBackground::Layer::mAttachment,
6288 uint8_t(NS_STYLE_BG_ATTACHMENT_SCROLL),
6289 parentBG->mAttachmentCount,
6290 bg->mAttachmentCount, maxItemCount, rebuild,
6291 canStoreInRuleTree);
6293 // background-clip: enum, inherit, initial [list]
6294 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundClip(),
6295 bg->mLayers,
6296 parentBG->mLayers, &nsStyleBackground::Layer::mClip,
6297 uint8_t(NS_STYLE_BG_CLIP_BORDER), parentBG->mClipCount,
6298 bg->mClipCount, maxItemCount, rebuild, canStoreInRuleTree);
6300 // background-blend-mode: enum, inherit, initial [list]
6301 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundBlendMode(),
6302 bg->mLayers,
6303 parentBG->mLayers, &nsStyleBackground::Layer::mBlendMode,
6304 uint8_t(NS_STYLE_BLEND_NORMAL), parentBG->mBlendModeCount,
6305 bg->mBlendModeCount, maxItemCount, rebuild,
6306 canStoreInRuleTree);
6308 // background-origin: enum, inherit, initial [list]
6309 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundOrigin(),
6310 bg->mLayers,
6311 parentBG->mLayers, &nsStyleBackground::Layer::mOrigin,
6312 uint8_t(NS_STYLE_BG_ORIGIN_PADDING), parentBG->mOriginCount,
6313 bg->mOriginCount, maxItemCount, rebuild,
6314 canStoreInRuleTree);
6316 // background-position: enum, length, percent (flags), inherit [pair list]
6317 nsStyleBackground::Position initialPosition;
6318 initialPosition.SetInitialValues();
6319 SetBackgroundList(aContext, *aRuleData->ValueForBackgroundPosition(),
6320 bg->mLayers,
6321 parentBG->mLayers, &nsStyleBackground::Layer::mPosition,
6322 initialPosition, parentBG->mPositionCount,
6323 bg->mPositionCount, maxItemCount, rebuild,
6324 canStoreInRuleTree);
6326 // background-size: enum, length, auto, inherit, initial [pair list]
6327 nsStyleBackground::Size initialSize;
6328 initialSize.SetInitialValues();
6329 SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundSize(),
6330 bg->mLayers,
6331 parentBG->mLayers, &nsStyleBackground::Layer::mSize,
6332 initialSize, parentBG->mSizeCount,
6333 bg->mSizeCount, maxItemCount, rebuild,
6334 canStoreInRuleTree);
6336 if (rebuild) {
6337 // Delete any extra items. We need to keep layers in which any
6338 // property was specified.
6339 bg->mLayers.TruncateLength(maxItemCount);
6341 uint32_t fillCount = bg->mImageCount;
6342 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mImage,
6343 bg->mImageCount, fillCount);
6344 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mRepeat,
6345 bg->mRepeatCount, fillCount);
6346 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mAttachment,
6347 bg->mAttachmentCount, fillCount);
6348 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mClip,
6349 bg->mClipCount, fillCount);
6350 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mBlendMode,
6351 bg->mBlendModeCount, fillCount);
6352 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mOrigin,
6353 bg->mOriginCount, fillCount);
6354 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mPosition,
6355 bg->mPositionCount, fillCount);
6356 FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mSize,
6357 bg->mSizeCount, fillCount);
6360 // Now that the dust has settled, register the images with the document
6361 for (uint32_t i = 0; i < bg->mImageCount; ++i)
6362 bg->mLayers[i].TrackImages(aContext->PresContext());
6364 COMPUTE_END_RESET(Background, bg)
6367 const void*
6368 nsRuleNode::ComputeMarginData(void* aStartStruct,
6369 const nsRuleData* aRuleData,
6370 nsStyleContext* aContext,
6371 nsRuleNode* aHighestNode,
6372 const RuleDetail aRuleDetail,
6373 const bool aCanStoreInRuleTree)
6375 COMPUTE_START_RESET(Margin, (), margin, parentMargin)
6377 // margin: length, percent, auto, inherit
6378 nsStyleCoord coord;
6379 nsCSSRect ourMargin;
6380 ourMargin.mTop = *aRuleData->ValueForMarginTop();
6381 ourMargin.mRight = *aRuleData->ValueForMarginRightValue();
6382 ourMargin.mBottom = *aRuleData->ValueForMarginBottom();
6383 ourMargin.mLeft = *aRuleData->ValueForMarginLeftValue();
6384 AdjustLogicalBoxProp(aContext,
6385 *aRuleData->ValueForMarginLeftLTRSource(),
6386 *aRuleData->ValueForMarginLeftRTLSource(),
6387 *aRuleData->ValueForMarginStartValue(),
6388 *aRuleData->ValueForMarginEndValue(),
6389 NS_SIDE_LEFT, ourMargin, canStoreInRuleTree);
6390 AdjustLogicalBoxProp(aContext,
6391 *aRuleData->ValueForMarginRightLTRSource(),
6392 *aRuleData->ValueForMarginRightRTLSource(),
6393 *aRuleData->ValueForMarginEndValue(),
6394 *aRuleData->ValueForMarginStartValue(),
6395 NS_SIDE_RIGHT, ourMargin, canStoreInRuleTree);
6396 NS_FOR_CSS_SIDES(side) {
6397 nsStyleCoord parentCoord = parentMargin->mMargin.Get(side);
6398 if (SetCoord(ourMargin.*(nsCSSRect::sides[side]),
6399 coord, parentCoord,
6400 SETCOORD_LPAH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
6401 SETCOORD_UNSET_INITIAL,
6402 aContext, mPresContext, canStoreInRuleTree)) {
6403 margin->mMargin.Set(side, coord);
6407 margin->RecalcData();
6408 COMPUTE_END_RESET(Margin, margin)
6411 static void
6412 SetBorderImageRect(const nsCSSValue& aValue,
6413 /** outparam */ nsCSSRect& aRect)
6415 switch (aValue.GetUnit()) {
6416 case eCSSUnit_Null:
6417 aRect.Reset();
6418 break;
6419 case eCSSUnit_Rect:
6420 aRect = aValue.GetRectValue();
6421 break;
6422 case eCSSUnit_Inherit:
6423 case eCSSUnit_Initial:
6424 case eCSSUnit_Unset:
6425 aRect.SetAllSidesTo(aValue);
6426 break;
6427 default:
6428 NS_ASSERTION(false, "Unexpected border image value for rect.");
6432 static void
6433 SetBorderImagePair(const nsCSSValue& aValue,
6434 /** outparam */ nsCSSValuePair& aPair)
6436 switch (aValue.GetUnit()) {
6437 case eCSSUnit_Null:
6438 aPair.Reset();
6439 break;
6440 case eCSSUnit_Pair:
6441 aPair = aValue.GetPairValue();
6442 break;
6443 case eCSSUnit_Inherit:
6444 case eCSSUnit_Initial:
6445 case eCSSUnit_Unset:
6446 aPair.SetBothValuesTo(aValue);
6447 break;
6448 default:
6449 NS_ASSERTION(false, "Unexpected border image value for pair.");
6453 static void
6454 SetBorderImageSlice(const nsCSSValue& aValue,
6455 /** outparam */ nsCSSValue& aSlice,
6456 /** outparam */ nsCSSValue& aFill)
6458 const nsCSSValueList* valueList;
6459 switch (aValue.GetUnit()) {
6460 case eCSSUnit_Null:
6461 aSlice.Reset();
6462 aFill.Reset();
6463 break;
6464 case eCSSUnit_List:
6465 // Get slice dimensions.
6466 valueList = aValue.GetListValue();
6467 aSlice = valueList->mValue;
6469 // Get "fill" keyword.
6470 valueList = valueList->mNext;
6471 if (valueList) {
6472 aFill = valueList->mValue;
6473 } else {
6474 aFill.SetInitialValue();
6476 break;
6477 case eCSSUnit_Inherit:
6478 case eCSSUnit_Initial:
6479 case eCSSUnit_Unset:
6480 aSlice = aValue;
6481 aFill = aValue;
6482 break;
6483 default:
6484 NS_ASSERTION(false, "Unexpected border image value for pair.");
6488 const void*
6489 nsRuleNode::ComputeBorderData(void* aStartStruct,
6490 const nsRuleData* aRuleData,
6491 nsStyleContext* aContext,
6492 nsRuleNode* aHighestNode,
6493 const RuleDetail aRuleDetail,
6494 const bool aCanStoreInRuleTree)
6496 COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder)
6498 // box-decoration-break: enum, inherit, initial
6499 SetDiscrete(*aRuleData->ValueForBoxDecorationBreak(),
6500 border->mBoxDecorationBreak, canStoreInRuleTree,
6501 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
6502 parentBorder->mBoxDecorationBreak,
6503 NS_STYLE_BOX_DECORATION_BREAK_SLICE, 0, 0, 0, 0);
6505 // box-shadow: none, list, inherit, initial
6506 const nsCSSValue* boxShadowValue = aRuleData->ValueForBoxShadow();
6507 switch (boxShadowValue->GetUnit()) {
6508 case eCSSUnit_Null:
6509 break;
6511 case eCSSUnit_Initial:
6512 case eCSSUnit_Unset:
6513 case eCSSUnit_None:
6514 border->mBoxShadow = nullptr;
6515 break;
6517 case eCSSUnit_Inherit:
6518 border->mBoxShadow = parentBorder->mBoxShadow;
6519 canStoreInRuleTree = false;
6520 break;
6522 case eCSSUnit_List:
6523 case eCSSUnit_ListDep:
6524 border->mBoxShadow = GetShadowData(boxShadowValue->GetListValue(),
6525 aContext, true, canStoreInRuleTree);
6526 break;
6528 default:
6529 NS_ABORT_IF_FALSE(false,
6530 nsPrintfCString("unrecognized shadow unit %d",
6531 boxShadowValue->GetUnit()).get());
6534 // border-width, border-*-width: length, enum, inherit
6535 nsStyleCoord coord;
6536 nsCSSRect ourBorderWidth;
6537 ourBorderWidth.mTop = *aRuleData->ValueForBorderTopWidth();
6538 ourBorderWidth.mRight = *aRuleData->ValueForBorderRightWidthValue();
6539 ourBorderWidth.mBottom = *aRuleData->ValueForBorderBottomWidth();
6540 ourBorderWidth.mLeft = *aRuleData->ValueForBorderLeftWidthValue();
6541 AdjustLogicalBoxProp(aContext,
6542 *aRuleData->ValueForBorderLeftWidthLTRSource(),
6543 *aRuleData->ValueForBorderLeftWidthRTLSource(),
6544 *aRuleData->ValueForBorderStartWidthValue(),
6545 *aRuleData->ValueForBorderEndWidthValue(),
6546 NS_SIDE_LEFT, ourBorderWidth, canStoreInRuleTree);
6547 AdjustLogicalBoxProp(aContext,
6548 *aRuleData->ValueForBorderRightWidthLTRSource(),
6549 *aRuleData->ValueForBorderRightWidthRTLSource(),
6550 *aRuleData->ValueForBorderEndWidthValue(),
6551 *aRuleData->ValueForBorderStartWidthValue(),
6552 NS_SIDE_RIGHT, ourBorderWidth, canStoreInRuleTree);
6553 { // scope for compilers with broken |for| loop scoping
6554 NS_FOR_CSS_SIDES(side) {
6555 const nsCSSValue &value = ourBorderWidth.*(nsCSSRect::sides[side]);
6556 NS_ASSERTION(eCSSUnit_Percent != value.GetUnit(),
6557 "Percentage borders not implemented yet "
6558 "If implementing, make sure to fix all consumers of "
6559 "nsStyleBorder, the IsPercentageAwareChild method, "
6560 "the nsAbsoluteContainingBlock::FrameDependsOnContainer "
6561 "method, the "
6562 "nsLineLayout::IsPercentageAwareReplacedElement method "
6563 "and probably some other places");
6564 if (eCSSUnit_Enumerated == value.GetUnit()) {
6565 NS_ASSERTION(value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
6566 value.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
6567 value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
6568 "Unexpected enum value");
6569 border->SetBorderWidth(side,
6570 (mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
6572 // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
6573 else if (SetCoord(value, coord, nsStyleCoord(),
6574 SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
6575 aContext, mPresContext, canStoreInRuleTree)) {
6576 NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
6577 // clamp negative calc() to 0.
6578 border->SetBorderWidth(side, std::max(coord.GetCoordValue(), 0));
6580 else if (eCSSUnit_Inherit == value.GetUnit()) {
6581 canStoreInRuleTree = false;
6582 border->SetBorderWidth(side,
6583 parentBorder->GetComputedBorder().Side(side));
6585 else if (eCSSUnit_Initial == value.GetUnit() ||
6586 eCSSUnit_Unset == value.GetUnit()) {
6587 border->SetBorderWidth(side,
6588 (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
6590 else {
6591 NS_ASSERTION(eCSSUnit_Null == value.GetUnit(),
6592 "missing case handling border width");
6597 // border-style, border-*-style: enum, inherit
6598 nsCSSRect ourBorderStyle;
6599 ourBorderStyle.mTop = *aRuleData->ValueForBorderTopStyle();
6600 ourBorderStyle.mRight = *aRuleData->ValueForBorderRightStyleValue();
6601 ourBorderStyle.mBottom = *aRuleData->ValueForBorderBottomStyle();
6602 ourBorderStyle.mLeft = *aRuleData->ValueForBorderLeftStyleValue();
6603 AdjustLogicalBoxProp(aContext,
6604 *aRuleData->ValueForBorderLeftStyleLTRSource(),
6605 *aRuleData->ValueForBorderLeftStyleRTLSource(),
6606 *aRuleData->ValueForBorderStartStyleValue(),
6607 *aRuleData->ValueForBorderEndStyleValue(),
6608 NS_SIDE_LEFT, ourBorderStyle, canStoreInRuleTree);
6609 AdjustLogicalBoxProp(aContext,
6610 *aRuleData->ValueForBorderRightStyleLTRSource(),
6611 *aRuleData->ValueForBorderRightStyleRTLSource(),
6612 *aRuleData->ValueForBorderEndStyleValue(),
6613 *aRuleData->ValueForBorderStartStyleValue(),
6614 NS_SIDE_RIGHT, ourBorderStyle, canStoreInRuleTree);
6615 { // scope for compilers with broken |for| loop scoping
6616 NS_FOR_CSS_SIDES(side) {
6617 const nsCSSValue &value = ourBorderStyle.*(nsCSSRect::sides[side]);
6618 nsCSSUnit unit = value.GetUnit();
6619 NS_ABORT_IF_FALSE(eCSSUnit_None != unit,
6620 "'none' should be handled as enumerated value");
6621 if (eCSSUnit_Enumerated == unit) {
6622 border->SetBorderStyle(side, value.GetIntValue());
6624 else if (eCSSUnit_Initial == unit ||
6625 eCSSUnit_Unset == unit) {
6626 border->SetBorderStyle(side, NS_STYLE_BORDER_STYLE_NONE);
6628 else if (eCSSUnit_Inherit == unit) {
6629 canStoreInRuleTree = false;
6630 border->SetBorderStyle(side, parentBorder->GetBorderStyle(side));
6635 // -moz-border-*-colors: color, string, enum, none, inherit/initial
6636 nscolor borderColor;
6637 nscolor unused = NS_RGB(0,0,0);
6639 static const nsCSSProperty borderColorsProps[] = {
6640 eCSSProperty_border_top_colors,
6641 eCSSProperty_border_right_colors,
6642 eCSSProperty_border_bottom_colors,
6643 eCSSProperty_border_left_colors
6646 NS_FOR_CSS_SIDES(side) {
6647 const nsCSSValue& value = *aRuleData->ValueFor(borderColorsProps[side]);
6648 switch (value.GetUnit()) {
6649 case eCSSUnit_Null:
6650 break;
6652 case eCSSUnit_Initial:
6653 case eCSSUnit_Unset:
6654 case eCSSUnit_None:
6655 border->ClearBorderColors(side);
6656 break;
6658 case eCSSUnit_Inherit: {
6659 canStoreInRuleTree = false;
6660 border->ClearBorderColors(side);
6661 if (parentContext) {
6662 nsBorderColors *parentColors;
6663 parentBorder->GetCompositeColors(side, &parentColors);
6664 if (parentColors) {
6665 border->EnsureBorderColors();
6666 border->mBorderColors[side] = parentColors->Clone();
6669 break;
6672 case eCSSUnit_List:
6673 case eCSSUnit_ListDep: {
6674 // Some composite border color information has been specified for this
6675 // border side.
6676 border->EnsureBorderColors();
6677 border->ClearBorderColors(side);
6678 const nsCSSValueList* list = value.GetListValue();
6679 while (list) {
6680 if (SetColor(list->mValue, unused, mPresContext,
6681 aContext, borderColor, canStoreInRuleTree))
6682 border->AppendBorderColor(side, borderColor);
6683 else {
6684 NS_NOTREACHED("unexpected item in -moz-border-*-colors list");
6686 list = list->mNext;
6688 break;
6691 default:
6692 NS_ABORT_IF_FALSE(false, "unrecognized border color unit");
6696 // border-color, border-*-color: color, string, enum, inherit
6697 bool foreground;
6698 nsCSSRect ourBorderColor;
6699 ourBorderColor.mTop = *aRuleData->ValueForBorderTopColor();
6700 ourBorderColor.mRight = *aRuleData->ValueForBorderRightColorValue();
6701 ourBorderColor.mBottom = *aRuleData->ValueForBorderBottomColor();
6702 ourBorderColor.mLeft = *aRuleData->ValueForBorderLeftColorValue();
6703 AdjustLogicalBoxProp(aContext,
6704 *aRuleData->ValueForBorderLeftColorLTRSource(),
6705 *aRuleData->ValueForBorderLeftColorRTLSource(),
6706 *aRuleData->ValueForBorderStartColorValue(),
6707 *aRuleData->ValueForBorderEndColorValue(),
6708 NS_SIDE_LEFT, ourBorderColor, canStoreInRuleTree);
6709 AdjustLogicalBoxProp(aContext,
6710 *aRuleData->ValueForBorderRightColorLTRSource(),
6711 *aRuleData->ValueForBorderRightColorRTLSource(),
6712 *aRuleData->ValueForBorderEndColorValue(),
6713 *aRuleData->ValueForBorderStartColorValue(),
6714 NS_SIDE_RIGHT, ourBorderColor, canStoreInRuleTree);
6715 { // scope for compilers with broken |for| loop scoping
6716 NS_FOR_CSS_SIDES(side) {
6717 const nsCSSValue &value = ourBorderColor.*(nsCSSRect::sides[side]);
6718 if (eCSSUnit_Inherit == value.GetUnit()) {
6719 canStoreInRuleTree = false;
6720 if (parentContext) {
6721 parentBorder->GetBorderColor(side, borderColor, foreground);
6722 if (foreground) {
6723 // We want to inherit the color from the parent, not use the
6724 // color on the element where this chunk of style data will be
6725 // used. We can ensure that the data for the parent are fully
6726 // computed (unlike for the element where this will be used, for
6727 // which the color could be specified on a more specific rule).
6728 border->SetBorderColor(side, parentContext->StyleColor()->mColor);
6729 } else
6730 border->SetBorderColor(side, borderColor);
6731 } else {
6732 // We're the root
6733 border->SetBorderToForeground(side);
6736 else if (SetColor(value, unused, mPresContext, aContext, borderColor,
6737 canStoreInRuleTree)) {
6738 border->SetBorderColor(side, borderColor);
6740 else if (eCSSUnit_Enumerated == value.GetUnit()) {
6741 switch (value.GetIntValue()) {
6742 case NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR:
6743 border->SetBorderToForeground(side);
6744 break;
6745 default:
6746 NS_NOTREACHED("Unexpected enumerated color");
6747 break;
6750 else if (eCSSUnit_Initial == value.GetUnit() ||
6751 eCSSUnit_Unset == value.GetUnit()) {
6752 border->SetBorderToForeground(side);
6757 // border-radius: length, percent, inherit
6759 const nsCSSProperty* subprops =
6760 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius);
6761 NS_FOR_CSS_FULL_CORNERS(corner) {
6762 int cx = NS_FULL_TO_HALF_CORNER(corner, false);
6763 int cy = NS_FULL_TO_HALF_CORNER(corner, true);
6764 const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
6765 nsStyleCoord parentX = parentBorder->mBorderRadius.Get(cx);
6766 nsStyleCoord parentY = parentBorder->mBorderRadius.Get(cy);
6767 nsStyleCoord coordX, coordY;
6769 if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
6770 SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
6771 SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
6772 aContext, mPresContext, canStoreInRuleTree)) {
6773 border->mBorderRadius.Set(cx, coordX);
6774 border->mBorderRadius.Set(cy, coordY);
6779 // float-edge: enum, inherit, initial
6780 SetDiscrete(*aRuleData->ValueForFloatEdge(),
6781 border->mFloatEdge, canStoreInRuleTree,
6782 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
6783 parentBorder->mFloatEdge,
6784 NS_STYLE_FLOAT_EDGE_CONTENT, 0, 0, 0, 0);
6786 // border-image-source
6787 const nsCSSValue* borderImageSource = aRuleData->ValueForBorderImageSource();
6788 if (borderImageSource->GetUnit() == eCSSUnit_Inherit) {
6789 canStoreInRuleTree = false;
6790 border->mBorderImageSource = parentBorder->mBorderImageSource;
6791 } else {
6792 SetStyleImage(aContext,
6793 *borderImageSource,
6794 border->mBorderImageSource,
6795 canStoreInRuleTree);
6798 nsCSSValue borderImageSliceValue;
6799 nsCSSValue borderImageSliceFill;
6800 SetBorderImageSlice(*aRuleData->ValueForBorderImageSlice(),
6801 borderImageSliceValue, borderImageSliceFill);
6803 // border-image-slice: fill
6804 SetDiscrete(borderImageSliceFill,
6805 border->mBorderImageFill,
6806 canStoreInRuleTree,
6807 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
6808 parentBorder->mBorderImageFill,
6809 NS_STYLE_BORDER_IMAGE_SLICE_NOFILL, 0, 0, 0, 0);
6811 nsCSSRect borderImageSlice;
6812 SetBorderImageRect(borderImageSliceValue, borderImageSlice);
6814 nsCSSRect borderImageWidth;
6815 SetBorderImageRect(*aRuleData->ValueForBorderImageWidth(),
6816 borderImageWidth);
6818 nsCSSRect borderImageOutset;
6819 SetBorderImageRect(*aRuleData->ValueForBorderImageOutset(),
6820 borderImageOutset);
6822 NS_FOR_CSS_SIDES (side) {
6823 // border-image-slice
6824 if (SetCoord(borderImageSlice.*(nsCSSRect::sides[side]), coord,
6825 parentBorder->mBorderImageSlice.Get(side),
6826 SETCOORD_FACTOR | SETCOORD_PERCENT |
6827 SETCOORD_INHERIT | SETCOORD_INITIAL_HUNDRED_PCT |
6828 SETCOORD_UNSET_INITIAL,
6829 aContext, mPresContext, canStoreInRuleTree)) {
6830 border->mBorderImageSlice.Set(side, coord);
6833 // border-image-width
6834 // 'auto' here means "same as slice"
6835 if (SetCoord(borderImageWidth.*(nsCSSRect::sides[side]), coord,
6836 parentBorder->mBorderImageWidth.Get(side),
6837 SETCOORD_LPAH | SETCOORD_FACTOR | SETCOORD_INITIAL_FACTOR_ONE |
6838 SETCOORD_UNSET_INITIAL,
6839 aContext, mPresContext, canStoreInRuleTree)) {
6840 border->mBorderImageWidth.Set(side, coord);
6843 // border-image-outset
6844 if (SetCoord(borderImageOutset.*(nsCSSRect::sides[side]), coord,
6845 parentBorder->mBorderImageOutset.Get(side),
6846 SETCOORD_LENGTH | SETCOORD_FACTOR |
6847 SETCOORD_INHERIT | SETCOORD_INITIAL_FACTOR_ZERO |
6848 SETCOORD_UNSET_INITIAL,
6849 aContext, mPresContext, canStoreInRuleTree)) {
6850 border->mBorderImageOutset.Set(side, coord);
6854 // border-image-repeat
6855 nsCSSValuePair borderImageRepeat;
6856 SetBorderImagePair(*aRuleData->ValueForBorderImageRepeat(),
6857 borderImageRepeat);
6859 SetDiscrete(borderImageRepeat.mXValue,
6860 border->mBorderImageRepeatH,
6861 canStoreInRuleTree,
6862 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
6863 parentBorder->mBorderImageRepeatH,
6864 NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
6866 SetDiscrete(borderImageRepeat.mYValue,
6867 border->mBorderImageRepeatV,
6868 canStoreInRuleTree,
6869 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
6870 parentBorder->mBorderImageRepeatV,
6871 NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
6873 border->TrackImage(aContext->PresContext());
6875 COMPUTE_END_RESET(Border, border)
6878 const void*
6879 nsRuleNode::ComputePaddingData(void* aStartStruct,
6880 const nsRuleData* aRuleData,
6881 nsStyleContext* aContext,
6882 nsRuleNode* aHighestNode,
6883 const RuleDetail aRuleDetail,
6884 const bool aCanStoreInRuleTree)
6886 COMPUTE_START_RESET(Padding, (), padding, parentPadding)
6888 // padding: length, percent, inherit
6889 nsStyleCoord coord;
6890 nsCSSRect ourPadding;
6891 ourPadding.mTop = *aRuleData->ValueForPaddingTop();
6892 ourPadding.mRight = *aRuleData->ValueForPaddingRightValue();
6893 ourPadding.mBottom = *aRuleData->ValueForPaddingBottom();
6894 ourPadding.mLeft = *aRuleData->ValueForPaddingLeftValue();
6895 AdjustLogicalBoxProp(aContext,
6896 *aRuleData->ValueForPaddingLeftLTRSource(),
6897 *aRuleData->ValueForPaddingLeftRTLSource(),
6898 *aRuleData->ValueForPaddingStartValue(),
6899 *aRuleData->ValueForPaddingEndValue(),
6900 NS_SIDE_LEFT, ourPadding, canStoreInRuleTree);
6901 AdjustLogicalBoxProp(aContext,
6902 *aRuleData->ValueForPaddingRightLTRSource(),
6903 *aRuleData->ValueForPaddingRightRTLSource(),
6904 *aRuleData->ValueForPaddingEndValue(),
6905 *aRuleData->ValueForPaddingStartValue(),
6906 NS_SIDE_RIGHT, ourPadding, canStoreInRuleTree);
6907 NS_FOR_CSS_SIDES(side) {
6908 nsStyleCoord parentCoord = parentPadding->mPadding.Get(side);
6909 if (SetCoord(ourPadding.*(nsCSSRect::sides[side]),
6910 coord, parentCoord,
6911 SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
6912 SETCOORD_UNSET_INITIAL,
6913 aContext, mPresContext, canStoreInRuleTree)) {
6914 padding->mPadding.Set(side, coord);
6918 padding->RecalcData();
6919 COMPUTE_END_RESET(Padding, padding)
6922 const void*
6923 nsRuleNode::ComputeOutlineData(void* aStartStruct,
6924 const nsRuleData* aRuleData,
6925 nsStyleContext* aContext,
6926 nsRuleNode* aHighestNode,
6927 const RuleDetail aRuleDetail,
6928 const bool aCanStoreInRuleTree)
6930 COMPUTE_START_RESET(Outline, (mPresContext), outline, parentOutline)
6932 // outline-width: length, enum, inherit
6933 const nsCSSValue* outlineWidthValue = aRuleData->ValueForOutlineWidth();
6934 if (eCSSUnit_Initial == outlineWidthValue->GetUnit() ||
6935 eCSSUnit_Unset == outlineWidthValue->GetUnit()) {
6936 outline->mOutlineWidth =
6937 nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
6939 else {
6940 SetCoord(*outlineWidthValue, outline->mOutlineWidth,
6941 parentOutline->mOutlineWidth,
6942 SETCOORD_LEH | SETCOORD_CALC_LENGTH_ONLY, aContext,
6943 mPresContext, canStoreInRuleTree);
6946 // outline-offset: length, inherit
6947 nsStyleCoord tempCoord;
6948 const nsCSSValue* outlineOffsetValue = aRuleData->ValueForOutlineOffset();
6949 if (SetCoord(*outlineOffsetValue, tempCoord,
6950 nsStyleCoord(parentOutline->mOutlineOffset,
6951 nsStyleCoord::CoordConstructor),
6952 SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
6953 SETCOORD_UNSET_INITIAL,
6954 aContext, mPresContext, canStoreInRuleTree)) {
6955 outline->mOutlineOffset = tempCoord.GetCoordValue();
6956 } else {
6957 NS_ASSERTION(outlineOffsetValue->GetUnit() == eCSSUnit_Null,
6958 "unexpected unit");
6961 // outline-color: color, string, enum, inherit
6962 nscolor outlineColor;
6963 nscolor unused = NS_RGB(0,0,0);
6964 const nsCSSValue* outlineColorValue = aRuleData->ValueForOutlineColor();
6965 if (eCSSUnit_Inherit == outlineColorValue->GetUnit()) {
6966 canStoreInRuleTree = false;
6967 if (parentContext) {
6968 if (parentOutline->GetOutlineColor(outlineColor))
6969 outline->SetOutlineColor(outlineColor);
6970 else {
6971 // We want to inherit the color from the parent, not use the
6972 // color on the element where this chunk of style data will be
6973 // used. We can ensure that the data for the parent are fully
6974 // computed (unlike for the element where this will be used, for
6975 // which the color could be specified on a more specific rule).
6976 outline->SetOutlineColor(parentContext->StyleColor()->mColor);
6978 } else {
6979 outline->SetOutlineInitialColor();
6982 else if (SetColor(*outlineColorValue, unused, mPresContext,
6983 aContext, outlineColor, canStoreInRuleTree))
6984 outline->SetOutlineColor(outlineColor);
6985 else if (eCSSUnit_Enumerated == outlineColorValue->GetUnit() ||
6986 eCSSUnit_Initial == outlineColorValue->GetUnit() ||
6987 eCSSUnit_Unset == outlineColorValue->GetUnit()) {
6988 outline->SetOutlineInitialColor();
6991 // -moz-outline-radius: length, percent, inherit
6993 const nsCSSProperty* subprops =
6994 nsCSSProps::SubpropertyEntryFor(eCSSProperty__moz_outline_radius);
6995 NS_FOR_CSS_FULL_CORNERS(corner) {
6996 int cx = NS_FULL_TO_HALF_CORNER(corner, false);
6997 int cy = NS_FULL_TO_HALF_CORNER(corner, true);
6998 const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
6999 nsStyleCoord parentX = parentOutline->mOutlineRadius.Get(cx);
7000 nsStyleCoord parentY = parentOutline->mOutlineRadius.Get(cy);
7001 nsStyleCoord coordX, coordY;
7003 if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
7004 SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
7005 SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
7006 aContext, mPresContext, canStoreInRuleTree)) {
7007 outline->mOutlineRadius.Set(cx, coordX);
7008 outline->mOutlineRadius.Set(cy, coordY);
7013 // outline-style: enum, inherit, initial
7014 // cannot use SetDiscrete because of SetOutlineStyle
7015 const nsCSSValue* outlineStyleValue = aRuleData->ValueForOutlineStyle();
7016 nsCSSUnit unit = outlineStyleValue->GetUnit();
7017 NS_ABORT_IF_FALSE(eCSSUnit_None != unit && eCSSUnit_Auto != unit,
7018 "'none' and 'auto' should be handled as enumerated values");
7019 if (eCSSUnit_Enumerated == unit) {
7020 outline->SetOutlineStyle(outlineStyleValue->GetIntValue());
7021 } else if (eCSSUnit_Initial == unit ||
7022 eCSSUnit_Unset == unit) {
7023 outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_NONE);
7024 } else if (eCSSUnit_Inherit == unit) {
7025 canStoreInRuleTree = false;
7026 outline->SetOutlineStyle(parentOutline->GetOutlineStyle());
7029 outline->RecalcData(mPresContext);
7030 COMPUTE_END_RESET(Outline, outline)
7033 const void*
7034 nsRuleNode::ComputeListData(void* aStartStruct,
7035 const nsRuleData* aRuleData,
7036 nsStyleContext* aContext,
7037 nsRuleNode* aHighestNode,
7038 const RuleDetail aRuleDetail,
7039 const bool aCanStoreInRuleTree)
7041 COMPUTE_START_INHERITED(List, (mPresContext), list, parentList)
7043 // list-style-type: string, none, inherit, initial
7044 const nsCSSValue* typeValue = aRuleData->ValueForListStyleType();
7045 switch (typeValue->GetUnit()) {
7046 case eCSSUnit_Unset:
7047 case eCSSUnit_Inherit: {
7048 canStoreInRuleTree = false;
7049 nsString type;
7050 parentList->GetListStyleType(type);
7051 list->SetListStyleType(type, parentList->GetCounterStyle());
7052 break;
7054 case eCSSUnit_Initial:
7055 list->SetListStyleType(NS_LITERAL_STRING("disc"), mPresContext);
7056 break;
7057 case eCSSUnit_Ident: {
7058 nsString typeIdent;
7059 typeValue->GetStringValue(typeIdent);
7060 list->SetListStyleType(typeIdent, mPresContext);
7061 break;
7063 case eCSSUnit_Enumerated: {
7064 // For compatibility with html attribute map.
7065 // This branch should never be called for value from CSS.
7066 int32_t intValue = typeValue->GetIntValue();
7067 nsAutoString name;
7068 switch (intValue) {
7069 case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
7070 name.AssignLiteral(MOZ_UTF16("lower-roman"));
7071 break;
7072 case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
7073 name.AssignLiteral(MOZ_UTF16("upper-roman"));
7074 break;
7075 case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
7076 name.AssignLiteral(MOZ_UTF16("lower-alpha"));
7077 break;
7078 case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
7079 name.AssignLiteral(MOZ_UTF16("upper-alpha"));
7080 break;
7081 default:
7082 CopyASCIItoUTF16(nsCSSProps::ValueToKeyword(
7083 intValue, nsCSSProps::kListStyleKTable), name);
7084 break;
7086 list->SetListStyleType(name, mPresContext);
7087 break;
7089 case eCSSUnit_Null:
7090 break;
7091 default:
7092 NS_NOTREACHED("Unexpected value unit");
7095 // list-style-image: url, none, inherit
7096 const nsCSSValue* imageValue = aRuleData->ValueForListStyleImage();
7097 if (eCSSUnit_Image == imageValue->GetUnit()) {
7098 NS_SET_IMAGE_REQUEST_WITH_DOC(list->SetListStyleImage,
7099 aContext,
7100 imageValue->GetImageValue)
7102 else if (eCSSUnit_None == imageValue->GetUnit() ||
7103 eCSSUnit_Initial == imageValue->GetUnit()) {
7104 list->SetListStyleImage(nullptr);
7106 else if (eCSSUnit_Inherit == imageValue->GetUnit() ||
7107 eCSSUnit_Unset == imageValue->GetUnit()) {
7108 canStoreInRuleTree = false;
7109 NS_SET_IMAGE_REQUEST(list->SetListStyleImage,
7110 aContext,
7111 parentList->GetListStyleImage())
7114 // list-style-position: enum, inherit, initial
7115 SetDiscrete(*aRuleData->ValueForListStylePosition(),
7116 list->mListStylePosition, canStoreInRuleTree,
7117 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
7118 parentList->mListStylePosition,
7119 NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, 0, 0, 0, 0);
7121 // image region property: length, auto, inherit
7122 const nsCSSValue* imageRegionValue = aRuleData->ValueForImageRegion();
7123 switch (imageRegionValue->GetUnit()) {
7124 case eCSSUnit_Inherit:
7125 case eCSSUnit_Unset:
7126 canStoreInRuleTree = false;
7127 list->mImageRegion = parentList->mImageRegion;
7128 break;
7130 case eCSSUnit_Initial:
7131 case eCSSUnit_Auto:
7132 list->mImageRegion.SetRect(0,0,0,0);
7133 break;
7135 case eCSSUnit_Null:
7136 break;
7138 case eCSSUnit_Rect: {
7139 const nsCSSRect& rgnRect = imageRegionValue->GetRectValue();
7141 if (rgnRect.mTop.GetUnit() == eCSSUnit_Auto)
7142 list->mImageRegion.y = 0;
7143 else if (rgnRect.mTop.IsLengthUnit())
7144 list->mImageRegion.y =
7145 CalcLength(rgnRect.mTop, aContext, mPresContext, canStoreInRuleTree);
7147 if (rgnRect.mBottom.GetUnit() == eCSSUnit_Auto)
7148 list->mImageRegion.height = 0;
7149 else if (rgnRect.mBottom.IsLengthUnit())
7150 list->mImageRegion.height =
7151 CalcLength(rgnRect.mBottom, aContext, mPresContext,
7152 canStoreInRuleTree) - list->mImageRegion.y;
7154 if (rgnRect.mLeft.GetUnit() == eCSSUnit_Auto)
7155 list->mImageRegion.x = 0;
7156 else if (rgnRect.mLeft.IsLengthUnit())
7157 list->mImageRegion.x =
7158 CalcLength(rgnRect.mLeft, aContext, mPresContext, canStoreInRuleTree);
7160 if (rgnRect.mRight.GetUnit() == eCSSUnit_Auto)
7161 list->mImageRegion.width = 0;
7162 else if (rgnRect.mRight.IsLengthUnit())
7163 list->mImageRegion.width =
7164 CalcLength(rgnRect.mRight, aContext, mPresContext,
7165 canStoreInRuleTree) - list->mImageRegion.x;
7166 break;
7169 default:
7170 NS_ABORT_IF_FALSE(false, "unrecognized image-region unit");
7173 COMPUTE_END_INHERITED(List, list)
7176 static void
7177 SetGridTrackBreadth(const nsCSSValue& aValue,
7178 nsStyleCoord& aResult,
7179 nsStyleContext* aStyleContext,
7180 nsPresContext* aPresContext,
7181 bool& aCanStoreInRuleTree)
7183 nsCSSUnit unit = aValue.GetUnit();
7184 if (unit == eCSSUnit_FlexFraction) {
7185 aResult.SetFlexFractionValue(aValue.GetFloatValue());
7186 } else {
7187 MOZ_ASSERT(unit != eCSSUnit_Inherit && unit != eCSSUnit_Unset,
7188 "Unexpected value that would use dummyParentCoord");
7189 const nsStyleCoord dummyParentCoord;
7190 SetCoord(aValue, aResult, dummyParentCoord,
7191 SETCOORD_LPE | SETCOORD_STORE_CALC,
7192 aStyleContext, aPresContext, aCanStoreInRuleTree);
7196 static void
7197 SetGridTrackSize(const nsCSSValue& aValue,
7198 nsStyleCoord& aResultMin,
7199 nsStyleCoord& aResultMax,
7200 nsStyleContext* aStyleContext,
7201 nsPresContext* aPresContext,
7202 bool& aCanStoreInRuleTree)
7204 if (aValue.GetUnit() == eCSSUnit_Function) {
7205 // A minmax() function.
7206 nsCSSValue::Array* func = aValue.GetArrayValue();
7207 NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_minmax,
7208 "Expected minmax(), got another function name");
7209 SetGridTrackBreadth(func->Item(1), aResultMin,
7210 aStyleContext, aPresContext, aCanStoreInRuleTree);
7211 SetGridTrackBreadth(func->Item(2), aResultMax,
7212 aStyleContext, aPresContext, aCanStoreInRuleTree);
7213 } else if (aValue.GetUnit() == eCSSUnit_Auto) {
7214 // 'auto' computes to 'minmax(min-content, max-content)'
7215 aResultMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
7216 eStyleUnit_Enumerated);
7217 aResultMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
7218 eStyleUnit_Enumerated);
7219 } else {
7220 // A single <track-breadth>,
7221 // specifies identical min and max sizing functions.
7222 SetGridTrackBreadth(aValue, aResultMin,
7223 aStyleContext, aPresContext, aCanStoreInRuleTree);
7224 aResultMax = aResultMin;
7228 static void
7229 SetGridAutoColumnsRows(const nsCSSValue& aValue,
7230 nsStyleCoord& aResultMin,
7231 nsStyleCoord& aResultMax,
7232 const nsStyleCoord& aParentValueMin,
7233 const nsStyleCoord& aParentValueMax,
7234 nsStyleContext* aStyleContext,
7235 nsPresContext* aPresContext,
7236 bool& aCanStoreInRuleTree)
7239 switch (aValue.GetUnit()) {
7240 case eCSSUnit_Null:
7241 break;
7243 case eCSSUnit_Inherit:
7244 aCanStoreInRuleTree = false;
7245 aResultMin = aParentValueMin;
7246 aResultMax = aParentValueMax;
7247 break;
7249 case eCSSUnit_Initial:
7250 case eCSSUnit_Unset:
7251 // The initial value is 'auto',
7252 // which computes to 'minmax(min-content, max-content)'.
7253 // (Explicitly-specified 'auto' values are handled in SetGridTrackSize.)
7254 aResultMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
7255 eStyleUnit_Enumerated);
7256 aResultMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
7257 eStyleUnit_Enumerated);
7258 break;
7260 default:
7261 SetGridTrackSize(aValue, aResultMin, aResultMax,
7262 aStyleContext, aPresContext, aCanStoreInRuleTree);
7266 static void
7267 AppendGridLineNames(const nsCSSValue& aValue,
7268 nsStyleGridTemplate& aResult)
7270 // Compute a <line-names> value
7271 nsTArray<nsString>* nameList = aResult.mLineNameLists.AppendElement();
7272 // Null unit means empty list, nothing more to do.
7273 if (aValue.GetUnit() != eCSSUnit_Null) {
7274 const nsCSSValueList* item = aValue.GetListValue();
7275 do {
7276 nsString* name = nameList->AppendElement();
7277 item->mValue.GetStringValue(*name);
7278 item = item->mNext;
7279 } while (item);
7283 static void
7284 SetGridTrackList(const nsCSSValue& aValue,
7285 nsStyleGridTemplate& aResult,
7286 const nsStyleGridTemplate& aParentValue,
7287 nsStyleContext* aStyleContext,
7288 nsPresContext* aPresContext,
7289 bool& aCanStoreInRuleTree)
7292 switch (aValue.GetUnit()) {
7293 case eCSSUnit_Null:
7294 break;
7296 case eCSSUnit_Inherit:
7297 aCanStoreInRuleTree = false;
7298 aResult.mIsSubgrid = aParentValue.mIsSubgrid;
7299 aResult.mLineNameLists = aParentValue.mLineNameLists;
7300 aResult.mMinTrackSizingFunctions = aParentValue.mMinTrackSizingFunctions;
7301 aResult.mMaxTrackSizingFunctions = aParentValue.mMaxTrackSizingFunctions;
7302 break;
7304 case eCSSUnit_Initial:
7305 case eCSSUnit_Unset:
7306 case eCSSUnit_None:
7307 aResult.mIsSubgrid = false;
7308 aResult.mLineNameLists.Clear();
7309 aResult.mMinTrackSizingFunctions.Clear();
7310 aResult.mMaxTrackSizingFunctions.Clear();
7311 break;
7313 default:
7314 aResult.mLineNameLists.Clear();
7315 aResult.mMinTrackSizingFunctions.Clear();
7316 aResult.mMaxTrackSizingFunctions.Clear();
7317 const nsCSSValueList* item = aValue.GetListValue();
7318 if (item->mValue.GetUnit() == eCSSUnit_Enumerated &&
7319 item->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) {
7320 // subgrid <line-name-list>?
7321 aResult.mIsSubgrid = true;
7322 item = item->mNext;
7323 while (item) {
7324 AppendGridLineNames(item->mValue, aResult);
7325 item = item->mNext;
7327 } else {
7328 // <track-list>
7329 // The list is expected to have odd number of items, at least 3
7330 // starting with a <line-names> (sub list of identifiers),
7331 // and alternating between that and <track-size>.
7332 aResult.mIsSubgrid = false;
7333 for (;;) {
7334 AppendGridLineNames(item->mValue, aResult);
7335 item = item->mNext;
7337 if (!item) {
7338 break;
7341 nsStyleCoord& min = *aResult.mMinTrackSizingFunctions.AppendElement();
7342 nsStyleCoord& max = *aResult.mMaxTrackSizingFunctions.AppendElement();
7343 SetGridTrackSize(item->mValue, min, max,
7344 aStyleContext, aPresContext, aCanStoreInRuleTree);
7346 item = item->mNext;
7347 MOZ_ASSERT(item, "Expected a eCSSUnit_List of odd length");
7349 MOZ_ASSERT(!aResult.mMinTrackSizingFunctions.IsEmpty() &&
7350 aResult.mMinTrackSizingFunctions.Length() ==
7351 aResult.mMaxTrackSizingFunctions.Length() &&
7352 aResult.mMinTrackSizingFunctions.Length() + 1 ==
7353 aResult.mLineNameLists.Length(),
7354 "Inconstistent array lengths for nsStyleGridTemplate");
7359 static void
7360 SetGridTemplateAreas(const nsCSSValue& aValue,
7361 nsRefPtr<css::GridTemplateAreasValue>* aResult,
7362 css::GridTemplateAreasValue* aParentValue,
7363 bool& aCanStoreInRuleTree)
7365 switch (aValue.GetUnit()) {
7366 case eCSSUnit_Null:
7367 break;
7369 case eCSSUnit_Inherit:
7370 aCanStoreInRuleTree = false;
7371 *aResult = aParentValue;
7372 break;
7374 case eCSSUnit_Initial:
7375 case eCSSUnit_Unset:
7376 case eCSSUnit_None:
7377 *aResult = nullptr;
7378 break;
7380 default:
7381 *aResult = aValue.GetGridTemplateAreas();
7385 static void
7386 SetGridLine(const nsCSSValue& aValue,
7387 nsStyleGridLine& aResult,
7388 const nsStyleGridLine& aParentValue,
7389 bool& aCanStoreInRuleTree)
7392 switch (aValue.GetUnit()) {
7393 case eCSSUnit_Null:
7394 break;
7396 case eCSSUnit_Inherit:
7397 aCanStoreInRuleTree = false;
7398 aResult = aParentValue;
7399 break;
7401 case eCSSUnit_Initial:
7402 case eCSSUnit_Unset:
7403 case eCSSUnit_Auto:
7404 aResult.SetAuto();
7405 break;
7407 default:
7408 aResult.SetAuto(); // Reset any existing value.
7409 const nsCSSValueList* item = aValue.GetListValue();
7410 do {
7411 if (item->mValue.GetUnit() == eCSSUnit_Enumerated) {
7412 aResult.mHasSpan = true;
7413 } else if (item->mValue.GetUnit() == eCSSUnit_Integer) {
7414 aResult.mInteger = item->mValue.GetIntValue();
7415 } else if (item->mValue.GetUnit() == eCSSUnit_Ident) {
7416 item->mValue.GetStringValue(aResult.mLineName);
7417 } else {
7418 NS_ASSERTION(false, "Unexpected unit");
7420 item = item->mNext;
7421 } while (item);
7422 MOZ_ASSERT(!aResult.IsAuto(),
7423 "should have set something away from default value");
7427 const void*
7428 nsRuleNode::ComputePositionData(void* aStartStruct,
7429 const nsRuleData* aRuleData,
7430 nsStyleContext* aContext,
7431 nsRuleNode* aHighestNode,
7432 const RuleDetail aRuleDetail,
7433 const bool aCanStoreInRuleTree)
7435 COMPUTE_START_RESET(Position, (), pos, parentPos)
7437 // box offsets: length, percent, calc, auto, inherit
7438 static const nsCSSProperty offsetProps[] = {
7439 eCSSProperty_top,
7440 eCSSProperty_right,
7441 eCSSProperty_bottom,
7442 eCSSProperty_left
7444 nsStyleCoord coord;
7445 NS_FOR_CSS_SIDES(side) {
7446 nsStyleCoord parentCoord = parentPos->mOffset.Get(side);
7447 if (SetCoord(*aRuleData->ValueFor(offsetProps[side]),
7448 coord, parentCoord,
7449 SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
7450 SETCOORD_UNSET_INITIAL,
7451 aContext, mPresContext, canStoreInRuleTree)) {
7452 pos->mOffset.Set(side, coord);
7456 SetCoord(*aRuleData->ValueForWidth(), pos->mWidth, parentPos->mWidth,
7457 SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
7458 SETCOORD_UNSET_INITIAL,
7459 aContext, mPresContext, canStoreInRuleTree);
7460 SetCoord(*aRuleData->ValueForMinWidth(), pos->mMinWidth, parentPos->mMinWidth,
7461 SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
7462 SETCOORD_UNSET_INITIAL,
7463 aContext, mPresContext, canStoreInRuleTree);
7464 SetCoord(*aRuleData->ValueForMaxWidth(), pos->mMaxWidth, parentPos->mMaxWidth,
7465 SETCOORD_LPOEH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
7466 SETCOORD_UNSET_INITIAL,
7467 aContext, mPresContext, canStoreInRuleTree);
7469 SetCoord(*aRuleData->ValueForHeight(), pos->mHeight, parentPos->mHeight,
7470 SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
7471 SETCOORD_UNSET_INITIAL,
7472 aContext, mPresContext, canStoreInRuleTree);
7473 SetCoord(*aRuleData->ValueForMinHeight(), pos->mMinHeight, parentPos->mMinHeight,
7474 SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
7475 SETCOORD_UNSET_INITIAL,
7476 aContext, mPresContext, canStoreInRuleTree);
7477 SetCoord(*aRuleData->ValueForMaxHeight(), pos->mMaxHeight, parentPos->mMaxHeight,
7478 SETCOORD_LPOH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
7479 SETCOORD_UNSET_INITIAL,
7480 aContext, mPresContext, canStoreInRuleTree);
7482 // box-sizing: enum, inherit, initial
7483 SetDiscrete(*aRuleData->ValueForBoxSizing(),
7484 pos->mBoxSizing, canStoreInRuleTree,
7485 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
7486 parentPos->mBoxSizing,
7487 NS_STYLE_BOX_SIZING_CONTENT, 0, 0, 0, 0);
7489 // align-content: enum, inherit, initial
7490 SetDiscrete(*aRuleData->ValueForAlignContent(),
7491 pos->mAlignContent, canStoreInRuleTree,
7492 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
7493 parentPos->mAlignContent,
7494 NS_STYLE_ALIGN_CONTENT_STRETCH, 0, 0, 0, 0);
7496 // align-items: enum, inherit, initial
7497 SetDiscrete(*aRuleData->ValueForAlignItems(),
7498 pos->mAlignItems, canStoreInRuleTree,
7499 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
7500 parentPos->mAlignItems,
7501 NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE, 0, 0, 0, 0);
7503 // align-self: enum, inherit, initial
7504 // NOTE: align-self's initial value is the special keyword "auto", which is
7505 // supposed to compute to our parent's computed value of "align-items". So
7506 // technically, "auto" itself is never a valid computed value for align-self,
7507 // since it always computes to something else. Despite that, we do actually
7508 // store "auto" in nsStylePosition::mAlignSelf, as NS_STYLE_ALIGN_SELF_AUTO
7509 // (and then resolve it as-necessary). We do this because "auto" is the
7510 // initial value for this property, so if we were to actually resolve it in
7511 // nsStylePosition, we'd never be able to share any nsStylePosition structs
7512 // in the rule tree, since their mAlignSelf values would depend on the parent
7513 // style, by default.
7514 if (aRuleData->ValueForAlignSelf()->GetUnit() == eCSSUnit_Inherit) {
7515 // Special handling for "align-self: inherit", in case we're inheriting
7516 // "align-self: auto", in which case we need to resolve the parent's "auto"
7517 // and inherit that resolved value.
7518 uint8_t inheritedAlignSelf = parentPos->mAlignSelf;
7519 if (inheritedAlignSelf == NS_STYLE_ALIGN_SELF_AUTO) {
7520 if (!parentContext) {
7521 // We're the root node. Nothing to inherit from --> just use default
7522 // value.
7523 inheritedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
7524 } else {
7525 // Our parent's "auto" value should resolve to our grandparent's value
7526 // for "align-items". So, that's what we're supposed to inherit.
7527 nsStyleContext* grandparentContext = parentContext->GetParent();
7528 if (!grandparentContext) {
7529 // No grandparent --> our parent is the root node, so its
7530 // "align-self: auto" computes to the default "align-items" value:
7531 inheritedAlignSelf = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
7532 } else {
7533 // Normal case -- we have a grandparent.
7534 // Its "align-items" value is what we should end up inheriting.
7535 const nsStylePosition* grandparentPos =
7536 grandparentContext->StylePosition();
7537 inheritedAlignSelf = grandparentPos->mAlignItems;
7542 pos->mAlignSelf = inheritedAlignSelf;
7543 canStoreInRuleTree = false;
7544 } else {
7545 SetDiscrete(*aRuleData->ValueForAlignSelf(),
7546 pos->mAlignSelf, canStoreInRuleTree,
7547 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
7548 parentPos->mAlignSelf, // (unused -- we handled inherit above)
7549 NS_STYLE_ALIGN_SELF_AUTO, // initial == auto
7550 0, 0, 0, 0);
7553 // flex-basis: auto, length, percent, enum, calc, inherit, initial
7554 // (Note: The flags here should match those used for 'width' property above.)
7555 SetCoord(*aRuleData->ValueForFlexBasis(), pos->mFlexBasis, parentPos->mFlexBasis,
7556 SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
7557 SETCOORD_UNSET_INITIAL,
7558 aContext, mPresContext, canStoreInRuleTree);
7560 // flex-direction: enum, inherit, initial
7561 SetDiscrete(*aRuleData->ValueForFlexDirection(),
7562 pos->mFlexDirection, canStoreInRuleTree,
7563 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
7564 parentPos->mFlexDirection,
7565 NS_STYLE_FLEX_DIRECTION_ROW, 0, 0, 0, 0);
7567 // flex-grow: float, inherit, initial
7568 SetFactor(*aRuleData->ValueForFlexGrow(),
7569 pos->mFlexGrow, canStoreInRuleTree,
7570 parentPos->mFlexGrow, 0.0f,
7571 SETFCT_UNSET_INITIAL);
7573 // flex-shrink: float, inherit, initial
7574 SetFactor(*aRuleData->ValueForFlexShrink(),
7575 pos->mFlexShrink, canStoreInRuleTree,
7576 parentPos->mFlexShrink, 1.0f,
7577 SETFCT_UNSET_INITIAL);
7579 // flex-wrap: enum, inherit, initial
7580 SetDiscrete(*aRuleData->ValueForFlexWrap(),
7581 pos->mFlexWrap, canStoreInRuleTree,
7582 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
7583 parentPos->mFlexWrap,
7584 NS_STYLE_FLEX_WRAP_NOWRAP, 0, 0, 0, 0);
7586 // order: integer, inherit, initial
7587 SetDiscrete(*aRuleData->ValueForOrder(),
7588 pos->mOrder, canStoreInRuleTree,
7589 SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
7590 parentPos->mOrder,
7591 NS_STYLE_ORDER_INITIAL, 0, 0, 0, 0);
7593 // justify-content: enum, inherit, initial
7594 SetDiscrete(*aRuleData->ValueForJustifyContent(),
7595 pos->mJustifyContent, canStoreInRuleTree,
7596 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
7597 parentPos->mJustifyContent,
7598 NS_STYLE_JUSTIFY_CONTENT_FLEX_START, 0, 0, 0, 0);
7600 // grid-auto-flow
7601 const nsCSSValue& gridAutoFlow = *aRuleData->ValueForGridAutoFlow();
7602 switch (gridAutoFlow.GetUnit()) {
7603 case eCSSUnit_Null:
7604 break;
7605 case eCSSUnit_Inherit:
7606 canStoreInRuleTree = false;
7607 pos->mGridAutoFlow = parentPos->mGridAutoFlow;
7608 break;
7609 case eCSSUnit_Initial:
7610 case eCSSUnit_Unset:
7611 pos->mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_ROW;
7612 break;
7613 default:
7614 NS_ASSERTION(gridAutoFlow.GetUnit() == eCSSUnit_Enumerated,
7615 "Unexpected unit");
7616 pos->mGridAutoFlow = gridAutoFlow.GetIntValue();
7619 // grid-auto-columns
7620 SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoColumns(),
7621 pos->mGridAutoColumnsMin,
7622 pos->mGridAutoColumnsMax,
7623 parentPos->mGridAutoColumnsMin,
7624 parentPos->mGridAutoColumnsMax,
7625 aContext, mPresContext, canStoreInRuleTree);
7627 // grid-auto-rows
7628 SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoRows(),
7629 pos->mGridAutoRowsMin,
7630 pos->mGridAutoRowsMax,
7631 parentPos->mGridAutoRowsMin,
7632 parentPos->mGridAutoRowsMax,
7633 aContext, mPresContext, canStoreInRuleTree);
7635 // grid-template-columns
7636 SetGridTrackList(*aRuleData->ValueForGridTemplateColumns(),
7637 pos->mGridTemplateColumns, parentPos->mGridTemplateColumns,
7638 aContext, mPresContext, canStoreInRuleTree);
7640 // grid-template-rows
7641 SetGridTrackList(*aRuleData->ValueForGridTemplateRows(),
7642 pos->mGridTemplateRows, parentPos->mGridTemplateRows,
7643 aContext, mPresContext, canStoreInRuleTree);
7645 // grid-tempate-areas
7646 SetGridTemplateAreas(*aRuleData->ValueForGridTemplateAreas(),
7647 &pos->mGridTemplateAreas,
7648 parentPos->mGridTemplateAreas,
7649 canStoreInRuleTree);
7651 // grid-column-start
7652 SetGridLine(*aRuleData->ValueForGridColumnStart(),
7653 pos->mGridColumnStart,
7654 parentPos->mGridColumnStart,
7655 canStoreInRuleTree);
7657 // grid-column-end
7658 SetGridLine(*aRuleData->ValueForGridColumnEnd(),
7659 pos->mGridColumnEnd,
7660 parentPos->mGridColumnEnd,
7661 canStoreInRuleTree);
7663 // grid-row-start
7664 SetGridLine(*aRuleData->ValueForGridRowStart(),
7665 pos->mGridRowStart,
7666 parentPos->mGridRowStart,
7667 canStoreInRuleTree);
7669 // grid-row-end
7670 SetGridLine(*aRuleData->ValueForGridRowEnd(),
7671 pos->mGridRowEnd,
7672 parentPos->mGridRowEnd,
7673 canStoreInRuleTree);
7675 // z-index
7676 const nsCSSValue* zIndexValue = aRuleData->ValueForZIndex();
7677 if (! SetCoord(*zIndexValue, pos->mZIndex, parentPos->mZIndex,
7678 SETCOORD_IA | SETCOORD_INITIAL_AUTO | SETCOORD_UNSET_INITIAL,
7679 aContext, nullptr, canStoreInRuleTree)) {
7680 if (eCSSUnit_Inherit == zIndexValue->GetUnit()) {
7681 // handle inherit, because it's ok to inherit 'auto' here
7682 canStoreInRuleTree = false;
7683 pos->mZIndex = parentPos->mZIndex;
7687 COMPUTE_END_RESET(Position, pos)
7690 const void*
7691 nsRuleNode::ComputeTableData(void* aStartStruct,
7692 const nsRuleData* aRuleData,
7693 nsStyleContext* aContext,
7694 nsRuleNode* aHighestNode,
7695 const RuleDetail aRuleDetail,
7696 const bool aCanStoreInRuleTree)
7698 COMPUTE_START_RESET(Table, (), table, parentTable)
7700 // table-layout: enum, inherit, initial
7701 SetDiscrete(*aRuleData->ValueForTableLayout(),
7702 table->mLayoutStrategy, canStoreInRuleTree,
7703 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
7704 parentTable->mLayoutStrategy,
7705 NS_STYLE_TABLE_LAYOUT_AUTO, 0, 0, 0, 0);
7707 // span: pixels (not a real CSS prop)
7708 const nsCSSValue* spanValue = aRuleData->ValueForSpan();
7709 if (eCSSUnit_Enumerated == spanValue->GetUnit() ||
7710 eCSSUnit_Integer == spanValue->GetUnit())
7711 table->mSpan = spanValue->GetIntValue();
7713 COMPUTE_END_RESET(Table, table)
7716 const void*
7717 nsRuleNode::ComputeTableBorderData(void* aStartStruct,
7718 const nsRuleData* aRuleData,
7719 nsStyleContext* aContext,
7720 nsRuleNode* aHighestNode,
7721 const RuleDetail aRuleDetail,
7722 const bool aCanStoreInRuleTree)
7724 COMPUTE_START_INHERITED(TableBorder, (mPresContext), table, parentTable)
7726 // border-collapse: enum, inherit, initial
7727 SetDiscrete(*aRuleData->ValueForBorderCollapse(), table->mBorderCollapse,
7728 canStoreInRuleTree,
7729 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
7730 parentTable->mBorderCollapse,
7731 NS_STYLE_BORDER_SEPARATE, 0, 0, 0, 0);
7733 const nsCSSValue* borderSpacingValue = aRuleData->ValueForBorderSpacing();
7734 if (borderSpacingValue->GetUnit() != eCSSUnit_Null) {
7735 // border-spacing-x/y: length, inherit
7736 nsStyleCoord parentX(parentTable->mBorderSpacingX,
7737 nsStyleCoord::CoordConstructor);
7738 nsStyleCoord parentY(parentTable->mBorderSpacingY,
7739 nsStyleCoord::CoordConstructor);
7740 nsStyleCoord coordX, coordY;
7742 #ifdef DEBUG
7743 bool result =
7744 #endif
7745 SetPairCoords(*borderSpacingValue,
7746 coordX, coordY, parentX, parentY,
7747 SETCOORD_LH | SETCOORD_INITIAL_ZERO |
7748 SETCOORD_CALC_LENGTH_ONLY |
7749 SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INHERIT,
7750 aContext, mPresContext, canStoreInRuleTree);
7751 NS_ASSERTION(result, "malformed table border value");
7752 table->mBorderSpacingX = coordX.GetCoordValue();
7753 table->mBorderSpacingY = coordY.GetCoordValue();
7756 // caption-side: enum, inherit, initial
7757 SetDiscrete(*aRuleData->ValueForCaptionSide(),
7758 table->mCaptionSide, canStoreInRuleTree,
7759 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
7760 parentTable->mCaptionSide,
7761 NS_STYLE_CAPTION_SIDE_TOP, 0, 0, 0, 0);
7763 // empty-cells: enum, inherit, initial
7764 SetDiscrete(*aRuleData->ValueForEmptyCells(),
7765 table->mEmptyCells, canStoreInRuleTree,
7766 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
7767 parentTable->mEmptyCells,
7768 (mPresContext->CompatibilityMode() == eCompatibility_NavQuirks)
7769 ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
7770 : NS_STYLE_TABLE_EMPTY_CELLS_SHOW,
7771 0, 0, 0, 0);
7773 COMPUTE_END_INHERITED(TableBorder, table)
7776 const void*
7777 nsRuleNode::ComputeContentData(void* aStartStruct,
7778 const nsRuleData* aRuleData,
7779 nsStyleContext* aContext,
7780 nsRuleNode* aHighestNode,
7781 const RuleDetail aRuleDetail,
7782 const bool aCanStoreInRuleTree)
7784 uint32_t count;
7785 nsAutoString buffer;
7787 COMPUTE_START_RESET(Content, (), content, parentContent)
7789 // content: [string, url, counter, attr, enum]+, normal, none, inherit
7790 const nsCSSValue* contentValue = aRuleData->ValueForContent();
7791 switch (contentValue->GetUnit()) {
7792 case eCSSUnit_Null:
7793 break;
7795 case eCSSUnit_Normal:
7796 case eCSSUnit_None:
7797 case eCSSUnit_Initial:
7798 case eCSSUnit_Unset:
7799 // "normal", "none", "initial" and "unset" all mean no content
7800 content->AllocateContents(0);
7801 break;
7803 case eCSSUnit_Inherit:
7804 canStoreInRuleTree = false;
7805 count = parentContent->ContentCount();
7806 if (NS_SUCCEEDED(content->AllocateContents(count))) {
7807 while (0 < count--) {
7808 content->ContentAt(count) = parentContent->ContentAt(count);
7811 break;
7813 case eCSSUnit_Enumerated: {
7814 NS_ABORT_IF_FALSE(contentValue->GetIntValue() ==
7815 NS_STYLE_CONTENT_ALT_CONTENT,
7816 "unrecognized solitary content keyword");
7817 content->AllocateContents(1);
7818 nsStyleContentData& data = content->ContentAt(0);
7819 data.mType = eStyleContentType_AltContent;
7820 data.mContent.mString = nullptr;
7821 break;
7824 case eCSSUnit_List:
7825 case eCSSUnit_ListDep: {
7826 const nsCSSValueList* contentValueList = contentValue->GetListValue();
7827 count = 0;
7828 while (contentValueList) {
7829 count++;
7830 contentValueList = contentValueList->mNext;
7832 if (NS_SUCCEEDED(content->AllocateContents(count))) {
7833 const nsAutoString nullStr;
7834 count = 0;
7835 contentValueList = contentValue->GetListValue();
7836 while (contentValueList) {
7837 const nsCSSValue& value = contentValueList->mValue;
7838 nsCSSUnit unit = value.GetUnit();
7839 nsStyleContentType type;
7840 nsStyleContentData &data = content->ContentAt(count++);
7841 switch (unit) {
7842 case eCSSUnit_String: type = eStyleContentType_String; break;
7843 case eCSSUnit_Image: type = eStyleContentType_Image; break;
7844 case eCSSUnit_Attr: type = eStyleContentType_Attr; break;
7845 case eCSSUnit_Counter: type = eStyleContentType_Counter; break;
7846 case eCSSUnit_Counters: type = eStyleContentType_Counters; break;
7847 case eCSSUnit_Enumerated:
7848 switch (value.GetIntValue()) {
7849 case NS_STYLE_CONTENT_OPEN_QUOTE:
7850 type = eStyleContentType_OpenQuote; break;
7851 case NS_STYLE_CONTENT_CLOSE_QUOTE:
7852 type = eStyleContentType_CloseQuote; break;
7853 case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
7854 type = eStyleContentType_NoOpenQuote; break;
7855 case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
7856 type = eStyleContentType_NoCloseQuote; break;
7857 default:
7858 NS_ERROR("bad content value");
7859 type = eStyleContentType_Uninitialized;
7861 break;
7862 default:
7863 NS_ERROR("bad content type");
7864 type = eStyleContentType_Uninitialized;
7866 data.mType = type;
7867 if (type == eStyleContentType_Image) {
7868 NS_SET_IMAGE_REQUEST_WITH_DOC(data.SetImage,
7869 aContext,
7870 value.GetImageValue);
7872 else if (type <= eStyleContentType_Attr) {
7873 value.GetStringValue(buffer);
7874 data.mContent.mString = NS_strdup(buffer.get());
7876 else if (type <= eStyleContentType_Counters) {
7877 data.mContent.mCounters = value.GetArrayValue();
7878 data.mContent.mCounters->AddRef();
7880 else {
7881 data.mContent.mString = nullptr;
7883 contentValueList = contentValueList->mNext;
7886 break;
7889 default:
7890 NS_ABORT_IF_FALSE(false,
7891 nsPrintfCString("unrecognized content unit %d",
7892 contentValue->GetUnit()).get());
7895 // counter-increment: [string [int]]+, none, inherit
7896 const nsCSSValue* counterIncrementValue =
7897 aRuleData->ValueForCounterIncrement();
7898 switch (counterIncrementValue->GetUnit()) {
7899 case eCSSUnit_Null:
7900 break;
7902 case eCSSUnit_None:
7903 case eCSSUnit_Initial:
7904 case eCSSUnit_Unset:
7905 content->AllocateCounterIncrements(0);
7906 break;
7908 case eCSSUnit_Inherit:
7909 canStoreInRuleTree = false;
7910 count = parentContent->CounterIncrementCount();
7911 if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
7912 while (0 < count--) {
7913 const nsStyleCounterData *data =
7914 parentContent->GetCounterIncrementAt(count);
7915 content->SetCounterIncrementAt(count, data->mCounter, data->mValue);
7918 break;
7920 case eCSSUnit_PairList:
7921 case eCSSUnit_PairListDep: {
7922 const nsCSSValuePairList* ourIncrement =
7923 counterIncrementValue->GetPairListValue();
7924 NS_ABORT_IF_FALSE(ourIncrement->mXValue.GetUnit() == eCSSUnit_Ident,
7925 "unexpected value unit");
7926 count = ListLength(ourIncrement);
7927 if (NS_FAILED(content->AllocateCounterIncrements(count))) {
7928 break;
7931 count = 0;
7932 for (const nsCSSValuePairList* p = ourIncrement; p; p = p->mNext, count++) {
7933 int32_t increment;
7934 if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
7935 increment = p->mYValue.GetIntValue();
7936 } else {
7937 increment = 1;
7939 p->mXValue.GetStringValue(buffer);
7940 content->SetCounterIncrementAt(count, buffer, increment);
7942 break;
7945 default:
7946 NS_ABORT_IF_FALSE(false, "unexpected value unit");
7949 // counter-reset: [string [int]]+, none, inherit
7950 const nsCSSValue* counterResetValue = aRuleData->ValueForCounterReset();
7951 switch (counterResetValue->GetUnit()) {
7952 case eCSSUnit_Null:
7953 break;
7955 case eCSSUnit_None:
7956 case eCSSUnit_Initial:
7957 case eCSSUnit_Unset:
7958 content->AllocateCounterResets(0);
7959 break;
7961 case eCSSUnit_Inherit:
7962 canStoreInRuleTree = false;
7963 count = parentContent->CounterResetCount();
7964 if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
7965 while (0 < count--) {
7966 const nsStyleCounterData *data =
7967 parentContent->GetCounterResetAt(count);
7968 content->SetCounterResetAt(count, data->mCounter, data->mValue);
7971 break;
7973 case eCSSUnit_PairList:
7974 case eCSSUnit_PairListDep: {
7975 const nsCSSValuePairList* ourReset =
7976 counterResetValue->GetPairListValue();
7977 NS_ABORT_IF_FALSE(ourReset->mXValue.GetUnit() == eCSSUnit_Ident,
7978 "unexpected value unit");
7979 count = ListLength(ourReset);
7980 if (NS_FAILED(content->AllocateCounterResets(count))) {
7981 break;
7984 count = 0;
7985 for (const nsCSSValuePairList* p = ourReset; p; p = p->mNext, count++) {
7986 int32_t reset;
7987 if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
7988 reset = p->mYValue.GetIntValue();
7989 } else {
7990 reset = 0;
7992 p->mXValue.GetStringValue(buffer);
7993 content->SetCounterResetAt(count, buffer, reset);
7995 break;
7998 default:
7999 NS_ABORT_IF_FALSE(false, "unexpected value unit");
8002 // marker-offset: length, auto, inherit
8003 SetCoord(*aRuleData->ValueForMarkerOffset(), content->mMarkerOffset, parentContent->mMarkerOffset,
8004 SETCOORD_LH | SETCOORD_AUTO | SETCOORD_INITIAL_AUTO |
8005 SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INITIAL,
8006 aContext, mPresContext, canStoreInRuleTree);
8008 // If we ended up with an image, track it.
8009 for (uint32_t i = 0; i < content->ContentCount(); ++i) {
8010 if ((content->ContentAt(i).mType == eStyleContentType_Image) &&
8011 content->ContentAt(i).mContent.mImage) {
8012 content->ContentAt(i).TrackImage(aContext->PresContext());
8016 COMPUTE_END_RESET(Content, content)
8019 const void*
8020 nsRuleNode::ComputeQuotesData(void* aStartStruct,
8021 const nsRuleData* aRuleData,
8022 nsStyleContext* aContext,
8023 nsRuleNode* aHighestNode,
8024 const RuleDetail aRuleDetail,
8025 const bool aCanStoreInRuleTree)
8027 COMPUTE_START_INHERITED(Quotes, (), quotes, parentQuotes)
8029 // quotes: inherit, initial, none, [string string]+
8030 const nsCSSValue* quotesValue = aRuleData->ValueForQuotes();
8031 switch (quotesValue->GetUnit()) {
8032 case eCSSUnit_Null:
8033 break;
8034 case eCSSUnit_Inherit:
8035 case eCSSUnit_Unset:
8036 canStoreInRuleTree = false;
8037 quotes->CopyFrom(*parentQuotes);
8038 break;
8039 case eCSSUnit_Initial:
8040 quotes->SetInitial();
8041 break;
8042 case eCSSUnit_None:
8043 quotes->AllocateQuotes(0);
8044 break;
8045 case eCSSUnit_PairList:
8046 case eCSSUnit_PairListDep: {
8047 const nsCSSValuePairList* ourQuotes
8048 = quotesValue->GetPairListValue();
8049 nsAutoString buffer;
8050 nsAutoString closeBuffer;
8051 uint32_t count = ListLength(ourQuotes);
8052 if (NS_FAILED(quotes->AllocateQuotes(count))) {
8053 break;
8055 count = 0;
8056 while (ourQuotes) {
8057 NS_ABORT_IF_FALSE(ourQuotes->mXValue.GetUnit() == eCSSUnit_String &&
8058 ourQuotes->mYValue.GetUnit() == eCSSUnit_String,
8059 "improper list contents for quotes");
8060 ourQuotes->mXValue.GetStringValue(buffer);
8061 ourQuotes->mYValue.GetStringValue(closeBuffer);
8062 quotes->SetQuotesAt(count++, buffer, closeBuffer);
8063 ourQuotes = ourQuotes->mNext;
8065 break;
8067 default:
8068 NS_ABORT_IF_FALSE(false, "unexpected value unit");
8071 COMPUTE_END_INHERITED(Quotes, quotes)
8074 const void*
8075 nsRuleNode::ComputeXULData(void* aStartStruct,
8076 const nsRuleData* aRuleData,
8077 nsStyleContext* aContext,
8078 nsRuleNode* aHighestNode,
8079 const RuleDetail aRuleDetail,
8080 const bool aCanStoreInRuleTree)
8082 COMPUTE_START_RESET(XUL, (), xul, parentXUL)
8084 // box-align: enum, inherit, initial
8085 SetDiscrete(*aRuleData->ValueForBoxAlign(),
8086 xul->mBoxAlign, canStoreInRuleTree,
8087 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
8088 parentXUL->mBoxAlign,
8089 NS_STYLE_BOX_ALIGN_STRETCH, 0, 0, 0, 0);
8091 // box-direction: enum, inherit, initial
8092 SetDiscrete(*aRuleData->ValueForBoxDirection(),
8093 xul->mBoxDirection, canStoreInRuleTree,
8094 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
8095 parentXUL->mBoxDirection,
8096 NS_STYLE_BOX_DIRECTION_NORMAL, 0, 0, 0, 0);
8098 // box-flex: factor, inherit
8099 SetFactor(*aRuleData->ValueForBoxFlex(),
8100 xul->mBoxFlex, canStoreInRuleTree,
8101 parentXUL->mBoxFlex, 0.0f,
8102 SETFCT_UNSET_INITIAL);
8104 // box-orient: enum, inherit, initial
8105 SetDiscrete(*aRuleData->ValueForBoxOrient(),
8106 xul->mBoxOrient, canStoreInRuleTree,
8107 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
8108 parentXUL->mBoxOrient,
8109 NS_STYLE_BOX_ORIENT_HORIZONTAL, 0, 0, 0, 0);
8111 // box-pack: enum, inherit, initial
8112 SetDiscrete(*aRuleData->ValueForBoxPack(),
8113 xul->mBoxPack, canStoreInRuleTree,
8114 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
8115 parentXUL->mBoxPack,
8116 NS_STYLE_BOX_PACK_START, 0, 0, 0, 0);
8118 // box-ordinal-group: integer, inherit, initial
8119 SetDiscrete(*aRuleData->ValueForBoxOrdinalGroup(),
8120 xul->mBoxOrdinal, canStoreInRuleTree,
8121 SETDSC_INTEGER | SETDSC_UNSET_INITIAL,
8122 parentXUL->mBoxOrdinal, 1,
8123 0, 0, 0, 0);
8125 const nsCSSValue* stackSizingValue = aRuleData->ValueForStackSizing();
8126 if (eCSSUnit_Inherit == stackSizingValue->GetUnit()) {
8127 canStoreInRuleTree = false;
8128 xul->mStretchStack = parentXUL->mStretchStack;
8129 } else if (eCSSUnit_Initial == stackSizingValue->GetUnit() ||
8130 eCSSUnit_Unset == stackSizingValue->GetUnit()) {
8131 xul->mStretchStack = true;
8132 } else if (eCSSUnit_Enumerated == stackSizingValue->GetUnit()) {
8133 xul->mStretchStack = stackSizingValue->GetIntValue() ==
8134 NS_STYLE_STACK_SIZING_STRETCH_TO_FIT;
8137 COMPUTE_END_RESET(XUL, xul)
8140 const void*
8141 nsRuleNode::ComputeColumnData(void* aStartStruct,
8142 const nsRuleData* aRuleData,
8143 nsStyleContext* aContext,
8144 nsRuleNode* aHighestNode,
8145 const RuleDetail aRuleDetail,
8146 const bool aCanStoreInRuleTree)
8148 COMPUTE_START_RESET(Column, (mPresContext), column, parent)
8150 // column-width: length, auto, inherit
8151 SetCoord(*aRuleData->ValueForColumnWidth(),
8152 column->mColumnWidth, parent->mColumnWidth,
8153 SETCOORD_LAH | SETCOORD_INITIAL_AUTO |
8154 SETCOORD_CALC_LENGTH_ONLY | SETCOORD_CALC_CLAMP_NONNEGATIVE |
8155 SETCOORD_UNSET_INITIAL,
8156 aContext, mPresContext, canStoreInRuleTree);
8158 // column-gap: length, inherit, normal
8159 SetCoord(*aRuleData->ValueForColumnGap(),
8160 column->mColumnGap, parent->mColumnGap,
8161 SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
8162 SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INITIAL,
8163 aContext, mPresContext, canStoreInRuleTree);
8164 // clamp negative calc() to 0
8165 if (column->mColumnGap.GetUnit() == eStyleUnit_Coord) {
8166 column->mColumnGap.SetCoordValue(
8167 std::max(column->mColumnGap.GetCoordValue(), 0));
8170 // column-count: auto, integer, inherit
8171 const nsCSSValue* columnCountValue = aRuleData->ValueForColumnCount();
8172 if (eCSSUnit_Auto == columnCountValue->GetUnit() ||
8173 eCSSUnit_Initial == columnCountValue->GetUnit() ||
8174 eCSSUnit_Unset == columnCountValue->GetUnit()) {
8175 column->mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
8176 } else if (eCSSUnit_Integer == columnCountValue->GetUnit()) {
8177 column->mColumnCount = columnCountValue->GetIntValue();
8178 // Max kMaxColumnCount columns - wallpaper for bug 345583.
8179 column->mColumnCount = std::min(column->mColumnCount,
8180 nsStyleColumn::kMaxColumnCount);
8181 } else if (eCSSUnit_Inherit == columnCountValue->GetUnit()) {
8182 canStoreInRuleTree = false;
8183 column->mColumnCount = parent->mColumnCount;
8186 // column-rule-width: length, enum, inherit
8187 const nsCSSValue& widthValue = *aRuleData->ValueForColumnRuleWidth();
8188 if (eCSSUnit_Initial == widthValue.GetUnit() ||
8189 eCSSUnit_Unset == widthValue.GetUnit()) {
8190 column->SetColumnRuleWidth(
8191 (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
8193 else if (eCSSUnit_Enumerated == widthValue.GetUnit()) {
8194 NS_ASSERTION(widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
8195 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
8196 widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
8197 "Unexpected enum value");
8198 column->SetColumnRuleWidth(
8199 (mPresContext->GetBorderWidthTable())[widthValue.GetIntValue()]);
8201 else if (eCSSUnit_Inherit == widthValue.GetUnit()) {
8202 column->SetColumnRuleWidth(parent->GetComputedColumnRuleWidth());
8203 canStoreInRuleTree = false;
8205 else if (widthValue.IsLengthUnit() || widthValue.IsCalcUnit()) {
8206 nscoord len =
8207 CalcLength(widthValue, aContext, mPresContext, canStoreInRuleTree);
8208 if (len < 0) {
8209 // FIXME: This is untested (by test_value_storage.html) for
8210 // column-rule-width since it gets covered up by the border
8211 // rounding code.
8212 NS_ASSERTION(widthValue.IsCalcUnit(),
8213 "parser should have rejected negative length");
8214 len = 0;
8216 column->SetColumnRuleWidth(len);
8219 // column-rule-style: enum, inherit
8220 const nsCSSValue& styleValue = *aRuleData->ValueForColumnRuleStyle();
8221 NS_ABORT_IF_FALSE(eCSSUnit_None != styleValue.GetUnit(),
8222 "'none' should be handled as enumerated value");
8223 if (eCSSUnit_Enumerated == styleValue.GetUnit()) {
8224 column->mColumnRuleStyle = styleValue.GetIntValue();
8226 else if (eCSSUnit_Initial == styleValue.GetUnit() ||
8227 eCSSUnit_Unset == styleValue.GetUnit()) {
8228 column->mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
8230 else if (eCSSUnit_Inherit == styleValue.GetUnit()) {
8231 canStoreInRuleTree = false;
8232 column->mColumnRuleStyle = parent->mColumnRuleStyle;
8235 // column-rule-color: color, inherit
8236 const nsCSSValue& colorValue = *aRuleData->ValueForColumnRuleColor();
8237 if (eCSSUnit_Inherit == colorValue.GetUnit()) {
8238 canStoreInRuleTree = false;
8239 column->mColumnRuleColorIsForeground = false;
8240 if (parent->mColumnRuleColorIsForeground) {
8241 if (parentContext) {
8242 column->mColumnRuleColor = parentContext->StyleColor()->mColor;
8243 } else {
8244 nsStyleColor defaultColumnRuleColor(mPresContext);
8245 column->mColumnRuleColor = defaultColumnRuleColor.mColor;
8247 } else {
8248 column->mColumnRuleColor = parent->mColumnRuleColor;
8251 else if (eCSSUnit_Initial == colorValue.GetUnit() ||
8252 eCSSUnit_Unset == colorValue.GetUnit() ||
8253 eCSSUnit_Enumerated == colorValue.GetUnit()) {
8254 column->mColumnRuleColorIsForeground = true;
8256 else if (SetColor(colorValue, 0, mPresContext, aContext,
8257 column->mColumnRuleColor, canStoreInRuleTree)) {
8258 column->mColumnRuleColorIsForeground = false;
8261 // column-fill: enum
8262 SetDiscrete(*aRuleData->ValueForColumnFill(),
8263 column->mColumnFill, canStoreInRuleTree,
8264 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
8265 parent->mColumnFill,
8266 NS_STYLE_COLUMN_FILL_BALANCE,
8267 0, 0, 0, 0);
8269 COMPUTE_END_RESET(Column, column)
8272 static void
8273 SetSVGPaint(const nsCSSValue& aValue, const nsStyleSVGPaint& parentPaint,
8274 nsPresContext* aPresContext, nsStyleContext *aContext,
8275 nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
8276 bool& aCanStoreInRuleTree)
8278 nscolor color;
8280 if (aValue.GetUnit() == eCSSUnit_Inherit ||
8281 aValue.GetUnit() == eCSSUnit_Unset) {
8282 aResult = parentPaint;
8283 aCanStoreInRuleTree = false;
8284 } else if (aValue.GetUnit() == eCSSUnit_None) {
8285 aResult.SetType(eStyleSVGPaintType_None);
8286 } else if (aValue.GetUnit() == eCSSUnit_Initial) {
8287 aResult.SetType(aInitialPaintType);
8288 aResult.mPaint.mColor = NS_RGB(0, 0, 0);
8289 aResult.mFallbackColor = NS_RGB(0, 0, 0);
8290 } else if (SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aContext,
8291 color, aCanStoreInRuleTree)) {
8292 aResult.SetType(eStyleSVGPaintType_Color);
8293 aResult.mPaint.mColor = color;
8294 } else if (aValue.GetUnit() == eCSSUnit_Pair) {
8295 const nsCSSValuePair& pair = aValue.GetPairValue();
8297 if (pair.mXValue.GetUnit() == eCSSUnit_URL) {
8298 aResult.SetType(eStyleSVGPaintType_Server);
8299 aResult.mPaint.mPaintServer = pair.mXValue.GetURLValue();
8300 NS_IF_ADDREF(aResult.mPaint.mPaintServer);
8301 } else if (pair.mXValue.GetUnit() == eCSSUnit_Enumerated) {
8303 switch (pair.mXValue.GetIntValue()) {
8304 case NS_COLOR_CONTEXT_FILL:
8305 aResult.SetType(eStyleSVGPaintType_ContextFill);
8306 break;
8307 case NS_COLOR_CONTEXT_STROKE:
8308 aResult.SetType(eStyleSVGPaintType_ContextStroke);
8309 break;
8310 default:
8311 NS_NOTREACHED("unknown keyword as paint server value");
8314 } else {
8315 NS_NOTREACHED("malformed paint server value");
8318 if (pair.mYValue.GetUnit() == eCSSUnit_None) {
8319 aResult.mFallbackColor = NS_RGBA(0, 0, 0, 0);
8320 } else {
8321 NS_ABORT_IF_FALSE(pair.mYValue.GetUnit() != eCSSUnit_Inherit,
8322 "cannot inherit fallback colour");
8323 SetColor(pair.mYValue, NS_RGB(0, 0, 0), aPresContext, aContext,
8324 aResult.mFallbackColor, aCanStoreInRuleTree);
8326 } else {
8327 NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Null,
8328 "malformed paint server value");
8332 static void
8333 SetSVGOpacity(const nsCSSValue& aValue,
8334 float& aOpacityField, nsStyleSVGOpacitySource& aOpacityTypeField,
8335 bool& aCanStoreInRuleTree,
8336 float aParentOpacity, nsStyleSVGOpacitySource aParentOpacityType)
8338 if (eCSSUnit_Enumerated == aValue.GetUnit()) {
8339 switch (aValue.GetIntValue()) {
8340 case NS_STYLE_CONTEXT_FILL_OPACITY:
8341 aOpacityTypeField = eStyleSVGOpacitySource_ContextFillOpacity;
8342 break;
8343 case NS_STYLE_CONTEXT_STROKE_OPACITY:
8344 aOpacityTypeField = eStyleSVGOpacitySource_ContextStrokeOpacity;
8345 break;
8346 default:
8347 NS_NOTREACHED("SetSVGOpacity: Unknown keyword");
8349 // Fall back on fully opaque
8350 aOpacityField = 1.0f;
8351 } else if (eCSSUnit_Inherit == aValue.GetUnit() ||
8352 eCSSUnit_Unset == aValue.GetUnit()) {
8353 aCanStoreInRuleTree = false;
8354 aOpacityField = aParentOpacity;
8355 aOpacityTypeField = aParentOpacityType;
8356 } else if (eCSSUnit_Null != aValue.GetUnit()) {
8357 SetFactor(aValue, aOpacityField, aCanStoreInRuleTree,
8358 aParentOpacity, 1.0f, SETFCT_OPACITY);
8359 aOpacityTypeField = eStyleSVGOpacitySource_Normal;
8363 const void*
8364 nsRuleNode::ComputeSVGData(void* aStartStruct,
8365 const nsRuleData* aRuleData,
8366 nsStyleContext* aContext,
8367 nsRuleNode* aHighestNode,
8368 const RuleDetail aRuleDetail,
8369 const bool aCanStoreInRuleTree)
8371 COMPUTE_START_INHERITED(SVG, (), svg, parentSVG)
8373 // clip-rule: enum, inherit, initial
8374 SetDiscrete(*aRuleData->ValueForClipRule(),
8375 svg->mClipRule, canStoreInRuleTree,
8376 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
8377 parentSVG->mClipRule,
8378 NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
8380 // color-interpolation: enum, inherit, initial
8381 SetDiscrete(*aRuleData->ValueForColorInterpolation(),
8382 svg->mColorInterpolation, canStoreInRuleTree,
8383 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
8384 parentSVG->mColorInterpolation,
8385 NS_STYLE_COLOR_INTERPOLATION_SRGB, 0, 0, 0, 0);
8387 // color-interpolation-filters: enum, inherit, initial
8388 SetDiscrete(*aRuleData->ValueForColorInterpolationFilters(),
8389 svg->mColorInterpolationFilters, canStoreInRuleTree,
8390 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
8391 parentSVG->mColorInterpolationFilters,
8392 NS_STYLE_COLOR_INTERPOLATION_LINEARRGB, 0, 0, 0, 0);
8394 // fill:
8395 SetSVGPaint(*aRuleData->ValueForFill(),
8396 parentSVG->mFill, mPresContext, aContext,
8397 svg->mFill, eStyleSVGPaintType_Color, canStoreInRuleTree);
8399 // fill-opacity: factor, inherit, initial,
8400 // context-fill-opacity, context-stroke-opacity
8401 nsStyleSVGOpacitySource contextFillOpacity = svg->mFillOpacitySource;
8402 SetSVGOpacity(*aRuleData->ValueForFillOpacity(),
8403 svg->mFillOpacity, contextFillOpacity, canStoreInRuleTree,
8404 parentSVG->mFillOpacity, parentSVG->mFillOpacitySource);
8405 svg->mFillOpacitySource = contextFillOpacity;
8407 // fill-rule: enum, inherit, initial
8408 SetDiscrete(*aRuleData->ValueForFillRule(),
8409 svg->mFillRule, canStoreInRuleTree,
8410 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
8411 parentSVG->mFillRule,
8412 NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
8414 // image-rendering: enum, inherit
8415 SetDiscrete(*aRuleData->ValueForImageRendering(),
8416 svg->mImageRendering, canStoreInRuleTree,
8417 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
8418 parentSVG->mImageRendering,
8419 NS_STYLE_IMAGE_RENDERING_AUTO, 0, 0, 0, 0);
8421 // marker-end: url, none, inherit
8422 const nsCSSValue* markerEndValue = aRuleData->ValueForMarkerEnd();
8423 if (eCSSUnit_URL == markerEndValue->GetUnit()) {
8424 svg->mMarkerEnd = markerEndValue->GetURLValue();
8425 } else if (eCSSUnit_None == markerEndValue->GetUnit() ||
8426 eCSSUnit_Initial == markerEndValue->GetUnit()) {
8427 svg->mMarkerEnd = nullptr;
8428 } else if (eCSSUnit_Inherit == markerEndValue->GetUnit() ||
8429 eCSSUnit_Unset == markerEndValue->GetUnit()) {
8430 canStoreInRuleTree = false;
8431 svg->mMarkerEnd = parentSVG->mMarkerEnd;
8434 // marker-mid: url, none, inherit
8435 const nsCSSValue* markerMidValue = aRuleData->ValueForMarkerMid();
8436 if (eCSSUnit_URL == markerMidValue->GetUnit()) {
8437 svg->mMarkerMid = markerMidValue->GetURLValue();
8438 } else if (eCSSUnit_None == markerMidValue->GetUnit() ||
8439 eCSSUnit_Initial == markerMidValue->GetUnit()) {
8440 svg->mMarkerMid = nullptr;
8441 } else if (eCSSUnit_Inherit == markerMidValue->GetUnit() ||
8442 eCSSUnit_Unset == markerMidValue->GetUnit()) {
8443 canStoreInRuleTree = false;
8444 svg->mMarkerMid = parentSVG->mMarkerMid;
8447 // marker-start: url, none, inherit
8448 const nsCSSValue* markerStartValue = aRuleData->ValueForMarkerStart();
8449 if (eCSSUnit_URL == markerStartValue->GetUnit()) {
8450 svg->mMarkerStart = markerStartValue->GetURLValue();
8451 } else if (eCSSUnit_None == markerStartValue->GetUnit() ||
8452 eCSSUnit_Initial == markerStartValue->GetUnit()) {
8453 svg->mMarkerStart = nullptr;
8454 } else if (eCSSUnit_Inherit == markerStartValue->GetUnit() ||
8455 eCSSUnit_Unset == markerStartValue->GetUnit()) {
8456 canStoreInRuleTree = false;
8457 svg->mMarkerStart = parentSVG->mMarkerStart;
8460 // paint-order: enum (bit field), inherit, initial
8461 const nsCSSValue* paintOrderValue = aRuleData->ValueForPaintOrder();
8462 switch (paintOrderValue->GetUnit()) {
8463 case eCSSUnit_Null:
8464 break;
8466 case eCSSUnit_Enumerated:
8467 static_assert
8468 (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <= 8,
8469 "SVGStyleStruct::mPaintOrder not big enough");
8470 svg->mPaintOrder = static_cast<uint8_t>(paintOrderValue->GetIntValue());
8471 break;
8473 case eCSSUnit_Inherit:
8474 case eCSSUnit_Unset:
8475 canStoreInRuleTree = false;
8476 svg->mPaintOrder = parentSVG->mPaintOrder;
8477 break;
8479 case eCSSUnit_Initial:
8480 svg->mPaintOrder = NS_STYLE_PAINT_ORDER_NORMAL;
8481 break;
8483 default:
8484 NS_NOTREACHED("unexpected unit");
8487 // shape-rendering: enum, inherit
8488 SetDiscrete(*aRuleData->ValueForShapeRendering(),
8489 svg->mShapeRendering, canStoreInRuleTree,
8490 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
8491 parentSVG->mShapeRendering,
8492 NS_STYLE_SHAPE_RENDERING_AUTO, 0, 0, 0, 0);
8494 // stroke:
8495 SetSVGPaint(*aRuleData->ValueForStroke(),
8496 parentSVG->mStroke, mPresContext, aContext,
8497 svg->mStroke, eStyleSVGPaintType_None, canStoreInRuleTree);
8499 // stroke-dasharray: <dasharray>, none, inherit, context-value
8500 const nsCSSValue* strokeDasharrayValue = aRuleData->ValueForStrokeDasharray();
8501 switch (strokeDasharrayValue->GetUnit()) {
8502 case eCSSUnit_Null:
8503 break;
8505 case eCSSUnit_Inherit:
8506 case eCSSUnit_Unset:
8507 canStoreInRuleTree = false;
8508 svg->mStrokeDasharrayFromObject = parentSVG->mStrokeDasharrayFromObject;
8509 // only do the copy if weren't already set up by the copy constructor
8510 // FIXME Bug 389408: This is broken when aStartStruct is non-null!
8511 if (!svg->mStrokeDasharray) {
8512 svg->mStrokeDasharrayLength = parentSVG->mStrokeDasharrayLength;
8513 if (svg->mStrokeDasharrayLength) {
8514 svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
8515 if (svg->mStrokeDasharray)
8516 memcpy(svg->mStrokeDasharray,
8517 parentSVG->mStrokeDasharray,
8518 svg->mStrokeDasharrayLength * sizeof(nsStyleCoord));
8519 else
8520 svg->mStrokeDasharrayLength = 0;
8523 break;
8525 case eCSSUnit_Enumerated:
8526 NS_ABORT_IF_FALSE(strokeDasharrayValue->GetIntValue() ==
8527 NS_STYLE_STROKE_PROP_CONTEXT_VALUE,
8528 "Unknown keyword for stroke-dasharray");
8529 svg->mStrokeDasharrayFromObject = true;
8530 delete [] svg->mStrokeDasharray;
8531 svg->mStrokeDasharray = nullptr;
8532 svg->mStrokeDasharrayLength = 0;
8533 break;
8535 case eCSSUnit_Initial:
8536 case eCSSUnit_None:
8537 svg->mStrokeDasharrayFromObject = false;
8538 delete [] svg->mStrokeDasharray;
8539 svg->mStrokeDasharray = nullptr;
8540 svg->mStrokeDasharrayLength = 0;
8541 break;
8543 case eCSSUnit_List:
8544 case eCSSUnit_ListDep: {
8545 svg->mStrokeDasharrayFromObject = false;
8546 delete [] svg->mStrokeDasharray;
8547 svg->mStrokeDasharray = nullptr;
8548 svg->mStrokeDasharrayLength = 0;
8550 // count number of values
8551 const nsCSSValueList *value = strokeDasharrayValue->GetListValue();
8552 svg->mStrokeDasharrayLength = ListLength(value);
8554 NS_ASSERTION(svg->mStrokeDasharrayLength != 0, "no dasharray items");
8556 svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
8558 if (svg->mStrokeDasharray) {
8559 uint32_t i = 0;
8560 while (nullptr != value) {
8561 SetCoord(value->mValue,
8562 svg->mStrokeDasharray[i++], nsStyleCoord(),
8563 SETCOORD_LP | SETCOORD_FACTOR,
8564 aContext, mPresContext, canStoreInRuleTree);
8565 value = value->mNext;
8567 } else {
8568 svg->mStrokeDasharrayLength = 0;
8570 break;
8573 default:
8574 NS_ABORT_IF_FALSE(false, "unrecognized dasharray unit");
8577 // stroke-dashoffset: <dashoffset>, inherit
8578 const nsCSSValue *strokeDashoffsetValue =
8579 aRuleData->ValueForStrokeDashoffset();
8580 svg->mStrokeDashoffsetFromObject =
8581 strokeDashoffsetValue->GetUnit() == eCSSUnit_Enumerated &&
8582 strokeDashoffsetValue->GetIntValue() == NS_STYLE_STROKE_PROP_CONTEXT_VALUE;
8583 if (svg->mStrokeDashoffsetFromObject) {
8584 svg->mStrokeDashoffset.SetCoordValue(0);
8585 } else {
8586 SetCoord(*aRuleData->ValueForStrokeDashoffset(),
8587 svg->mStrokeDashoffset, parentSVG->mStrokeDashoffset,
8588 SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_INITIAL_ZERO |
8589 SETCOORD_UNSET_INHERIT,
8590 aContext, mPresContext, canStoreInRuleTree);
8593 // stroke-linecap: enum, inherit, initial
8594 SetDiscrete(*aRuleData->ValueForStrokeLinecap(),
8595 svg->mStrokeLinecap, canStoreInRuleTree,
8596 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
8597 parentSVG->mStrokeLinecap,
8598 NS_STYLE_STROKE_LINECAP_BUTT, 0, 0, 0, 0);
8600 // stroke-linejoin: enum, inherit, initial
8601 SetDiscrete(*aRuleData->ValueForStrokeLinejoin(),
8602 svg->mStrokeLinejoin, canStoreInRuleTree,
8603 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
8604 parentSVG->mStrokeLinejoin,
8605 NS_STYLE_STROKE_LINEJOIN_MITER, 0, 0, 0, 0);
8607 // stroke-miterlimit: <miterlimit>, inherit
8608 SetFactor(*aRuleData->ValueForStrokeMiterlimit(),
8609 svg->mStrokeMiterlimit,
8610 canStoreInRuleTree,
8611 parentSVG->mStrokeMiterlimit, 4.0f,
8612 SETFCT_UNSET_INHERIT);
8614 // stroke-opacity:
8615 nsStyleSVGOpacitySource contextStrokeOpacity = svg->mStrokeOpacitySource;
8616 SetSVGOpacity(*aRuleData->ValueForStrokeOpacity(),
8617 svg->mStrokeOpacity, contextStrokeOpacity, canStoreInRuleTree,
8618 parentSVG->mStrokeOpacity, parentSVG->mStrokeOpacitySource);
8619 svg->mStrokeOpacitySource = contextStrokeOpacity;
8621 // stroke-width:
8622 const nsCSSValue* strokeWidthValue = aRuleData->ValueForStrokeWidth();
8623 switch (strokeWidthValue->GetUnit()) {
8624 case eCSSUnit_Enumerated:
8625 NS_ABORT_IF_FALSE(strokeWidthValue->GetIntValue() ==
8626 NS_STYLE_STROKE_PROP_CONTEXT_VALUE,
8627 "Unrecognized keyword for stroke-width");
8628 svg->mStrokeWidthFromObject = true;
8629 svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
8630 break;
8632 case eCSSUnit_Initial:
8633 svg->mStrokeWidthFromObject = false;
8634 svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
8635 break;
8637 default:
8638 svg->mStrokeWidthFromObject = false;
8639 SetCoord(*strokeWidthValue,
8640 svg->mStrokeWidth, parentSVG->mStrokeWidth,
8641 SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_UNSET_INHERIT,
8642 aContext, mPresContext, canStoreInRuleTree);
8645 // text-anchor: enum, inherit, initial
8646 SetDiscrete(*aRuleData->ValueForTextAnchor(),
8647 svg->mTextAnchor, canStoreInRuleTree,
8648 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
8649 parentSVG->mTextAnchor,
8650 NS_STYLE_TEXT_ANCHOR_START, 0, 0, 0, 0);
8652 // text-rendering: enum, inherit, initial
8653 SetDiscrete(*aRuleData->ValueForTextRendering(),
8654 svg->mTextRendering, canStoreInRuleTree,
8655 SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
8656 parentSVG->mTextRendering,
8657 NS_STYLE_TEXT_RENDERING_AUTO, 0, 0, 0, 0);
8659 COMPUTE_END_INHERITED(SVG, svg)
8662 // Returns true if the nsStyleFilter was successfully set using the nsCSSValue.
8663 bool
8664 nsRuleNode::SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
8665 const nsCSSValue& aValue,
8666 nsStyleContext* aStyleContext,
8667 nsPresContext* aPresContext,
8668 bool& aCanStoreInRuleTree)
8670 nsCSSUnit unit = aValue.GetUnit();
8671 if (unit == eCSSUnit_URL) {
8672 nsIURI* url = aValue.GetURLValue();
8673 if (!url)
8674 return false;
8675 aStyleFilter->SetURL(url);
8676 return true;
8679 NS_ABORT_IF_FALSE(unit == eCSSUnit_Function, "expected a filter function");
8681 nsCSSValue::Array* filterFunction = aValue.GetArrayValue();
8682 nsCSSKeyword functionName =
8683 (nsCSSKeyword)filterFunction->Item(0).GetIntValue();
8685 int32_t type;
8686 DebugOnly<bool> foundKeyword =
8687 nsCSSProps::FindKeyword(functionName,
8688 nsCSSProps::kFilterFunctionKTable,
8689 type);
8690 NS_ABORT_IF_FALSE(foundKeyword, "unknown filter type");
8691 if (type == NS_STYLE_FILTER_DROP_SHADOW) {
8692 nsRefPtr<nsCSSShadowArray> shadowArray = GetShadowData(
8693 filterFunction->Item(1).GetListValue(),
8694 aStyleContext,
8695 false,
8696 aCanStoreInRuleTree);
8697 aStyleFilter->SetDropShadow(shadowArray);
8698 return true;
8701 int32_t mask = SETCOORD_PERCENT | SETCOORD_FACTOR;
8702 if (type == NS_STYLE_FILTER_BLUR) {
8703 mask = SETCOORD_LENGTH |
8704 SETCOORD_CALC_LENGTH_ONLY |
8705 SETCOORD_CALC_CLAMP_NONNEGATIVE;
8706 } else if (type == NS_STYLE_FILTER_HUE_ROTATE) {
8707 mask = SETCOORD_ANGLE;
8710 NS_ABORT_IF_FALSE(filterFunction->Count() == 2,
8711 "all filter functions should have "
8712 "exactly one argument");
8714 nsCSSValue& arg = filterFunction->Item(1);
8715 nsStyleCoord filterParameter;
8716 DebugOnly<bool> didSetCoord = SetCoord(arg, filterParameter,
8717 nsStyleCoord(), mask,
8718 aStyleContext, aPresContext,
8719 aCanStoreInRuleTree);
8720 aStyleFilter->SetFilterParameter(filterParameter, type);
8721 NS_ABORT_IF_FALSE(didSetCoord, "unexpected unit");
8722 return true;
8725 const void*
8726 nsRuleNode::ComputeSVGResetData(void* aStartStruct,
8727 const nsRuleData* aRuleData,
8728 nsStyleContext* aContext,
8729 nsRuleNode* aHighestNode,
8730 const RuleDetail aRuleDetail,
8731 const bool aCanStoreInRuleTree)
8733 COMPUTE_START_RESET(SVGReset, (), svgReset, parentSVGReset)
8735 // stop-color:
8736 const nsCSSValue* stopColorValue = aRuleData->ValueForStopColor();
8737 if (eCSSUnit_Initial == stopColorValue->GetUnit() ||
8738 eCSSUnit_Unset == stopColorValue->GetUnit()) {
8739 svgReset->mStopColor = NS_RGB(0, 0, 0);
8740 } else {
8741 SetColor(*stopColorValue, parentSVGReset->mStopColor,
8742 mPresContext, aContext, svgReset->mStopColor, canStoreInRuleTree);
8745 // flood-color:
8746 const nsCSSValue* floodColorValue = aRuleData->ValueForFloodColor();
8747 if (eCSSUnit_Initial == floodColorValue->GetUnit() ||
8748 eCSSUnit_Unset == floodColorValue->GetUnit()) {
8749 svgReset->mFloodColor = NS_RGB(0, 0, 0);
8750 } else {
8751 SetColor(*floodColorValue, parentSVGReset->mFloodColor,
8752 mPresContext, aContext, svgReset->mFloodColor, canStoreInRuleTree);
8755 // lighting-color:
8756 const nsCSSValue* lightingColorValue = aRuleData->ValueForLightingColor();
8757 if (eCSSUnit_Initial == lightingColorValue->GetUnit() ||
8758 eCSSUnit_Unset == lightingColorValue->GetUnit()) {
8759 svgReset->mLightingColor = NS_RGB(255, 255, 255);
8760 } else {
8761 SetColor(*lightingColorValue, parentSVGReset->mLightingColor,
8762 mPresContext, aContext, svgReset->mLightingColor,
8763 canStoreInRuleTree);
8766 // clip-path: url, none, inherit
8767 const nsCSSValue* clipPathValue = aRuleData->ValueForClipPath();
8768 if (eCSSUnit_URL == clipPathValue->GetUnit()) {
8769 svgReset->mClipPath = clipPathValue->GetURLValue();
8770 } else if (eCSSUnit_None == clipPathValue->GetUnit() ||
8771 eCSSUnit_Initial == clipPathValue->GetUnit() ||
8772 eCSSUnit_Unset == clipPathValue->GetUnit()) {
8773 svgReset->mClipPath = nullptr;
8774 } else if (eCSSUnit_Inherit == clipPathValue->GetUnit()) {
8775 canStoreInRuleTree = false;
8776 svgReset->mClipPath = parentSVGReset->mClipPath;
8779 // stop-opacity:
8780 SetFactor(*aRuleData->ValueForStopOpacity(),
8781 svgReset->mStopOpacity, canStoreInRuleTree,
8782 parentSVGReset->mStopOpacity, 1.0f,
8783 SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
8785 // flood-opacity:
8786 SetFactor(*aRuleData->ValueForFloodOpacity(),
8787 svgReset->mFloodOpacity, canStoreInRuleTree,
8788 parentSVGReset->mFloodOpacity, 1.0f,
8789 SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
8791 // dominant-baseline: enum, inherit, initial
8792 SetDiscrete(*aRuleData->ValueForDominantBaseline(),
8793 svgReset->mDominantBaseline,
8794 canStoreInRuleTree,
8795 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
8796 parentSVGReset->mDominantBaseline,
8797 NS_STYLE_DOMINANT_BASELINE_AUTO, 0, 0, 0, 0);
8799 // vector-effect: enum, inherit, initial
8800 SetDiscrete(*aRuleData->ValueForVectorEffect(),
8801 svgReset->mVectorEffect,
8802 canStoreInRuleTree,
8803 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
8804 parentSVGReset->mVectorEffect,
8805 NS_STYLE_VECTOR_EFFECT_NONE, 0, 0, 0, 0);
8807 // filter: url, none, inherit
8808 const nsCSSValue* filterValue = aRuleData->ValueForFilter();
8809 switch (filterValue->GetUnit()) {
8810 case eCSSUnit_Null:
8811 break;
8812 case eCSSUnit_None:
8813 case eCSSUnit_Initial:
8814 case eCSSUnit_Unset:
8815 svgReset->mFilters.Clear();
8816 break;
8817 case eCSSUnit_Inherit:
8818 canStoreInRuleTree = false;
8819 svgReset->mFilters = parentSVGReset->mFilters;
8820 break;
8821 case eCSSUnit_List:
8822 case eCSSUnit_ListDep: {
8823 svgReset->mFilters.Clear();
8824 const nsCSSValueList* cur = filterValue->GetListValue();
8825 while (cur) {
8826 nsStyleFilter styleFilter;
8827 if (!SetStyleFilterToCSSValue(&styleFilter, cur->mValue, aContext,
8828 mPresContext, canStoreInRuleTree)) {
8829 svgReset->mFilters.Clear();
8830 break;
8832 NS_ABORT_IF_FALSE(styleFilter.GetType() != NS_STYLE_FILTER_NONE,
8833 "filter should be set");
8834 svgReset->mFilters.AppendElement(styleFilter);
8835 cur = cur->mNext;
8837 break;
8839 default:
8840 NS_NOTREACHED("unexpected unit");
8843 // mask: url, none, inherit
8844 const nsCSSValue* maskValue = aRuleData->ValueForMask();
8845 if (eCSSUnit_URL == maskValue->GetUnit()) {
8846 svgReset->mMask = maskValue->GetURLValue();
8847 } else if (eCSSUnit_None == maskValue->GetUnit() ||
8848 eCSSUnit_Initial == maskValue->GetUnit() ||
8849 eCSSUnit_Unset == maskValue->GetUnit()) {
8850 svgReset->mMask = nullptr;
8851 } else if (eCSSUnit_Inherit == maskValue->GetUnit()) {
8852 canStoreInRuleTree = false;
8853 svgReset->mMask = parentSVGReset->mMask;
8856 // mask-type: enum, inherit, initial
8857 SetDiscrete(*aRuleData->ValueForMaskType(),
8858 svgReset->mMaskType,
8859 canStoreInRuleTree,
8860 SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
8861 parentSVGReset->mMaskType,
8862 NS_STYLE_MASK_TYPE_LUMINANCE, 0, 0, 0, 0);
8864 COMPUTE_END_RESET(SVGReset, svgReset)
8867 const void*
8868 nsRuleNode::ComputeVariablesData(void* aStartStruct,
8869 const nsRuleData* aRuleData,
8870 nsStyleContext* aContext,
8871 nsRuleNode* aHighestNode,
8872 const RuleDetail aRuleDetail,
8873 const bool aCanStoreInRuleTree)
8875 COMPUTE_START_INHERITED(Variables, (), variables, parentVariables)
8877 MOZ_ASSERT(aRuleData->mVariables,
8878 "shouldn't be in ComputeVariablesData if there were no variable "
8879 "declarations specified");
8881 CSSVariableResolver resolver(&variables->mVariables);
8882 resolver.Resolve(&parentVariables->mVariables,
8883 aRuleData->mVariables);
8884 canStoreInRuleTree = false;
8886 COMPUTE_END_INHERITED(Variables, variables)
8889 const void*
8890 nsRuleNode::GetStyleData(nsStyleStructID aSID,
8891 nsStyleContext* aContext,
8892 bool aComputeData)
8894 NS_ASSERTION(IsUsedDirectly(),
8895 "if we ever call this on rule nodes that aren't used "
8896 "directly, we should adjust handling of mDependentBits "
8897 "in some way.");
8899 const void *data;
8900 data = mStyleData.GetStyleData(aSID);
8901 if (MOZ_LIKELY(data != nullptr))
8902 return data; // We have a fully specified struct. Just return it.
8904 if (MOZ_UNLIKELY(!aComputeData))
8905 return nullptr;
8907 // Nothing is cached. We'll have to delve further and examine our rules.
8908 data = WalkRuleTree(aSID, aContext);
8910 NS_ABORT_IF_FALSE(data, "should have aborted on out-of-memory");
8911 return data;
8914 // See comments above in GetStyleData for an explanation of what the
8915 // code below does.
8916 #define STYLE_STRUCT(name_, checkdata_cb_) \
8917 const nsStyle##name_* \
8918 nsRuleNode::GetStyle##name_(nsStyleContext* aContext, bool aComputeData) \
8920 NS_ASSERTION(IsUsedDirectly(), \
8921 "if we ever call this on rule nodes that aren't used " \
8922 "directly, we should adjust handling of mDependentBits " \
8923 "in some way."); \
8925 const nsStyle##name_ *data; \
8926 data = mStyleData.GetStyle##name_(); \
8927 if (MOZ_LIKELY(data != nullptr)) \
8928 return data; \
8930 if (MOZ_UNLIKELY(!aComputeData)) \
8931 return nullptr; \
8933 data = static_cast<const nsStyle##name_ *> \
8934 (WalkRuleTree(eStyleStruct_##name_, aContext)); \
8936 NS_ABORT_IF_FALSE(data, "should have aborted on out-of-memory"); \
8937 return data; \
8939 #include "nsStyleStructList.h"
8940 #undef STYLE_STRUCT
8942 void
8943 nsRuleNode::Mark()
8945 for (nsRuleNode *node = this;
8946 node && !(node->mDependentBits & NS_RULE_NODE_GC_MARK);
8947 node = node->mParent)
8948 node->mDependentBits |= NS_RULE_NODE_GC_MARK;
8951 bool
8952 nsRuleNode::DestroyIfNotMarked()
8954 // If we're not marked, then we have to delete ourself.
8955 // However, we never allow the root node to GC itself, because nsStyleSet
8956 // wants to hold onto the root node and not worry about re-creating a
8957 // rule walker if the root node is deleted.
8958 if (!(mDependentBits & NS_RULE_NODE_GC_MARK) &&
8959 // Skip this only if we're the *current* root and not an old one.
8960 !(IsRoot() && mPresContext->StyleSet()->GetRuleTree() == this)) {
8961 Destroy();
8962 return true;
8965 // Clear our mark, for the next time around.
8966 mDependentBits &= ~NS_RULE_NODE_GC_MARK;
8967 return false;
8970 PLDHashOperator
8971 nsRuleNode::SweepHashEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
8972 uint32_t number, void *arg)
8974 ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
8975 nsRuleNode* node = entry->mRuleNode;
8976 if (node->DestroyIfNotMarked()) {
8977 return PL_DHASH_REMOVE; // implies NEXT, unless |ed with STOP
8979 if (node->HaveChildren()) {
8980 // When children are hashed mNextSibling is not normally used but we use it
8981 // here to build a list of children that needs to be swept.
8982 nsRuleNode** headQ = static_cast<nsRuleNode**>(arg);
8983 node->mNextSibling = *headQ;
8984 *headQ = node;
8986 return PL_DHASH_NEXT;
8989 void
8990 nsRuleNode::SweepChildren(nsTArray<nsRuleNode*>& aSweepQueue)
8992 NS_ASSERTION(!(mDependentBits & NS_RULE_NODE_GC_MARK),
8993 "missing DestroyIfNotMarked() call");
8994 NS_ASSERTION(HaveChildren(),
8995 "why call SweepChildren with no children?");
8996 uint32_t childrenDestroyed = 0;
8997 nsRuleNode* survivorsWithChildren = nullptr;
8998 if (ChildrenAreHashed()) {
8999 PLDHashTable* children = ChildrenHash();
9000 uint32_t oldChildCount = children->EntryCount();
9001 PL_DHashTableEnumerate(children, SweepHashEntry, &survivorsWithChildren);
9002 childrenDestroyed = oldChildCount - children->EntryCount();
9003 if (childrenDestroyed == oldChildCount) {
9004 PL_DHashTableDestroy(children);
9005 mChildren.asVoid = nullptr;
9007 } else {
9008 for (nsRuleNode** children = ChildrenListPtr(); *children; ) {
9009 nsRuleNode* next = (*children)->mNextSibling;
9010 if ((*children)->DestroyIfNotMarked()) {
9011 // This rule node was destroyed, unlink it from the list by
9012 // making *children point to the next entry.
9013 *children = next;
9014 ++childrenDestroyed;
9015 } else {
9016 children = &(*children)->mNextSibling;
9019 survivorsWithChildren = ChildrenList();
9021 if (survivorsWithChildren) {
9022 aSweepQueue.AppendElement(survivorsWithChildren);
9024 NS_ASSERTION(childrenDestroyed <= mRefCnt, "wrong ref count");
9025 mRefCnt -= childrenDestroyed;
9026 NS_POSTCONDITION(IsRoot() || mRefCnt > 0,
9027 "We didn't get swept, so we'd better have style contexts "
9028 "pointing to us or to one of our descendants, which means "
9029 "we'd better have a nonzero mRefCnt here!");
9032 bool
9033 nsRuleNode::Sweep()
9035 NS_ASSERTION(IsRoot(), "must start sweeping at a root");
9036 NS_ASSERTION(!mNextSibling, "root must not have mNextSibling");
9038 if (DestroyIfNotMarked()) {
9039 return true;
9042 nsAutoTArray<nsRuleNode*, 70> sweepQueue;
9043 sweepQueue.AppendElement(this);
9044 while (!sweepQueue.IsEmpty()) {
9045 nsTArray<nsRuleNode*>::index_type last = sweepQueue.Length() - 1;
9046 nsRuleNode* ruleNode = sweepQueue[last];
9047 sweepQueue.RemoveElementAt(last);
9048 for (; ruleNode; ruleNode = ruleNode->mNextSibling) {
9049 if (ruleNode->HaveChildren()) {
9050 ruleNode->SweepChildren(sweepQueue);
9054 return false;
9057 /* static */ bool
9058 nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
9059 uint32_t ruleTypeMask,
9060 bool aAuthorColorsAllowed)
9062 uint32_t inheritBits = 0;
9063 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND)
9064 inheritBits |= NS_STYLE_INHERIT_BIT(Background);
9066 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER)
9067 inheritBits |= NS_STYLE_INHERIT_BIT(Border);
9069 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING)
9070 inheritBits |= NS_STYLE_INHERIT_BIT(Padding);
9072 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW)
9073 inheritBits |= NS_STYLE_INHERIT_BIT(Text);
9075 // properties in the SIDS, whether or not we care about them
9076 size_t nprops = 0,
9077 backgroundOffset, borderOffset, paddingOffset, textShadowOffset;
9079 // We put the reset properties the start of the nsCSSValue array....
9081 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
9082 backgroundOffset = nprops;
9083 nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Background);
9086 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
9087 borderOffset = nprops;
9088 nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Border);
9091 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
9092 paddingOffset = nprops;
9093 nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Padding);
9096 // ...and the inherited properties at the end of the array.
9097 size_t inheritedOffset = nprops;
9099 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
9100 textShadowOffset = nprops;
9101 nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Text);
9104 void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
9105 AutoCSSValueArray dataArray(dataStorage, nprops);
9107 /* We're relying on the use of |aStyleContext| not mutating it! */
9108 nsRuleData ruleData(inheritBits, dataArray.get(),
9109 aStyleContext->PresContext(), aStyleContext);
9111 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
9112 ruleData.mValueOffsets[eStyleStruct_Background] = backgroundOffset;
9115 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
9116 ruleData.mValueOffsets[eStyleStruct_Border] = borderOffset;
9119 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
9120 ruleData.mValueOffsets[eStyleStruct_Padding] = paddingOffset;
9123 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
9124 ruleData.mValueOffsets[eStyleStruct_Text] = textShadowOffset;
9127 static const nsCSSProperty backgroundValues[] = {
9128 eCSSProperty_background_color,
9129 eCSSProperty_background_image,
9132 static const nsCSSProperty borderValues[] = {
9133 eCSSProperty_border_top_color,
9134 eCSSProperty_border_top_style,
9135 eCSSProperty_border_top_width,
9136 eCSSProperty_border_right_color_value,
9137 eCSSProperty_border_right_style_value,
9138 eCSSProperty_border_right_width_value,
9139 eCSSProperty_border_bottom_color,
9140 eCSSProperty_border_bottom_style,
9141 eCSSProperty_border_bottom_width,
9142 eCSSProperty_border_left_color_value,
9143 eCSSProperty_border_left_style_value,
9144 eCSSProperty_border_left_width_value,
9145 eCSSProperty_border_start_color_value,
9146 eCSSProperty_border_start_style_value,
9147 eCSSProperty_border_start_width_value,
9148 eCSSProperty_border_end_color_value,
9149 eCSSProperty_border_end_style_value,
9150 eCSSProperty_border_end_width_value,
9151 eCSSProperty_border_top_left_radius,
9152 eCSSProperty_border_top_right_radius,
9153 eCSSProperty_border_bottom_right_radius,
9154 eCSSProperty_border_bottom_left_radius,
9157 static const nsCSSProperty paddingValues[] = {
9158 eCSSProperty_padding_top,
9159 eCSSProperty_padding_right_value,
9160 eCSSProperty_padding_bottom,
9161 eCSSProperty_padding_left_value,
9162 eCSSProperty_padding_start_value,
9163 eCSSProperty_padding_end_value,
9166 static const nsCSSProperty textShadowValues[] = {
9167 eCSSProperty_text_shadow
9170 // Number of properties we care about
9171 size_t nValues = 0;
9173 nsCSSValue* values[MOZ_ARRAY_LENGTH(backgroundValues) +
9174 MOZ_ARRAY_LENGTH(borderValues) +
9175 MOZ_ARRAY_LENGTH(paddingValues) +
9176 MOZ_ARRAY_LENGTH(textShadowValues)];
9178 nsCSSProperty properties[MOZ_ARRAY_LENGTH(backgroundValues) +
9179 MOZ_ARRAY_LENGTH(borderValues) +
9180 MOZ_ARRAY_LENGTH(paddingValues) +
9181 MOZ_ARRAY_LENGTH(textShadowValues)];
9183 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
9184 for (uint32_t i = 0, i_end = ArrayLength(backgroundValues);
9185 i < i_end; ++i) {
9186 properties[nValues] = backgroundValues[i];
9187 values[nValues++] = ruleData.ValueFor(backgroundValues[i]);
9191 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
9192 for (uint32_t i = 0, i_end = ArrayLength(borderValues);
9193 i < i_end; ++i) {
9194 properties[nValues] = borderValues[i];
9195 values[nValues++] = ruleData.ValueFor(borderValues[i]);
9199 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
9200 for (uint32_t i = 0, i_end = ArrayLength(paddingValues);
9201 i < i_end; ++i) {
9202 properties[nValues] = paddingValues[i];
9203 values[nValues++] = ruleData.ValueFor(paddingValues[i]);
9207 if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
9208 for (uint32_t i = 0, i_end = ArrayLength(textShadowValues);
9209 i < i_end; ++i) {
9210 properties[nValues] = textShadowValues[i];
9211 values[nValues++] = ruleData.ValueFor(textShadowValues[i]);
9215 nsStyleContext* styleContext = aStyleContext;
9217 // We need to be careful not to count styles covered up by user-important or
9218 // UA-important declarations. But we do want to catch explicit inherit
9219 // styling in those and check our parent style context to see whether we have
9220 // user styling for those properties. Note that we don't care here about
9221 // inheritance due to lack of a specified value, since all the properties we
9222 // care about are reset properties.
9223 bool haveExplicitUAInherit;
9224 do {
9225 haveExplicitUAInherit = false;
9226 for (nsRuleNode* ruleNode = styleContext->RuleNode(); ruleNode;
9227 ruleNode = ruleNode->GetParent()) {
9228 nsIStyleRule *rule = ruleNode->GetRule();
9229 if (rule) {
9230 ruleData.mLevel = ruleNode->GetLevel();
9231 ruleData.mIsImportantRule = ruleNode->IsImportantRule();
9233 rule->MapRuleInfoInto(&ruleData);
9235 if (ruleData.mLevel == nsStyleSet::eAgentSheet ||
9236 ruleData.mLevel == nsStyleSet::eUserSheet) {
9237 // This is a rule whose effect we want to ignore, so if any of
9238 // the properties we care about were set, set them to the dummy
9239 // value that they'll never otherwise get.
9240 for (uint32_t i = 0; i < nValues; ++i) {
9241 nsCSSUnit unit = values[i]->GetUnit();
9242 if (unit != eCSSUnit_Null &&
9243 unit != eCSSUnit_Dummy &&
9244 unit != eCSSUnit_DummyInherit) {
9245 if (unit == eCSSUnit_Inherit ||
9246 (i >= inheritedOffset && unit == eCSSUnit_Unset)) {
9247 haveExplicitUAInherit = true;
9248 values[i]->SetDummyInheritValue();
9249 } else {
9250 values[i]->SetDummyValue();
9254 } else {
9255 // If any of the values we care about was set by the above rule,
9256 // we have author style.
9257 for (uint32_t i = 0; i < nValues; ++i) {
9258 if (values[i]->GetUnit() != eCSSUnit_Null &&
9259 values[i]->GetUnit() != eCSSUnit_Dummy && // see above
9260 values[i]->GetUnit() != eCSSUnit_DummyInherit) {
9261 // If author colors are not allowed, only claim to have
9262 // author-specified rules if we're looking at a non-color
9263 // property or if we're looking at the background color and it's
9264 // set to transparent. Anything else should get set to a dummy
9265 // value instead.
9266 if (aAuthorColorsAllowed ||
9267 !nsCSSProps::PropHasFlags(properties[i],
9268 CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED) ||
9269 (properties[i] == eCSSProperty_background_color &&
9270 !values[i]->IsNonTransparentColor())) {
9271 return true;
9274 values[i]->SetDummyValue();
9281 if (haveExplicitUAInherit) {
9282 // reset all the eCSSUnit_Null values to eCSSUnit_Dummy (since they're
9283 // not styled by the author, or by anyone else), and then reset all the
9284 // eCSSUnit_DummyInherit values to eCSSUnit_Null (so we will be able to
9285 // detect them being styled by the author) and move up to our parent
9286 // style context.
9287 for (uint32_t i = 0; i < nValues; ++i)
9288 if (values[i]->GetUnit() == eCSSUnit_Null)
9289 values[i]->SetDummyValue();
9290 for (uint32_t i = 0; i < nValues; ++i)
9291 if (values[i]->GetUnit() == eCSSUnit_DummyInherit)
9292 values[i]->Reset();
9293 styleContext = styleContext->GetParent();
9295 } while (haveExplicitUAInherit && styleContext);
9297 return false;
9300 /* static */
9301 bool
9302 nsRuleNode::ComputeColor(const nsCSSValue& aValue, nsPresContext* aPresContext,
9303 nsStyleContext* aStyleContext, nscolor& aResult)
9305 MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Inherit,
9306 "aValue shouldn't have eCSSUnit_Inherit");
9307 MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Initial,
9308 "aValue shouldn't have eCSSUnit_Initial");
9309 MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Unset,
9310 "aValue shouldn't have eCSSUnit_Unset");
9312 bool canStoreInRuleTree;
9313 bool ok = SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aStyleContext,
9314 aResult, canStoreInRuleTree);
9315 MOZ_ASSERT(ok || !(aPresContext && aStyleContext));
9316 return ok;