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