Line data Source code
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/. */
6 :
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 : */
11 :
12 : #include "nsRuleNode.h"
13 :
14 : #include <algorithm>
15 : #include <functional>
16 :
17 : #include "mozilla/ArrayUtils.h"
18 : #include "mozilla/Assertions.h"
19 : #include "mozilla/DebugOnly.h"
20 : #include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for PlaybackDirection
21 : #include "mozilla/Likely.h"
22 : #include "mozilla/LookAndFeel.h"
23 : #include "mozilla/Maybe.h"
24 : #include "mozilla/OperatorNewExtensions.h"
25 : #include "mozilla/Unused.h"
26 :
27 : #include "mozilla/css/Declaration.h"
28 : #include "mozilla/TypeTraits.h"
29 :
30 : #include "gfxContext.h"
31 : #include "nsAlgorithm.h" // for clamped()
32 : #include "nscore.h"
33 : #include "nsCRT.h" // for IsAscii()
34 : #include "nsIWidget.h"
35 : #include "nsIPresShell.h"
36 : #include "nsFontMetrics.h"
37 : #include "gfxFont.h"
38 : #include "nsCSSAnonBoxes.h"
39 : #include "nsCSSPseudoElements.h"
40 : #include "nsThemeConstants.h"
41 : #include "PLDHashTable.h"
42 : #include "GeckoStyleContext.h"
43 : #include "nsStyleSet.h"
44 : #include "nsStyleStruct.h"
45 : #include "nsSize.h"
46 : #include "nsRuleData.h"
47 : #include "nsIStyleRule.h"
48 : #include "nsBidiUtils.h"
49 : #include "nsStyleStructInlines.h"
50 : #include "nsCSSProps.h"
51 : #include "nsTArray.h"
52 : #include "nsContentUtils.h"
53 : #include "CSSCalc.h"
54 : #include "nsPrintfCString.h"
55 : #include "nsStyleUtil.h"
56 : #include "nsIDocument.h"
57 : #include "prtime.h"
58 : #include "CSSVariableResolver.h"
59 : #include "nsCSSParser.h"
60 : #include "CounterStyleManager.h"
61 : #include "nsCSSPropertyIDSet.h"
62 : #include "mozilla/RuleNodeCacheConditions.h"
63 : #include "nsDeviceContext.h"
64 : #include "nsQueryObject.h"
65 : #include "nsUnicodeProperties.h"
66 :
67 : #if defined(_MSC_VER) || defined(__MINGW32__)
68 : #include <malloc.h>
69 : #ifdef _MSC_VER
70 : #define alloca _alloca
71 : #endif
72 : #endif
73 : #ifdef SOLARIS
74 : #include <alloca.h>
75 : #endif
76 :
77 : using std::max;
78 : using std::min;
79 : using namespace mozilla;
80 : using namespace mozilla::dom;
81 :
82 : namespace mozilla {
83 :
84 : enum UnsetAction
85 : {
86 : eUnsetInitial,
87 : eUnsetInherit
88 : };
89 :
90 : } // namespace mozilla
91 :
92 : void*
93 50 : nsConditionalResetStyleData::GetConditionalStyleData(nsStyleStructID aSID,
94 : GeckoStyleContext* aStyleContext) const
95 : {
96 50 : Entry* e = static_cast<Entry*>(mEntries[aSID]);
97 50 : MOZ_ASSERT(e, "if mConditionalBits bit is set, we must have at least one "
98 : "conditional style struct");
99 0 : do {
100 50 : if (e->mConditions.Matches(aStyleContext)) {
101 50 : void* data = e->mStyleStruct;
102 :
103 : // For reset structs with conditions, we cache the data on the
104 : // style context.
105 : // Tell the style context that it doesn't own the data
106 50 : aStyleContext->AddStyleBit(GetBitForSID(aSID));
107 50 : aStyleContext->SetStyle(aSID, data);
108 :
109 50 : return data;
110 : }
111 0 : e = e->mNext;
112 0 : } while (e);
113 0 : return nullptr;
114 : }
115 :
116 : // Creates an imgRequestProxy based on the specified value in aValue and
117 : // returns it. If the nsPresContext is static (e.g. for printing), then
118 : // a static request (i.e. showing the first frame, without animation)
119 : // will be created.
120 : static already_AddRefed<imgRequestProxy>
121 141 : CreateImageRequest(nsPresContext* aPresContext, const nsCSSValue& aValue)
122 : {
123 : RefPtr<imgRequestProxy> req =
124 282 : aValue.GetPossiblyStaticImageValue(aPresContext->Document(),
125 282 : aPresContext);
126 282 : return req.forget();
127 : }
128 :
129 : static already_AddRefed<nsStyleImageRequest>
130 141 : CreateStyleImageRequest(nsPresContext* aPresContext, const nsCSSValue& aValue,
131 : nsStyleImageRequest::Mode aModeFlags =
132 : nsStyleImageRequest::Mode::Track)
133 : {
134 141 : css::ImageValue* imageValue = aValue.GetImageStructValue();
135 : ImageTracker* imageTracker =
136 282 : (aModeFlags & nsStyleImageRequest::Mode::Track)
137 141 : ? aPresContext->Document()->ImageTracker()
138 282 : : nullptr;
139 282 : RefPtr<imgRequestProxy> proxy = CreateImageRequest(aPresContext, aValue);
140 : RefPtr<nsStyleImageRequest> request =
141 423 : new nsStyleImageRequest(aModeFlags, proxy, imageValue, imageTracker);
142 282 : return request.forget();
143 : }
144 :
145 : static void
146 : SetStyleShapeSourceToCSSValue(StyleShapeSource* aShapeSource,
147 : const nsCSSValue* aValue,
148 : GeckoStyleContext* aStyleContext,
149 : nsPresContext* aPresContext,
150 : RuleNodeCacheConditions& aConditions);
151 :
152 : /* Helper function to convert a CSS <position> specified value into its
153 : * computed-style form. */
154 : static void
155 : ComputePositionValue(GeckoStyleContext* aStyleContext,
156 : const nsCSSValue& aValue,
157 : Position& aComputedValue,
158 : RuleNodeCacheConditions& aConditions);
159 :
160 : /*
161 : * For storage of an |nsRuleNode|'s children in a PLDHashTable.
162 : */
163 :
164 : struct ChildrenHashEntry : public PLDHashEntryHdr {
165 : // key is |mRuleNode->GetKey()|
166 : nsRuleNode *mRuleNode;
167 : };
168 :
169 : /* static */ PLDHashNumber
170 1797 : nsRuleNode::ChildrenHashHashKey(const void *aKey)
171 : {
172 : const nsRuleNode::Key *key =
173 1797 : static_cast<const nsRuleNode::Key*>(aKey);
174 : // Disagreement on importance and level for the same rule is extremely
175 : // rare, so hash just on the rule.
176 1797 : return PLDHashTable::HashVoidPtrKeyStub(key->mRule);
177 : }
178 :
179 : /* static */ bool
180 1669 : nsRuleNode::ChildrenHashMatchEntry(const PLDHashEntryHdr *aHdr,
181 : const void *aKey)
182 : {
183 : const ChildrenHashEntry *entry =
184 1669 : static_cast<const ChildrenHashEntry*>(aHdr);
185 : const nsRuleNode::Key *key =
186 1669 : static_cast<const nsRuleNode::Key*>(aKey);
187 1669 : return entry->mRuleNode->GetKey() == *key;
188 : }
189 :
190 : /* static */ const PLDHashTableOps
191 : nsRuleNode::ChildrenHashOps = {
192 : // It's probably better to allocate the table itself using malloc and
193 : // free rather than the pres shell's arena because the table doesn't
194 : // grow very often and the pres shell's arena doesn't recycle very
195 : // large size allocations.
196 : ChildrenHashHashKey,
197 : ChildrenHashMatchEntry,
198 : PLDHashTable::MoveEntryStub,
199 : PLDHashTable::ClearEntryStub,
200 : nullptr
201 : };
202 :
203 :
204 : // EnsureBlockDisplay:
205 : // Never change display:none or display:contents *ever*, otherwise:
206 : // - if the display value (argument) is not a block-type
207 : // then we set it to a valid block display value
208 : // - For enforcing the floated/positioned element CSS2 rules
209 : // - We allow the behavior of "list-item" to be customized.
210 : // CSS21 says that position/float do not convert 'list-item' to 'block',
211 : // but it explicitly does not define whether 'list-item' should be
212 : // converted to block *on the root node*. To allow for flexibility
213 : // (so that we don't have to support a list-item root node), this method
214 : // lets the caller pick either behavior, using the 'aConvertListItem' arg.
215 : // Reference: http://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo
216 : /* static */
217 : void
218 193 : nsRuleNode::EnsureBlockDisplay(StyleDisplay& display,
219 : bool aConvertListItem /* = false */)
220 : {
221 : // see if the display value is already a block
222 193 : switch (display) {
223 : case StyleDisplay::ListItem:
224 0 : if (aConvertListItem) {
225 0 : display = StyleDisplay::Block;
226 0 : break;
227 : } // else, fall through to share the 'break' for non-changing display vals
228 : MOZ_FALLTHROUGH;
229 : case StyleDisplay::None:
230 : case StyleDisplay::Contents:
231 : // never change display:none or display:contents *ever*
232 : case StyleDisplay::Table:
233 : case StyleDisplay::Block:
234 : case StyleDisplay::Flex:
235 : case StyleDisplay::WebkitBox:
236 : case StyleDisplay::Grid:
237 : case StyleDisplay::FlowRoot:
238 : // do not muck with these at all - already blocks
239 : // This is equivalent to nsStyleDisplay::IsBlockOutside. (XXX Maybe we
240 : // should just call that?)
241 : // This needs to match the check done in
242 : // nsCSSFrameConstructor::FindMathMLData for <math>.
243 85 : break;
244 :
245 : case StyleDisplay::InlineTable:
246 : // make inline tables into tables
247 0 : display = StyleDisplay::Table;
248 0 : break;
249 :
250 : case StyleDisplay::InlineFlex:
251 : // make inline flex containers into flex containers
252 0 : display = StyleDisplay::Flex;
253 0 : break;
254 :
255 : case StyleDisplay::WebkitInlineBox:
256 : // make -webkit-inline-box containers into -webkit-box containers
257 0 : display = StyleDisplay::WebkitBox;
258 0 : break;
259 :
260 : case StyleDisplay::InlineGrid:
261 : // make inline grid containers into grid containers
262 0 : display = StyleDisplay::Grid;
263 0 : break;
264 :
265 : default:
266 : // make it a block
267 108 : display = StyleDisplay::Block;
268 : }
269 193 : }
270 :
271 : // EnsureInlineDisplay:
272 : // - if the display value (argument) is not an inline type
273 : // then we set it to a valid inline display value
274 : /* static */
275 : void
276 0 : nsRuleNode::EnsureInlineDisplay(StyleDisplay& display)
277 : {
278 : // see if the display value is already inline
279 0 : switch (display) {
280 : case StyleDisplay::Block:
281 : case StyleDisplay::FlowRoot:
282 0 : display = StyleDisplay::InlineBlock;
283 0 : break;
284 : case StyleDisplay::Table:
285 0 : display = StyleDisplay::InlineTable;
286 0 : break;
287 : case StyleDisplay::Flex:
288 0 : display = StyleDisplay::InlineFlex;
289 0 : break;
290 : case StyleDisplay::WebkitBox:
291 0 : display = StyleDisplay::WebkitInlineBox;
292 0 : break;
293 : case StyleDisplay::Grid:
294 0 : display = StyleDisplay::InlineGrid;
295 0 : break;
296 : case StyleDisplay::MozBox:
297 0 : display = StyleDisplay::MozInlineBox;
298 0 : break;
299 : case StyleDisplay::MozStack:
300 0 : display = StyleDisplay::MozInlineStack;
301 0 : break;
302 : default:
303 0 : break; // Do nothing
304 : }
305 0 : }
306 :
307 : static nscoord CalcLengthWith(const nsCSSValue& aValue,
308 : nscoord aFontSize,
309 : const nsStyleFont* aStyleFont,
310 : nsStyleContext* aStyleContext,
311 : nsPresContext* aPresContext,
312 : bool aUseProvidedRootEmSize,
313 : bool aUseUserFontSet,
314 : RuleNodeCacheConditions& aConditions);
315 :
316 : struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
317 : public css::FloatCoeffsAlreadyNormalizedOps
318 : {
319 : // Declare that we have floats as coefficients so that we unambiguously
320 : // resolve coeff_type (BasicCoordCalcOps and FloatCoeffsAlreadyNormalizedOps
321 : // both have |typedef float coeff_type|).
322 : typedef float coeff_type;
323 :
324 : // All of the parameters to CalcLengthWith except aValue.
325 : const nscoord mFontSize;
326 : const nsStyleFont* const mStyleFont;
327 : nsStyleContext* const mStyleContext;
328 : nsPresContext* const mPresContext;
329 : const bool mUseProvidedRootEmSize;
330 : const bool mUseUserFontSet;
331 : RuleNodeCacheConditions& mConditions;
332 :
333 0 : CalcLengthCalcOps(nscoord aFontSize, const nsStyleFont* aStyleFont,
334 : nsStyleContext* aStyleContext, nsPresContext* aPresContext,
335 : bool aUseProvidedRootEmSize, bool aUseUserFontSet,
336 : RuleNodeCacheConditions& aConditions)
337 0 : : mFontSize(aFontSize),
338 : mStyleFont(aStyleFont),
339 : mStyleContext(aStyleContext),
340 : mPresContext(aPresContext),
341 : mUseProvidedRootEmSize(aUseProvidedRootEmSize),
342 : mUseUserFontSet(aUseUserFontSet),
343 0 : mConditions(aConditions)
344 : {
345 0 : }
346 :
347 0 : result_type ComputeLeafValue(const nsCSSValue& aValue)
348 : {
349 0 : return CalcLengthWith(aValue, mFontSize, mStyleFont,
350 0 : mStyleContext, mPresContext, mUseProvidedRootEmSize,
351 0 : mUseUserFontSet, mConditions);
352 : }
353 : };
354 :
355 19 : static inline nscoord ScaleCoordRound(const nsCSSValue& aValue, float aFactor)
356 : {
357 19 : return NSToCoordRoundWithClamp(aValue.GetFloatValue() * aFactor);
358 : }
359 :
360 0 : static inline nscoord ScaleViewportCoordTrunc(const nsCSSValue& aValue,
361 : nscoord aViewportSize)
362 : {
363 : // For units (like percentages and viewport units) where authors might
364 : // repeatedly use a value and expect some multiple of the value to be
365 : // smaller than a container, we need to use floor rather than round.
366 : // We need to use division by 100.0 rather than multiplication by 0.1f
367 : // to avoid introducing error.
368 0 : return NSToCoordTruncClamped(aValue.GetFloatValue() *
369 0 : aViewportSize / 100.0f);
370 : }
371 :
372 : /* static */
373 : already_AddRefed<nsFontMetrics>
374 8 : nsRuleNode::GetMetricsFor(nsPresContext* aPresContext,
375 : bool aIsVertical,
376 : const nsStyleFont* aStyleFont,
377 : nscoord aFontSize,
378 : bool aUseUserFontSet)
379 : {
380 16 : nsFont font = aStyleFont->mFont;
381 8 : font.size = aFontSize;
382 : gfxFont::Orientation orientation
383 8 : = aIsVertical ? gfxFont::eVertical : gfxFont::eHorizontal;
384 8 : nsFontMetrics::Params params;
385 8 : params.language = aStyleFont->mLanguage;
386 8 : params.explicitLanguage = aStyleFont->mExplicitLanguage;
387 8 : params.orientation = orientation;
388 8 : params.userFontSet =
389 8 : aUseUserFontSet ? aPresContext->GetUserFontSet() : nullptr;
390 8 : params.textPerf = aPresContext->GetTextPerfMetrics();
391 16 : return aPresContext->DeviceContext()->GetMetricsFor(font, params);
392 : }
393 :
394 : /* static */
395 : already_AddRefed<nsFontMetrics>
396 8 : nsRuleNode::GetMetricsFor(nsPresContext* aPresContext,
397 : nsStyleContext* aStyleContext,
398 : const nsStyleFont* aStyleFont,
399 : nscoord aFontSize, // overrides value from aStyleFont
400 : bool aUseUserFontSet)
401 : {
402 8 : bool isVertical = false;
403 8 : if (aStyleContext) {
404 8 : WritingMode wm(aStyleContext);
405 8 : if (wm.IsVertical() && !wm.IsSideways()) {
406 0 : isVertical = true;
407 : }
408 : }
409 : return nsRuleNode::GetMetricsFor(aPresContext, isVertical, aStyleFont,
410 8 : aFontSize, aUseUserFontSet);
411 : }
412 :
413 : /* static */
414 : void
415 0 : nsRuleNode::FixupNoneGeneric(nsFont* aFont,
416 : const nsPresContext* aPresContext,
417 : uint8_t aGenericFontID,
418 : const nsFont* aDefaultVariableFont)
419 : {
420 : bool useDocumentFonts =
421 0 : aPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
422 0 : if (aGenericFontID == kGenericFont_NONE ||
423 0 : (!useDocumentFonts && (aGenericFontID == kGenericFont_cursive ||
424 : aGenericFontID == kGenericFont_fantasy))) {
425 : FontFamilyType defaultGeneric =
426 0 : aDefaultVariableFont->fontlist.FirstGeneric();
427 0 : MOZ_ASSERT(aDefaultVariableFont->fontlist.Length() == 1 &&
428 : (defaultGeneric == eFamily_serif ||
429 : defaultGeneric == eFamily_sans_serif));
430 0 : if (defaultGeneric != eFamily_none) {
431 0 : if (useDocumentFonts) {
432 0 : aFont->fontlist.SetDefaultFontType(defaultGeneric);
433 : } else {
434 : // Either prioritize the first generic in the list,
435 : // or (if there isn't one) prepend the default variable font.
436 0 : if (!aFont->fontlist.PrioritizeFirstGeneric()) {
437 0 : aFont->fontlist.PrependGeneric(defaultGeneric);
438 : }
439 : }
440 0 : }
441 : } else {
442 0 : aFont->fontlist.SetDefaultFontType(eFamily_none);
443 : }
444 0 : }
445 :
446 : /* static */
447 : void
448 12 : nsRuleNode::ApplyMinFontSize(nsStyleFont* aFont,
449 : const nsPresContext* aPresContext,
450 : nscoord aMinFontSize)
451 : {
452 12 : nscoord fontSize = aFont->mSize;
453 :
454 : // enforce the user' specified minimum font-size on the value that we expose
455 : // (but don't change font-size:0, since that would unhide hidden text)
456 12 : if (fontSize > 0) {
457 12 : if (aMinFontSize < 0) {
458 0 : aMinFontSize = 0;
459 : } else {
460 12 : aMinFontSize = (aMinFontSize * aFont->mMinFontSizeRatio) / 100;
461 : }
462 12 : if (fontSize < aMinFontSize && !aPresContext->IsChrome()) {
463 : // override the minimum font-size constraint
464 0 : fontSize = aMinFontSize;
465 : }
466 : }
467 12 : aFont->mFont.size = fontSize;
468 12 : }
469 :
470 0 : static nsSize CalcViewportUnitsScale(nsPresContext* aPresContext)
471 : {
472 : // The caller is making use of viewport units, so notify the pres context
473 : // that it will need to rebuild the rule tree if the size of the viewport
474 : // changes.
475 0 : aPresContext->SetUsesViewportUnits(true);
476 :
477 : // The default (when we have 'overflow: auto' on the root element, or
478 : // trivially for 'overflow: hidden' since we never have scrollbars in that
479 : // case) is to define the scale of the viewport units without considering
480 : // scrollbars.
481 0 : nsSize viewportSize(aPresContext->GetVisibleArea().Size());
482 :
483 : // Check for 'overflow: scroll' styles on the root scroll frame. If we find
484 : // any, the standard requires us to take scrollbars into account.
485 : nsIScrollableFrame* scrollFrame =
486 0 : aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
487 0 : if (scrollFrame) {
488 0 : ScrollbarStyles styles(scrollFrame->GetScrollbarStyles());
489 :
490 0 : if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL ||
491 0 : styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
492 : // Gather scrollbar size information.
493 : RefPtr<gfxContext> context =
494 0 : aPresContext->PresShell()->CreateReferenceRenderingContext();
495 0 : nsMargin sizes(scrollFrame->GetDesiredScrollbarSizes(aPresContext, context));
496 :
497 0 : if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
498 : // 'overflow-x: scroll' means we must consider the horizontal scrollbar,
499 : // which affects the scale of viewport height units.
500 0 : viewportSize.height -= sizes.TopBottom();
501 : }
502 :
503 0 : if (styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
504 : // 'overflow-y: scroll' means we must consider the vertical scrollbar,
505 : // which affects the scale of viewport width units.
506 0 : viewportSize.width -= sizes.LeftRight();
507 : }
508 : }
509 : }
510 :
511 0 : return viewportSize;
512 : }
513 :
514 : // If |aStyleFont| is nullptr, aStyleContext->StyleFont() is used.
515 : //
516 : // In case that |aValue| is rem unit, if |aStyleContext| is null, callers must
517 : // specify a valid |aStyleFont| and |aUseProvidedRootEmSize| must be true so
518 : // that we can get the length from |aStyleFont|.
519 2514 : static nscoord CalcLengthWith(const nsCSSValue& aValue,
520 : nscoord aFontSize,
521 : const nsStyleFont* aStyleFont,
522 : nsStyleContext* aStyleContext,
523 : nsPresContext* aPresContext,
524 : bool aUseProvidedRootEmSize,
525 : // aUseUserFontSet should always be true
526 : // except when called from
527 : // CalcLengthWithInitialFont.
528 : bool aUseUserFontSet,
529 : RuleNodeCacheConditions& aConditions)
530 : {
531 2514 : NS_ASSERTION(aValue.IsLengthUnit() || aValue.IsCalcUnit(),
532 : "not a length or calc unit");
533 2514 : NS_ASSERTION(aStyleFont || aStyleContext,
534 : "Must have style data");
535 2514 : NS_ASSERTION(aStyleContext || aUseProvidedRootEmSize,
536 : "Must have style context or specify aUseProvidedRootEmSize");
537 2514 : NS_ASSERTION(aPresContext, "Must have prescontext");
538 :
539 2514 : if (aValue.IsFixedLengthUnit()) {
540 0 : return aValue.GetFixedLength(aPresContext);
541 : }
542 2514 : if (aValue.IsPixelLengthUnit()) {
543 2495 : return aValue.GetPixelLength();
544 : }
545 19 : if (aValue.IsCalcUnit()) {
546 : // For properties for which lengths are the *only* units accepted in
547 : // calc(), we can handle calc() here and just compute a final
548 : // result. We ensure that we don't get to this code for other
549 : // properties by not calling CalcLength in those cases: SetCoord
550 : // only calls CalcLength for a calc when it is appropriate to do so.
551 : CalcLengthCalcOps ops(aFontSize, aStyleFont,
552 : aStyleContext, aPresContext,
553 : aUseProvidedRootEmSize, aUseUserFontSet,
554 0 : aConditions);
555 0 : return css::ComputeCalc(aValue, ops);
556 : }
557 19 : switch (aValue.GetUnit()) {
558 : // nsPresContext::SetVisibleArea and
559 : // nsPresContext::MediaFeatureValuesChanged handle dynamic changes
560 : // of the basis for viewport units by rebuilding the rule tree and
561 : // style context tree. Not caching them in the rule tree wouldn't
562 : // be sufficient to handle these changes because we also need a way
563 : // to get rid of cached values in the style context tree without any
564 : // changes in specified style. We can either do this by not caching
565 : // in the rule tree and then throwing away the style context tree
566 : // for dynamic viewport size changes, or by allowing caching in the
567 : // rule tree and using the existing rebuild style data path that
568 : // throws away the style context and the rule tree.
569 : // Thus we do cache viewport units in the rule tree. This allows us
570 : // to benefit from the performance advantages of the rule tree
571 : // (e.g., faster dynamic changes on other things, like transforms)
572 : // and allows us not to need an additional code path, in exchange
573 : // for an increased cost to dynamic changes to the viewport size
574 : // when viewport units are in use.
575 : case eCSSUnit_ViewportWidth: {
576 0 : nscoord viewportWidth = CalcViewportUnitsScale(aPresContext).width;
577 0 : return ScaleViewportCoordTrunc(aValue, viewportWidth);
578 : }
579 : case eCSSUnit_ViewportHeight: {
580 0 : nscoord viewportHeight = CalcViewportUnitsScale(aPresContext).height;
581 0 : return ScaleViewportCoordTrunc(aValue, viewportHeight);
582 : }
583 : case eCSSUnit_ViewportMin: {
584 0 : nsSize vuScale(CalcViewportUnitsScale(aPresContext));
585 0 : nscoord viewportMin = min(vuScale.width, vuScale.height);
586 0 : return ScaleViewportCoordTrunc(aValue, viewportMin);
587 : }
588 : case eCSSUnit_ViewportMax: {
589 0 : nsSize vuScale(CalcViewportUnitsScale(aPresContext));
590 0 : nscoord viewportMax = max(vuScale.width, vuScale.height);
591 0 : return ScaleViewportCoordTrunc(aValue, viewportMax);
592 : }
593 : // While we could deal with 'rem' units correctly by simply not
594 : // caching any data that uses them in the rule tree, it's valuable
595 : // to store them in the rule tree (for faster dynamic changes of
596 : // other things). And since the font size of the root element
597 : // changes rarely, we instead handle dynamic changes to the root
598 : // element's font size by rebuilding all style data in
599 : // nsCSSFrameConstructor::RestyleElement.
600 : case eCSSUnit_RootEM: {
601 0 : aPresContext->SetUsesRootEMUnits(true);
602 : nscoord rootFontSize;
603 :
604 : // NOTE: Be very careful with |styleFont|, since we haven't added any
605 : // conditions to aConditions or set it to uncacheable yet, so we don't
606 : // want to introduce any dependencies on aStyleContext's data here.
607 : const nsStyleFont *styleFont =
608 0 : aStyleFont ? aStyleFont : aStyleContext->StyleFont();
609 :
610 0 : if (aUseProvidedRootEmSize) {
611 : // We should use the provided aFontSize as the reference length to
612 : // scale. This only happens when we are calculating font-size or
613 : // an equivalent (scriptminsize or CalcLengthWithInitialFont) on
614 : // the root element, in which case aFontSize is already the
615 : // value we want.
616 0 : if (aFontSize == -1) {
617 : // XXX Should this be styleFont->mSize instead to avoid taking
618 : // minfontsize prefs into account?
619 0 : aFontSize = styleFont->mFont.size;
620 : }
621 0 : rootFontSize = aFontSize;
622 0 : } else if (aStyleContext && !aStyleContext->GetParent()) {
623 : // This is the root element (XXX we don't really know this, but
624 : // nsRuleNode::SetFont makes the same assumption!), so we should
625 : // use StyleFont on this context to get the root element's
626 : // font size.
627 0 : rootFontSize = styleFont->mFont.size;
628 : } else {
629 : // This is not the root element or we are calculating something other
630 : // than font size, so rem is relative to the root element's font size.
631 : // Find the root style context by walking up the style context tree.
632 : // NOTE: We should not call ResolveStyleFor() against the root element
633 : // to obtain the root style here because it may lead to reentrant call
634 : // of nsStyleSet::GetContext().
635 0 : nsStyleContext* rootStyle = aStyleContext;
636 0 : while (rootStyle->GetParent()) {
637 0 : rootStyle = rootStyle->GetParent();
638 : }
639 0 : const nsStyleFont *rootStyleFont = rootStyle->StyleFont();
640 0 : rootFontSize = rootStyleFont->mFont.size;
641 : }
642 :
643 0 : return ScaleCoordRound(aValue, float(rootFontSize));
644 : }
645 : default:
646 : // Fall through to the code for units that can't be stored in the
647 : // rule tree because they depend on font data.
648 19 : break;
649 : }
650 : // Common code for units that depend on the element's font data and
651 : // thus can't be stored in the rule tree:
652 : const nsStyleFont *styleFont =
653 19 : aStyleFont ? aStyleFont : aStyleContext->StyleFont();
654 19 : if (aFontSize == -1) {
655 : // XXX Should this be styleFont->mSize instead to avoid taking minfontsize
656 : // prefs into account?
657 19 : aFontSize = styleFont->mFont.size;
658 : }
659 19 : switch (aValue.GetUnit()) {
660 : case eCSSUnit_EM: {
661 11 : if (aValue.GetFloatValue() == 0.0f) {
662 : // Don't call SetFontSizeDependency for '0em'.
663 0 : return 0;
664 : }
665 : // CSS2.1 specifies that this unit scales to the computed font
666 : // size, not the em-width in the font metrics, despite the name.
667 11 : aConditions.SetFontSizeDependency(aFontSize);
668 11 : return ScaleCoordRound(aValue, float(aFontSize));
669 : }
670 : case eCSSUnit_XHeight: {
671 0 : aPresContext->SetUsesExChUnits(true);
672 : RefPtr<nsFontMetrics> fm =
673 0 : nsRuleNode::GetMetricsFor(aPresContext, aStyleContext, styleFont,
674 0 : aFontSize, aUseUserFontSet);
675 0 : aConditions.SetUncacheable();
676 0 : return ScaleCoordRound(aValue, float(fm->XHeight()));
677 : }
678 : case eCSSUnit_Char: {
679 8 : aPresContext->SetUsesExChUnits(true);
680 : RefPtr<nsFontMetrics> fm =
681 16 : nsRuleNode::GetMetricsFor(aPresContext, aStyleContext, styleFont,
682 16 : aFontSize, aUseUserFontSet);
683 : gfxFloat zeroWidth =
684 : fm->GetThebesFontGroup()->GetFirstValidFont()->
685 8 : GetMetrics(fm->Orientation()).zeroOrAveCharWidth;
686 :
687 8 : aConditions.SetUncacheable();
688 8 : return ScaleCoordRound(aValue, ceil(aPresContext->AppUnitsPerDevPixel() *
689 8 : zeroWidth));
690 : }
691 : default:
692 0 : NS_NOTREACHED("unexpected unit");
693 0 : break;
694 : }
695 0 : return 0;
696 : }
697 :
698 : /* static */ nscoord
699 2452 : nsRuleNode::CalcLength(const nsCSSValue& aValue,
700 : nsStyleContext* aStyleContext,
701 : nsPresContext* aPresContext,
702 : RuleNodeCacheConditions& aConditions)
703 : {
704 2452 : NS_ASSERTION(aStyleContext, "Must have style data");
705 :
706 : return CalcLengthWith(aValue, -1, nullptr,
707 : aStyleContext, aPresContext,
708 2452 : false, true, aConditions);
709 : }
710 :
711 : /* Inline helper function to redirect requests to CalcLength. */
712 2424 : static inline nscoord CalcLength(const nsCSSValue& aValue,
713 : nsStyleContext* aStyleContext,
714 : nsPresContext* aPresContext,
715 : RuleNodeCacheConditions& aConditions)
716 : {
717 : return nsRuleNode::CalcLength(aValue, aStyleContext,
718 2424 : aPresContext, aConditions);
719 : }
720 :
721 : /* static */ nscoord
722 62 : nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
723 : const nsCSSValue& aValue)
724 : {
725 124 : nsStyleFont defaultFont(aPresContext); // FIXME: best language?
726 62 : RuleNodeCacheConditions conditions;
727 : return CalcLengthWith(aValue, -1, &defaultFont,
728 : nullptr, aPresContext,
729 124 : true, false, conditions);
730 : }
731 :
732 : struct LengthPercentPairCalcOps : public css::FloatCoeffsAlreadyNormalizedOps
733 : {
734 : typedef nsRuleNode::ComputedCalc result_type;
735 :
736 127 : LengthPercentPairCalcOps(nsStyleContext* aContext,
737 : nsPresContext* aPresContext,
738 : RuleNodeCacheConditions& aConditions)
739 127 : : mContext(aContext),
740 : mPresContext(aPresContext),
741 : mConditions(aConditions),
742 127 : mHasPercent(false) {}
743 :
744 : nsStyleContext* mContext;
745 : nsPresContext* mPresContext;
746 : RuleNodeCacheConditions& mConditions;
747 : bool mHasPercent;
748 :
749 220 : result_type ComputeLeafValue(const nsCSSValue& aValue)
750 : {
751 220 : if (aValue.GetUnit() == eCSSUnit_Percent) {
752 3 : mHasPercent = true;
753 3 : return result_type(0, aValue.GetPercentValue());
754 : }
755 434 : return result_type(CalcLength(aValue, mContext, mPresContext,
756 : mConditions),
757 217 : 0.0f);
758 : }
759 :
760 : result_type
761 93 : MergeAdditive(nsCSSUnit aCalcFunction,
762 : result_type aValue1, result_type aValue2)
763 : {
764 93 : if (aCalcFunction == eCSSUnit_Calc_Plus) {
765 130 : return result_type(NSCoordSaturatingAdd(aValue1.mLength,
766 : aValue2.mLength),
767 130 : aValue1.mPercent + aValue2.mPercent);
768 : }
769 28 : MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Minus,
770 : "min() and max() are not allowed in calc() on transform");
771 56 : return result_type(NSCoordSaturatingSubtract(aValue1.mLength,
772 : aValue2.mLength, 0),
773 56 : aValue1.mPercent - aValue2.mPercent);
774 : }
775 :
776 : result_type
777 88 : MergeMultiplicativeL(nsCSSUnit aCalcFunction,
778 : float aValue1, result_type aValue2)
779 : {
780 88 : MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_L,
781 : "unexpected unit");
782 176 : return result_type(NSCoordSaturatingMultiply(aValue2.mLength, aValue1),
783 264 : aValue1 * aValue2.mPercent);
784 : }
785 :
786 : result_type
787 13 : MergeMultiplicativeR(nsCSSUnit aCalcFunction,
788 : result_type aValue1, float aValue2)
789 : {
790 13 : MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_R ||
791 : aCalcFunction == eCSSUnit_Calc_Divided,
792 : "unexpected unit");
793 13 : if (aCalcFunction == eCSSUnit_Calc_Divided) {
794 13 : aValue2 = 1.0f / aValue2;
795 : }
796 26 : return result_type(NSCoordSaturatingMultiply(aValue1.mLength, aValue2),
797 39 : aValue1.mPercent * aValue2);
798 : }
799 :
800 : };
801 :
802 : static void
803 127 : SpecifiedCalcToComputedCalc(const nsCSSValue& aValue, nsStyleCoord& aCoord,
804 : nsStyleContext* aStyleContext,
805 : RuleNodeCacheConditions& aConditions)
806 : {
807 : LengthPercentPairCalcOps ops(aStyleContext, aStyleContext->PresContext(),
808 127 : aConditions);
809 127 : nsRuleNode::ComputedCalc vals = ComputeCalc(aValue, ops);
810 :
811 127 : nsStyleCoord::Calc* calcObj = new nsStyleCoord::Calc;
812 :
813 127 : calcObj->mLength = vals.mLength;
814 127 : calcObj->mPercent = vals.mPercent;
815 127 : calcObj->mHasPercent = ops.mHasPercent;
816 :
817 127 : aCoord.SetCalcValue(calcObj);
818 127 : }
819 :
820 : /* static */ nsRuleNode::ComputedCalc
821 0 : nsRuleNode::SpecifiedCalcToComputedCalc(const nsCSSValue& aValue,
822 : nsStyleContext* aStyleContext,
823 : nsPresContext* aPresContext,
824 : RuleNodeCacheConditions& aConditions)
825 : {
826 : LengthPercentPairCalcOps ops(aStyleContext, aPresContext,
827 0 : aConditions);
828 0 : return ComputeCalc(aValue, ops);
829 : }
830 :
831 : // This is our public API for handling calc() expressions that involve
832 : // percentages.
833 : /* static */ nscoord
834 231 : nsRuleNode::ComputeComputedCalc(const nsStyleCoord& aValue,
835 : nscoord aPercentageBasis)
836 : {
837 231 : nsStyleCoord::Calc* calc = aValue.GetCalcValue();
838 231 : return calc->mLength +
839 231 : NSToCoordFloorClamped(aPercentageBasis * calc->mPercent);
840 : }
841 :
842 : /* static */ nscoord
843 8317 : nsRuleNode::ComputeCoordPercentCalc(const nsStyleCoord& aCoord,
844 : nscoord aPercentageBasis)
845 : {
846 8317 : switch (aCoord.GetUnit()) {
847 : case eStyleUnit_Coord:
848 8069 : return aCoord.GetCoordValue();
849 : case eStyleUnit_Percent:
850 20 : return NSToCoordFloorClamped(aPercentageBasis * aCoord.GetPercentValue());
851 : case eStyleUnit_Calc:
852 228 : return ComputeComputedCalc(aCoord, aPercentageBasis);
853 : default:
854 0 : MOZ_ASSERT(false, "unexpected unit");
855 : return 0;
856 : }
857 : }
858 :
859 : /* Given an enumerated value that represents a box position, converts it to
860 : * a float representing the percentage of the box it corresponds to. For
861 : * example, "center" becomes 0.5f.
862 : *
863 : * @param aEnumValue The enumerated value.
864 : * @return The float percent it corresponds to.
865 : */
866 : static float
867 18 : GetFloatFromBoxPosition(int32_t aEnumValue)
868 : {
869 18 : switch (aEnumValue) {
870 : case NS_STYLE_IMAGELAYER_POSITION_LEFT:
871 : case NS_STYLE_IMAGELAYER_POSITION_TOP:
872 3 : return 0.0f;
873 : case NS_STYLE_IMAGELAYER_POSITION_RIGHT:
874 : case NS_STYLE_IMAGELAYER_POSITION_BOTTOM:
875 2 : return 1.0f;
876 : default:
877 0 : MOZ_FALLTHROUGH_ASSERT("unexpected box position value");
878 : case NS_STYLE_IMAGELAYER_POSITION_CENTER:
879 13 : return 0.5f;
880 : }
881 : }
882 :
883 : #define SETCOORD_NORMAL 0x01 // N
884 : #define SETCOORD_AUTO 0x02 // A
885 : #define SETCOORD_INHERIT 0x04 // H
886 : #define SETCOORD_PERCENT 0x08 // P
887 : #define SETCOORD_FACTOR 0x10 // F
888 : #define SETCOORD_LENGTH 0x20 // L
889 : #define SETCOORD_INTEGER 0x40 // I
890 : #define SETCOORD_ENUMERATED 0x80 // E
891 : #define SETCOORD_NONE 0x100 // O
892 : #define SETCOORD_INITIAL_ZERO 0x200
893 : #define SETCOORD_INITIAL_AUTO 0x400
894 : #define SETCOORD_INITIAL_NONE 0x800
895 : #define SETCOORD_INITIAL_NORMAL 0x1000
896 : #define SETCOORD_INITIAL_HALF 0x2000
897 : #define SETCOORD_INITIAL_HUNDRED_PCT 0x00004000
898 : #define SETCOORD_INITIAL_FACTOR_ONE 0x00008000
899 : #define SETCOORD_INITIAL_FACTOR_ZERO 0x00010000
900 : #define SETCOORD_CALC_LENGTH_ONLY 0x00020000
901 : #define SETCOORD_CALC_CLAMP_NONNEGATIVE 0x00040000 // modifier for CALC_LENGTH_ONLY
902 : #define SETCOORD_STORE_CALC 0x00080000
903 : #define SETCOORD_BOX_POSITION 0x00100000 // exclusive with _ENUMERATED
904 : #define SETCOORD_ANGLE 0x00200000
905 : #define SETCOORD_UNSET_INHERIT 0x00400000
906 : #define SETCOORD_UNSET_INITIAL 0x00800000
907 :
908 : #define SETCOORD_LP (SETCOORD_LENGTH | SETCOORD_PERCENT)
909 : #define SETCOORD_LH (SETCOORD_LENGTH | SETCOORD_INHERIT)
910 : #define SETCOORD_AH (SETCOORD_AUTO | SETCOORD_INHERIT)
911 : #define SETCOORD_LAH (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT)
912 : #define SETCOORD_LPH (SETCOORD_LP | SETCOORD_INHERIT)
913 : #define SETCOORD_LPAH (SETCOORD_LP | SETCOORD_AH)
914 : #define SETCOORD_LPE (SETCOORD_LP | SETCOORD_ENUMERATED)
915 : #define SETCOORD_LPEH (SETCOORD_LPE | SETCOORD_INHERIT)
916 : #define SETCOORD_LPAEH (SETCOORD_LPAH | SETCOORD_ENUMERATED)
917 : #define SETCOORD_LPO (SETCOORD_LP | SETCOORD_NONE)
918 : #define SETCOORD_LPOH (SETCOORD_LPH | SETCOORD_NONE)
919 : #define SETCOORD_LPOEH (SETCOORD_LPOH | SETCOORD_ENUMERATED)
920 : #define SETCOORD_LE (SETCOORD_LENGTH | SETCOORD_ENUMERATED)
921 : #define SETCOORD_LEH (SETCOORD_LE | SETCOORD_INHERIT)
922 : #define SETCOORD_IA (SETCOORD_INTEGER | SETCOORD_AUTO)
923 : #define SETCOORD_LAE (SETCOORD_LENGTH | SETCOORD_AUTO | SETCOORD_ENUMERATED)
924 :
925 : // changes aCoord iff it returns true
926 10782 : static bool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
927 : const nsStyleCoord& aParentCoord,
928 : int32_t aMask, GeckoStyleContext* aStyleContext,
929 : nsPresContext* aPresContext,
930 : RuleNodeCacheConditions& aConditions)
931 : {
932 10782 : bool result = true;
933 10782 : if (aValue.GetUnit() == eCSSUnit_Null) {
934 7659 : result = false;
935 : }
936 9082 : else if ((((aMask & SETCOORD_LENGTH) != 0) &&
937 6246 : aValue.IsLengthUnit()) ||
938 1200 : (((aMask & SETCOORD_CALC_LENGTH_ONLY) != 0) &&
939 56 : aValue.IsCalcUnit())) {
940 : nscoord len = CalcLength(aValue, aStyleContext, aPresContext,
941 1979 : aConditions);
942 1979 : if ((aMask & SETCOORD_CALC_CLAMP_NONNEGATIVE) && len < 0) {
943 0 : NS_ASSERTION(aValue.IsCalcUnit(),
944 : "parser should have ensured no nonnegative lengths");
945 0 : len = 0;
946 : }
947 1979 : aCoord.SetCoordValue(len);
948 : }
949 1935 : else if (((aMask & SETCOORD_PERCENT) != 0) &&
950 791 : (aValue.GetUnit() == eCSSUnit_Percent)) {
951 251 : aCoord.SetPercentValue(aValue.GetPercentValue());
952 : }
953 913 : else if (((aMask & SETCOORD_INTEGER) != 0) &&
954 20 : (aValue.GetUnit() == eCSSUnit_Integer)) {
955 15 : aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Integer);
956 : }
957 937 : else if (((aMask & SETCOORD_ENUMERATED) != 0) &&
958 59 : (aValue.GetUnit() == eCSSUnit_Enumerated)) {
959 14 : aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Enumerated);
960 : }
961 894 : else if (((aMask & SETCOORD_BOX_POSITION) != 0) &&
962 30 : (aValue.GetUnit() == eCSSUnit_Enumerated)) {
963 2 : aCoord.SetPercentValue(GetFloatFromBoxPosition(aValue.GetIntValue()));
964 : }
965 1220 : else if (((aMask & SETCOORD_AUTO) != 0) &&
966 358 : (aValue.GetUnit() == eCSSUnit_Auto)) {
967 5 : aCoord.SetAutoValue();
968 : }
969 2498 : else if ((((aMask & SETCOORD_INHERIT) != 0) &&
970 1714 : aValue.GetUnit() == eCSSUnit_Inherit) ||
971 710 : (((aMask & SETCOORD_UNSET_INHERIT) != 0) &&
972 7 : aValue.GetUnit() == eCSSUnit_Unset)) {
973 154 : aCoord = aParentCoord; // just inherit value from parent
974 154 : aConditions.SetUncacheable();
975 : }
976 709 : else if (((aMask & SETCOORD_NORMAL) != 0) &&
977 6 : (aValue.GetUnit() == eCSSUnit_Normal)) {
978 6 : aCoord.SetNormalValue();
979 : }
980 778 : else if (((aMask & SETCOORD_NONE) != 0) &&
981 81 : (aValue.GetUnit() == eCSSUnit_None)) {
982 50 : aCoord.SetNoneValue();
983 : }
984 1152 : else if (((aMask & SETCOORD_FACTOR) != 0) &&
985 505 : (aValue.GetUnit() == eCSSUnit_Number)) {
986 505 : aCoord.SetFactorValue(aValue.GetFloatValue());
987 : }
988 269 : else if (((aMask & SETCOORD_STORE_CALC) != 0) &&
989 127 : (aValue.IsCalcUnit())) {
990 : SpecifiedCalcToComputedCalc(aValue, aCoord, aStyleContext,
991 127 : aConditions);
992 : }
993 30 : else if (aValue.GetUnit() == eCSSUnit_Initial ||
994 15 : (aValue.GetUnit() == eCSSUnit_Unset &&
995 0 : ((aMask & SETCOORD_UNSET_INITIAL) != 0))) {
996 0 : if ((aMask & SETCOORD_INITIAL_AUTO) != 0) {
997 0 : aCoord.SetAutoValue();
998 : }
999 0 : else if ((aMask & SETCOORD_INITIAL_ZERO) != 0) {
1000 0 : aCoord.SetCoordValue(0);
1001 : }
1002 0 : else if ((aMask & SETCOORD_INITIAL_FACTOR_ZERO) != 0) {
1003 0 : aCoord.SetFactorValue(0.0f);
1004 : }
1005 0 : else if ((aMask & SETCOORD_INITIAL_NONE) != 0) {
1006 0 : aCoord.SetNoneValue();
1007 : }
1008 0 : else if ((aMask & SETCOORD_INITIAL_NORMAL) != 0) {
1009 0 : aCoord.SetNormalValue();
1010 : }
1011 0 : else if ((aMask & SETCOORD_INITIAL_HALF) != 0) {
1012 0 : aCoord.SetPercentValue(0.5f);
1013 : }
1014 0 : else if ((aMask & SETCOORD_INITIAL_HUNDRED_PCT) != 0) {
1015 0 : aCoord.SetPercentValue(1.0f);
1016 : }
1017 0 : else if ((aMask & SETCOORD_INITIAL_FACTOR_ONE) != 0) {
1018 0 : aCoord.SetFactorValue(1.0f);
1019 : }
1020 : else {
1021 0 : result = false; // didn't set anything
1022 : }
1023 : }
1024 30 : else if ((aMask & SETCOORD_ANGLE) != 0 &&
1025 15 : (aValue.IsAngularUnit())) {
1026 : nsStyleUnit unit;
1027 0 : switch (aValue.GetUnit()) {
1028 0 : case eCSSUnit_Degree: unit = eStyleUnit_Degree; break;
1029 0 : case eCSSUnit_Grad: unit = eStyleUnit_Grad; break;
1030 0 : case eCSSUnit_Radian: unit = eStyleUnit_Radian; break;
1031 0 : case eCSSUnit_Turn: unit = eStyleUnit_Turn; break;
1032 0 : default: NS_NOTREACHED("unrecognized angular unit");
1033 0 : unit = eStyleUnit_Degree;
1034 : }
1035 0 : aCoord.SetAngleValue(aValue.GetAngleValue(), unit);
1036 : }
1037 : else {
1038 15 : result = false; // didn't set anything
1039 : }
1040 10782 : return result;
1041 : }
1042 :
1043 : // This inline function offers a shortcut for SetCoord() by refusing to accept
1044 : // SETCOORD_LENGTH, SETCOORD_INHERIT and SETCOORD_UNSET_* masks.
1045 8 : static inline bool SetAbsCoord(const nsCSSValue& aValue,
1046 : nsStyleCoord& aCoord,
1047 : int32_t aMask)
1048 : {
1049 8 : MOZ_ASSERT((aMask & (SETCOORD_LH | SETCOORD_UNSET_INHERIT |
1050 : SETCOORD_UNSET_INITIAL)) == 0,
1051 : "does not handle SETCOORD_LENGTH, SETCOORD_INHERIT and "
1052 : "SETCOORD_UNSET_*");
1053 :
1054 : // The values of the following variables will never be used; so it does not
1055 : // matter what to set.
1056 16 : const nsStyleCoord dummyParentCoord;
1057 8 : GeckoStyleContext* dummyStyleContext = nullptr;
1058 8 : nsPresContext* dummyPresContext = nullptr;
1059 8 : RuleNodeCacheConditions dummyCacheKey;
1060 :
1061 : bool rv = SetCoord(aValue, aCoord, dummyParentCoord, aMask,
1062 : dummyStyleContext, dummyPresContext,
1063 8 : dummyCacheKey);
1064 8 : MOZ_ASSERT(dummyCacheKey.CacheableWithoutDependencies(),
1065 : "SetCoord() should not modify dummyCacheKey.");
1066 :
1067 16 : return rv;
1068 : }
1069 :
1070 : /* Given a specified value that might be a pair value, call SetCoord twice,
1071 : * either using each member of the pair, or using the unpaired value twice.
1072 : */
1073 : static bool
1074 748 : SetPairCoords(const nsCSSValue& aValue,
1075 : nsStyleCoord& aCoordX, nsStyleCoord& aCoordY,
1076 : const nsStyleCoord& aParentX, const nsStyleCoord& aParentY,
1077 : int32_t aMask, GeckoStyleContext* aStyleContext,
1078 : nsPresContext* aPresContext, RuleNodeCacheConditions& aConditions)
1079 : {
1080 : const nsCSSValue& valX =
1081 748 : aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mXValue : aValue;
1082 : const nsCSSValue& valY =
1083 748 : aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mYValue : aValue;
1084 :
1085 : bool cX = SetCoord(valX, aCoordX, aParentX, aMask, aStyleContext,
1086 748 : aPresContext, aConditions);
1087 1496 : mozilla::DebugOnly<bool> cY = SetCoord(valY, aCoordY, aParentY, aMask,
1088 1496 : aStyleContext, aPresContext, aConditions);
1089 748 : MOZ_ASSERT(cX == cY, "changed one but not the other");
1090 1496 : return cX;
1091 : }
1092 :
1093 627 : static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
1094 : nsPresContext* aPresContext, nsStyleContext *aContext,
1095 : nscolor& aResult, RuleNodeCacheConditions& aConditions)
1096 : {
1097 627 : bool result = false;
1098 627 : nsCSSUnit unit = aValue.GetUnit();
1099 :
1100 627 : if (aValue.IsNumericColorUnit()) {
1101 258 : aResult = aValue.GetColorValue();
1102 258 : result = true;
1103 : }
1104 369 : else if (eCSSUnit_Ident == unit) {
1105 266 : nsAutoString value;
1106 133 : aValue.GetStringValue(value);
1107 : nscolor rgba;
1108 133 : if (NS_ColorNameToRGB(value, &rgba)) {
1109 133 : aResult = rgba;
1110 133 : result = true;
1111 : }
1112 : }
1113 236 : else if (eCSSUnit_EnumColor == unit) {
1114 81 : int32_t intValue = aValue.GetIntValue();
1115 81 : if (0 <= intValue) {
1116 78 : LookAndFeel::ColorID colorID = (LookAndFeel::ColorID) intValue;
1117 156 : bool useStandinsForNativeColors = aPresContext &&
1118 156 : !aPresContext->IsChrome();
1119 : DebugOnly<nsresult> rv =
1120 156 : LookAndFeel::GetColor(colorID, useStandinsForNativeColors, &aResult);
1121 78 : MOZ_ASSERT(NS_SUCCEEDED(rv),
1122 : "Unknown enum colors should have been rejected by parser");
1123 78 : result = true;
1124 : }
1125 : else {
1126 3 : aResult = NS_RGB(0, 0, 0);
1127 3 : result = false;
1128 3 : switch (intValue) {
1129 : case NS_COLOR_MOZ_HYPERLINKTEXT:
1130 0 : if (aPresContext) {
1131 0 : aResult = aPresContext->DefaultLinkColor();
1132 0 : result = true;
1133 : }
1134 0 : break;
1135 : case NS_COLOR_MOZ_VISITEDHYPERLINKTEXT:
1136 0 : if (aPresContext) {
1137 0 : aResult = aPresContext->DefaultVisitedLinkColor();
1138 0 : result = true;
1139 : }
1140 0 : break;
1141 : case NS_COLOR_MOZ_ACTIVEHYPERLINKTEXT:
1142 0 : if (aPresContext) {
1143 0 : aResult = aPresContext->DefaultActiveLinkColor();
1144 0 : result = true;
1145 : }
1146 0 : break;
1147 : case NS_COLOR_CURRENTCOLOR:
1148 : // The data computed from this can't be shared in the rule tree
1149 : // because they could be used on a node with a different color
1150 3 : aConditions.SetUncacheable();
1151 3 : if (aContext) {
1152 3 : aResult = aContext->StyleColor()->mColor;
1153 3 : result = true;
1154 : }
1155 3 : break;
1156 : case NS_COLOR_MOZ_DEFAULT_COLOR:
1157 0 : if (aPresContext) {
1158 0 : aResult = aPresContext->DefaultColor();
1159 0 : result = true;
1160 : }
1161 0 : break;
1162 : case NS_COLOR_MOZ_DEFAULT_BACKGROUND_COLOR:
1163 0 : if (aPresContext) {
1164 0 : aResult = aPresContext->DefaultBackgroundColor();
1165 0 : result = true;
1166 : }
1167 0 : break;
1168 : default:
1169 0 : NS_NOTREACHED("Should never have an unknown negative colorID.");
1170 0 : break;
1171 : }
1172 : }
1173 : }
1174 155 : else if (eCSSUnit_Inherit == unit) {
1175 0 : aResult = aParentColor;
1176 0 : result = true;
1177 0 : aConditions.SetUncacheable();
1178 : }
1179 155 : else if (eCSSUnit_Enumerated == unit &&
1180 0 : aValue.GetIntValue() == NS_STYLE_COLOR_INHERIT_FROM_BODY) {
1181 0 : NS_ASSERTION(aPresContext->CompatibilityMode() == eCompatibility_NavQuirks,
1182 : "Should only get this value in quirks mode");
1183 : // We just grab the color from the prescontext, and rely on the fact that
1184 : // if the body color ever changes all its descendants will get new style
1185 : // contexts (but NOT necessarily new rulenodes).
1186 0 : aResult = aPresContext->BodyTextColor();
1187 0 : result = true;
1188 0 : aConditions.SetUncacheable();
1189 : }
1190 627 : return result;
1191 : }
1192 :
1193 : template<UnsetAction UnsetTo>
1194 : static void
1195 2649 : SetComplexColor(const nsCSSValue& aValue,
1196 : const StyleComplexColor& aParentColor,
1197 : const StyleComplexColor& aInitialColor,
1198 : nsPresContext* aPresContext,
1199 : StyleComplexColor& aResult,
1200 : RuleNodeCacheConditions& aConditions)
1201 : {
1202 2649 : nsCSSUnit unit = aValue.GetUnit();
1203 2649 : if (unit == eCSSUnit_Null) {
1204 2199 : return;
1205 : }
1206 450 : if (unit == eCSSUnit_Initial ||
1207 : (UnsetTo == eUnsetInitial && unit == eCSSUnit_Unset)) {
1208 0 : aResult = aInitialColor;
1209 450 : } else if (unit == eCSSUnit_Inherit ||
1210 : (UnsetTo == eUnsetInherit && unit == eCSSUnit_Unset)) {
1211 143 : aConditions.SetUncacheable();
1212 143 : aResult = aParentColor;
1213 459 : } else if (unit == eCSSUnit_EnumColor &&
1214 152 : aValue.GetIntValue() == NS_COLOR_CURRENTCOLOR) {
1215 88 : aResult = StyleComplexColor::CurrentColor();
1216 219 : } else if (unit == eCSSUnit_ComplexColor) {
1217 0 : aResult = aValue.GetStyleComplexColorValue();
1218 219 : } else if (unit == eCSSUnit_Auto) {
1219 0 : aResult = StyleComplexColor::Auto();
1220 : } else {
1221 : nscolor resultColor;
1222 219 : if (!SetColor(aValue, aParentColor.mColor, aPresContext,
1223 : nullptr, resultColor, aConditions)) {
1224 0 : MOZ_ASSERT_UNREACHABLE("Unknown color value");
1225 : return;
1226 : }
1227 219 : aResult = StyleComplexColor::FromColor(resultColor);
1228 : }
1229 : }
1230 :
1231 : template<UnsetAction UnsetTo>
1232 : static Maybe<nscoord>
1233 748 : ComputeLineWidthValue(const nsCSSValue& aValue,
1234 : const nscoord aParentCoord,
1235 : const nscoord aInitialCoord,
1236 : GeckoStyleContext* aStyleContext,
1237 : nsPresContext* aPresContext,
1238 : RuleNodeCacheConditions& aConditions)
1239 : {
1240 748 : nsCSSUnit unit = aValue.GetUnit();
1241 748 : if (unit == eCSSUnit_Initial ||
1242 : (UnsetTo == eUnsetInitial && unit == eCSSUnit_Unset)) {
1243 0 : return Some(aInitialCoord);
1244 748 : } else if (unit == eCSSUnit_Inherit ||
1245 : (UnsetTo == eUnsetInherit && unit == eCSSUnit_Unset)) {
1246 25 : aConditions.SetUncacheable();
1247 25 : return Some(aParentCoord);
1248 723 : } else if (unit == eCSSUnit_Enumerated) {
1249 58 : NS_ASSERTION(aValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
1250 : aValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
1251 : aValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
1252 : "Unexpected line-width keyword!");
1253 58 : return Some(nsPresContext::GetBorderWidthForKeyword(aValue.GetIntValue()));
1254 1106 : } else if (aValue.IsLengthUnit() ||
1255 441 : aValue.IsCalcUnit()) {
1256 : nscoord len =
1257 224 : CalcLength(aValue, aStyleContext, aPresContext, aConditions);
1258 224 : if (len < 0) {
1259 0 : NS_ASSERTION(aValue.IsCalcUnit(),
1260 : "Parser should have rejected negative length!");
1261 0 : len = 0;
1262 : }
1263 224 : return Some(len);
1264 : } else {
1265 441 : NS_ASSERTION(unit == eCSSUnit_Null,
1266 : "Missing case handling for line-width computing!");
1267 441 : return Maybe<nscoord>(Nothing());
1268 : }
1269 : }
1270 :
1271 30 : static void SetGradientCoord(const nsCSSValue& aValue, nsPresContext* aPresContext,
1272 : GeckoStyleContext* aContext, nsStyleCoord& aResult,
1273 : RuleNodeCacheConditions& aConditions)
1274 : {
1275 : // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
1276 30 : if (!SetCoord(aValue, aResult, nsStyleCoord(),
1277 : SETCOORD_LPO | SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC,
1278 : aContext, aPresContext, aConditions)) {
1279 0 : NS_NOTREACHED("unexpected unit for gradient anchor point");
1280 0 : aResult.SetNoneValue();
1281 : }
1282 30 : }
1283 :
1284 15 : static void SetGradient(const nsCSSValue& aValue, nsPresContext* aPresContext,
1285 : GeckoStyleContext* aContext, nsStyleGradient& aResult,
1286 : RuleNodeCacheConditions& aConditions)
1287 : {
1288 15 : MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Gradient,
1289 : "The given data is not a gradient");
1290 :
1291 15 : const nsCSSValueGradient* gradient = aValue.GetGradientValue();
1292 :
1293 15 : if (gradient->mIsExplicitSize) {
1294 0 : SetCoord(gradient->GetRadiusX(), aResult.mRadiusX, nsStyleCoord(),
1295 : SETCOORD_LP | SETCOORD_STORE_CALC,
1296 0 : aContext, aPresContext, aConditions);
1297 0 : if (gradient->GetRadiusY().GetUnit() != eCSSUnit_None) {
1298 0 : SetCoord(gradient->GetRadiusY(), aResult.mRadiusY, nsStyleCoord(),
1299 : SETCOORD_LP | SETCOORD_STORE_CALC,
1300 0 : aContext, aPresContext, aConditions);
1301 0 : aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
1302 : } else {
1303 0 : aResult.mRadiusY = aResult.mRadiusX;
1304 0 : aResult.mShape = NS_STYLE_GRADIENT_SHAPE_CIRCULAR;
1305 : }
1306 0 : aResult.mSize = NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE;
1307 15 : } else if (gradient->mIsRadial) {
1308 0 : if (gradient->GetRadialShape().GetUnit() == eCSSUnit_Enumerated) {
1309 0 : aResult.mShape = gradient->GetRadialShape().GetIntValue();
1310 : } else {
1311 0 : NS_ASSERTION(gradient->GetRadialShape().GetUnit() == eCSSUnit_None,
1312 : "bad unit for radial shape");
1313 0 : aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
1314 : }
1315 0 : if (gradient->GetRadialSize().GetUnit() == eCSSUnit_Enumerated) {
1316 0 : aResult.mSize = gradient->GetRadialSize().GetIntValue();
1317 : } else {
1318 0 : NS_ASSERTION(gradient->GetRadialSize().GetUnit() == eCSSUnit_None,
1319 : "bad unit for radial shape");
1320 0 : aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
1321 : }
1322 : } else {
1323 15 : NS_ASSERTION(gradient->GetRadialShape().GetUnit() == eCSSUnit_None,
1324 : "bad unit for linear shape");
1325 15 : NS_ASSERTION(gradient->GetRadialSize().GetUnit() == eCSSUnit_None,
1326 : "bad unit for linear size");
1327 15 : aResult.mShape = NS_STYLE_GRADIENT_SHAPE_LINEAR;
1328 15 : aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
1329 : }
1330 :
1331 15 : aResult.mLegacySyntax = gradient->mIsLegacySyntax;
1332 15 : aResult.mMozLegacySyntax = gradient->mIsMozLegacySyntax;
1333 :
1334 : // bg-position
1335 15 : SetGradientCoord(gradient->mBgPos.mXValue, aPresContext, aContext,
1336 15 : aResult.mBgPosX, aConditions);
1337 :
1338 15 : SetGradientCoord(gradient->mBgPos.mYValue, aPresContext, aContext,
1339 15 : aResult.mBgPosY, aConditions);
1340 :
1341 15 : aResult.mRepeating = gradient->mIsRepeating;
1342 :
1343 : // angle
1344 30 : const nsStyleCoord dummyParentCoord;
1345 15 : if (!SetCoord(gradient->mAngle, aResult.mAngle, dummyParentCoord, SETCOORD_ANGLE,
1346 : aContext, aPresContext, aConditions)) {
1347 15 : NS_ASSERTION(gradient->mAngle.GetUnit() == eCSSUnit_None,
1348 : "bad unit for gradient angle");
1349 15 : aResult.mAngle.SetNoneValue();
1350 : }
1351 :
1352 : // stops
1353 56 : for (uint32_t i = 0; i < gradient->mStops.Length(); i++) {
1354 82 : nsStyleGradientStop stop;
1355 41 : const nsCSSValueGradientStop &valueStop = gradient->mStops[i];
1356 :
1357 82 : if (!SetCoord(valueStop.mLocation, stop.mLocation,
1358 82 : nsStyleCoord(), SETCOORD_LPO | SETCOORD_STORE_CALC,
1359 : aContext, aPresContext, aConditions)) {
1360 0 : NS_NOTREACHED("unexpected unit for gradient stop location");
1361 : }
1362 :
1363 41 : stop.mIsInterpolationHint = valueStop.mIsInterpolationHint;
1364 :
1365 : // inherit is not a valid color for stops, so we pass in a dummy
1366 : // parent color
1367 41 : NS_ASSERTION(valueStop.mColor.GetUnit() != eCSSUnit_Inherit,
1368 : "inherit is not a valid color for gradient stops");
1369 41 : if (!valueStop.mIsInterpolationHint) {
1370 41 : SetColor(valueStop.mColor, NS_RGB(0, 0, 0), aPresContext,
1371 41 : aContext, stop.mColor, aConditions);
1372 : } else {
1373 : // Always initialize to the same color so we don't need to worry
1374 : // about comparisons.
1375 0 : stop.mColor = NS_RGB(0, 0, 0);
1376 : }
1377 :
1378 41 : aResult.mStops.AppendElement(stop);
1379 : }
1380 15 : }
1381 :
1382 : // -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
1383 2 : static void SetStyleImageToImageRect(GeckoStyleContext* aStyleContext,
1384 : const nsCSSValue& aValue,
1385 : nsStyleImage& aResult)
1386 : {
1387 2 : MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Function &&
1388 : aValue.EqualsFunction(eCSSKeyword__moz_image_rect),
1389 : "the value is not valid -moz-image-rect()");
1390 :
1391 2 : nsCSSValue::Array* arr = aValue.GetArrayValue();
1392 2 : MOZ_ASSERT(arr && arr->Count() == 6, "invalid number of arguments");
1393 :
1394 : // <uri>
1395 2 : if (arr->Item(1).GetUnit() == eCSSUnit_Image) {
1396 2 : nsPresContext* pc = aStyleContext->PresContext();
1397 2 : aResult.SetImageRequest(CreateStyleImageRequest(pc, arr->Item(1)));
1398 : } else {
1399 0 : NS_WARNING("nsCSSValue::Image::Image() failed?");
1400 : }
1401 :
1402 : // <top>, <right>, <bottom>, <left>
1403 4 : nsStyleSides cropRect;
1404 10 : NS_FOR_CSS_SIDES(side) {
1405 16 : nsStyleCoord coord;
1406 8 : const nsCSSValue& val = arr->Item(2 + side);
1407 :
1408 : #ifdef DEBUG
1409 : bool unitOk =
1410 : #endif
1411 8 : SetAbsCoord(val, coord, SETCOORD_FACTOR | SETCOORD_PERCENT);
1412 8 : MOZ_ASSERT(unitOk, "Incorrect data structure created by CSS parser");
1413 8 : cropRect.Set(side, coord);
1414 : }
1415 2 : aResult.SetCropRect(MakeUnique<nsStyleSides>(cropRect));
1416 2 : }
1417 :
1418 208 : static void SetStyleImage(GeckoStyleContext* aStyleContext,
1419 : const nsCSSValue& aValue,
1420 : nsStyleImage& aResult,
1421 : RuleNodeCacheConditions& aConditions)
1422 : {
1423 208 : if (aValue.GetUnit() == eCSSUnit_Null) {
1424 100 : return;
1425 : }
1426 :
1427 108 : aResult.SetNull();
1428 :
1429 108 : nsPresContext* presContext = aStyleContext->PresContext();
1430 108 : switch (aValue.GetUnit()) {
1431 : case eCSSUnit_Image:
1432 22 : aResult.SetImageRequest(CreateStyleImageRequest(presContext, aValue));
1433 22 : break;
1434 : case eCSSUnit_Function:
1435 2 : if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
1436 2 : SetStyleImageToImageRect(aStyleContext, aValue, aResult);
1437 : } else {
1438 0 : NS_NOTREACHED("-moz-image-rect() is the only expected function");
1439 : }
1440 2 : break;
1441 : case eCSSUnit_Gradient:
1442 : {
1443 15 : nsStyleGradient* gradient = new nsStyleGradient();
1444 15 : SetGradient(aValue, presContext, aStyleContext, *gradient, aConditions);
1445 15 : aResult.SetGradientData(gradient);
1446 15 : break;
1447 : }
1448 : case eCSSUnit_Element:
1449 : {
1450 0 : nsCOMPtr<nsIAtom> atom = NS_Atomize(aValue.GetStringBufferValue());
1451 0 : aResult.SetElementId(atom.forget());
1452 0 : break;
1453 : }
1454 : case eCSSUnit_Initial:
1455 : case eCSSUnit_Unset:
1456 : case eCSSUnit_None:
1457 68 : break;
1458 : case eCSSUnit_URL:
1459 : {
1460 : #ifdef DEBUG
1461 : // eCSSUnit_URL is expected only if
1462 : // 1. we have eCSSUnit_URL values for if-visited style contexts, which
1463 : // we can safely treat like 'none'.
1464 : // 2. aValue is a local-ref URL, e.g. url(#foo).
1465 : // 3. aValue is a not a local-ref URL, but it refers to an element in
1466 : // the current document. For example, the url of the current document
1467 : // is "http://foo.html" and aValue is url(http://foo.html#foo).
1468 : //
1469 : // We skip image download in TryToStartImageLoadOnValue under #2 and #3,
1470 : // and that's part of reasons we get eCSSUnit_URL instead of
1471 : // eCSSUnit_Image here.
1472 :
1473 : // Check #2.
1474 1 : bool isLocalRef = aValue.GetURLStructValue()->IsLocalRef();
1475 :
1476 : // Check #3.
1477 1 : bool isEqualExceptRef = false;
1478 1 : if (!isLocalRef) {
1479 0 : nsIDocument* currentDoc = presContext->Document();
1480 0 : nsIURI* docURI = currentDoc->GetDocumentURI();
1481 0 : nsIURI* imageURI = aValue.GetURLValue();
1482 0 : imageURI->EqualsExceptRef(docURI, &isEqualExceptRef);
1483 : }
1484 :
1485 1 : MOZ_ASSERT(aStyleContext->IsStyleIfVisited() || isEqualExceptRef ||
1486 : isLocalRef,
1487 : "unexpected unit; maybe nsCSSValue::Image::Image() failed?");
1488 : #endif
1489 1 : aResult.SetURLValue(do_AddRef(aValue.GetURLStructValue()));
1490 1 : break;
1491 : }
1492 : default:
1493 0 : MOZ_ASSERT_UNREACHABLE("Unexpected Unit type.");
1494 : break;
1495 : }
1496 : }
1497 :
1498 : struct SetEnumValueHelper
1499 : {
1500 : template<typename FieldT>
1501 0 : static void SetIntegerValue(FieldT&, const nsCSSValue&)
1502 : {
1503 : // FIXME Is it possible to turn this assertion into a compilation error?
1504 0 : MOZ_ASSERT_UNREACHABLE("inappropriate unit");
1505 : }
1506 :
1507 : #define DEFINE_ENUM_CLASS_SETTER(type_, min_, max_) \
1508 : static void SetEnumeratedValue(type_& aField, const nsCSSValue& aValue) \
1509 : { \
1510 : auto value = aValue.GetIntValue(); \
1511 : MOZ_ASSERT(value >= static_cast<decltype(value)>(type_::min_) && \
1512 : value <= static_cast<decltype(value)>(type_::max_), \
1513 : "inappropriate value"); \
1514 : aField = static_cast<type_>(value); \
1515 : }
1516 :
1517 32 : DEFINE_ENUM_CLASS_SETTER(StyleBoxAlign, Stretch, End)
1518 0 : DEFINE_ENUM_CLASS_SETTER(StyleBoxDecorationBreak, Slice, Clone)
1519 0 : DEFINE_ENUM_CLASS_SETTER(StyleBoxDirection, Normal, Reverse)
1520 20 : DEFINE_ENUM_CLASS_SETTER(StyleBoxOrient, Horizontal, Vertical)
1521 37 : DEFINE_ENUM_CLASS_SETTER(StyleBoxPack, Start, Justify)
1522 12 : DEFINE_ENUM_CLASS_SETTER(StyleBoxSizing, Content, Border)
1523 0 : DEFINE_ENUM_CLASS_SETTER(StyleClear, None, Both)
1524 1 : DEFINE_ENUM_CLASS_SETTER(StyleFillRule, Nonzero, Evenodd)
1525 76 : DEFINE_ENUM_CLASS_SETTER(StyleFloat, None, InlineEnd)
1526 0 : DEFINE_ENUM_CLASS_SETTER(StyleFloatEdge, ContentBox, MarginBox)
1527 0 : DEFINE_ENUM_CLASS_SETTER(StyleHyphens, None, Auto)
1528 0 : DEFINE_ENUM_CLASS_SETTER(StyleStackSizing, Ignore, IgnoreVertical)
1529 0 : DEFINE_ENUM_CLASS_SETTER(StyleTextJustify, None, InterCharacter)
1530 1470 : DEFINE_ENUM_CLASS_SETTER(StyleUserFocus, None, SelectMenu)
1531 4 : DEFINE_ENUM_CLASS_SETTER(StyleUserSelect, None, MozText)
1532 0 : DEFINE_ENUM_CLASS_SETTER(StyleUserInput, None, Auto)
1533 6 : DEFINE_ENUM_CLASS_SETTER(StyleUserModify, ReadOnly, WriteOnly)
1534 2 : DEFINE_ENUM_CLASS_SETTER(StyleWindowDragging, Default, NoDrag)
1535 0 : DEFINE_ENUM_CLASS_SETTER(StyleOrient, Inline, Vertical)
1536 0 : DEFINE_ENUM_CLASS_SETTER(StyleGeometryBox, BorderBox, ViewBox)
1537 19 : DEFINE_ENUM_CLASS_SETTER(StyleWhiteSpace, Normal, PreSpace)
1538 : #ifdef MOZ_XUL
1539 357 : DEFINE_ENUM_CLASS_SETTER(StyleDisplay, None, MozPopup)
1540 : #else
1541 : DEFINE_ENUM_CLASS_SETTER(StyleDisplay, None, InlineBox)
1542 : #endif
1543 :
1544 : #undef DEF_SET_ENUMERATED_VALUE
1545 : };
1546 :
1547 : template<typename FieldT>
1548 : struct SetIntegerValueHelper
1549 : {
1550 4 : static void SetIntegerValue(FieldT& aField, const nsCSSValue& aValue)
1551 : {
1552 4 : aField = aValue.GetIntValue();
1553 4 : }
1554 844 : static void SetEnumeratedValue(FieldT& aField, const nsCSSValue& aValue)
1555 : {
1556 844 : aField = aValue.GetIntValue();
1557 844 : }
1558 : };
1559 :
1560 : template<typename FieldT>
1561 : struct SetValueHelper : Conditional<IsEnum<FieldT>::value,
1562 : SetEnumValueHelper,
1563 : SetIntegerValueHelper<FieldT>>::Type
1564 : {
1565 : template<typename ValueT>
1566 115 : static void SetValue(FieldT& aField, const ValueT& aValue)
1567 : {
1568 115 : aField = aValue;
1569 115 : }
1570 0 : static void SetValue(FieldT&, unused_t)
1571 : {
1572 : // FIXME Is it possible to turn this assertion into a compilation error?
1573 0 : MOZ_ASSERT_UNREACHABLE("inappropriate unit");
1574 : }
1575 : };
1576 :
1577 :
1578 : // flags for SetValue - align values with SETCOORD_* constants
1579 : // where possible
1580 :
1581 : #define SETVAL_INTEGER 0x40 // I
1582 : #define SETVAL_ENUMERATED 0x80 // E
1583 : #define SETVAL_UNSET_INHERIT 0x00400000
1584 : #define SETVAL_UNSET_INITIAL 0x00800000
1585 :
1586 : // no caller cares whether aField was changed or not
1587 : template<typename FieldT, typename InitialT,
1588 : typename AutoT, typename NoneT, typename NormalT, typename SysFontT>
1589 : static void
1590 27615 : SetValue(const nsCSSValue& aValue, FieldT& aField,
1591 : RuleNodeCacheConditions& aConditions, uint32_t aMask,
1592 : FieldT aParentValue,
1593 : InitialT aInitialValue,
1594 : AutoT aAutoValue,
1595 : NoneT aNoneValue,
1596 : NormalT aNormalValue,
1597 : SysFontT aSystemFontValue)
1598 : {
1599 : typedef SetValueHelper<FieldT> Helper;
1600 :
1601 27615 : switch (aValue.GetUnit()) {
1602 : case eCSSUnit_Null:
1603 23980 : return;
1604 :
1605 : // every caller of SetValue provides inherit and initial
1606 : // alternatives, so we don't require them to say so in the mask
1607 : case eCSSUnit_Inherit:
1608 636 : aConditions.SetUncacheable();
1609 636 : aField = aParentValue;
1610 636 : return;
1611 :
1612 : case eCSSUnit_Initial:
1613 61 : Helper::SetValue(aField, aInitialValue);
1614 61 : return;
1615 :
1616 : // every caller provides one or other of these alternatives,
1617 : // but they have to say which
1618 : case eCSSUnit_Enumerated:
1619 2880 : if (aMask & SETVAL_ENUMERATED) {
1620 2880 : Helper::SetEnumeratedValue(aField, aValue);
1621 2880 : return;
1622 : }
1623 0 : break;
1624 :
1625 : case eCSSUnit_Integer:
1626 4 : if (aMask & SETVAL_INTEGER) {
1627 4 : Helper::SetIntegerValue(aField, aValue);
1628 4 : return;
1629 : }
1630 0 : break;
1631 :
1632 : // remaining possibilities in descending order of frequency of use
1633 : case eCSSUnit_Auto:
1634 0 : Helper::SetValue(aField, aAutoValue);
1635 0 : return;
1636 :
1637 : case eCSSUnit_None:
1638 0 : Helper::SetValue(aField, aNoneValue);
1639 0 : return;
1640 :
1641 : case eCSSUnit_Normal:
1642 0 : Helper::SetValue(aField, aNormalValue);
1643 0 : return;
1644 :
1645 : case eCSSUnit_System_Font:
1646 54 : Helper::SetValue(aField, aSystemFontValue);
1647 54 : return;
1648 :
1649 : case eCSSUnit_Unset:
1650 0 : if (aMask & SETVAL_UNSET_INHERIT) {
1651 0 : aConditions.SetUncacheable();
1652 0 : aField = aParentValue;
1653 0 : return;
1654 : }
1655 0 : if (aMask & SETVAL_UNSET_INITIAL) {
1656 0 : Helper::SetValue(aField, aInitialValue);
1657 0 : return;
1658 : }
1659 0 : break;
1660 :
1661 : default:
1662 0 : break;
1663 : }
1664 :
1665 0 : NS_NOTREACHED("SetValue: inappropriate unit");
1666 : }
1667 :
1668 : template <typename FieldT, typename T1>
1669 : static void
1670 26153 : SetValue(const nsCSSValue& aValue, FieldT& aField,
1671 : RuleNodeCacheConditions& aConditions, uint32_t aMask,
1672 : FieldT aParentValue, T1 aInitialValue)
1673 : {
1674 26153 : SetValue(aValue, aField, aConditions, aMask, aParentValue,
1675 : aInitialValue, Unused, Unused, Unused, Unused);
1676 26153 : }
1677 :
1678 : // flags for SetFactor
1679 : #define SETFCT_POSITIVE 0x01 // assert value is >= 0.0f
1680 : #define SETFCT_OPACITY 0x02 // clamp value to [0.0f .. 1.0f]
1681 : #define SETFCT_NONE 0x04 // allow _None (uses aInitialValue).
1682 : #define SETFCT_UNSET_INHERIT 0x00400000
1683 : #define SETFCT_UNSET_INITIAL 0x00800000
1684 :
1685 : static void
1686 968 : SetFactor(const nsCSSValue& aValue, float& aField, RuleNodeCacheConditions& aConditions,
1687 : float aParentValue, float aInitialValue, uint32_t aFlags = 0)
1688 : {
1689 968 : switch (aValue.GetUnit()) {
1690 : case eCSSUnit_Null:
1691 877 : return;
1692 :
1693 : case eCSSUnit_Number:
1694 85 : aField = aValue.GetFloatValue();
1695 85 : if (aFlags & SETFCT_POSITIVE) {
1696 0 : NS_ASSERTION(aField >= 0.0f, "negative value for positive-only property");
1697 0 : if (aField < 0.0f)
1698 0 : aField = 0.0f;
1699 : }
1700 85 : if (aFlags & SETFCT_OPACITY) {
1701 63 : if (aField < 0.0f)
1702 0 : aField = 0.0f;
1703 63 : if (aField > 1.0f)
1704 0 : aField = 1.0f;
1705 : }
1706 85 : return;
1707 :
1708 : case eCSSUnit_Inherit:
1709 6 : aConditions.SetUncacheable();
1710 6 : aField = aParentValue;
1711 6 : return;
1712 :
1713 : case eCSSUnit_Initial:
1714 0 : aField = aInitialValue;
1715 0 : return;
1716 :
1717 : case eCSSUnit_None:
1718 0 : if (aFlags & SETFCT_NONE) {
1719 0 : aField = aInitialValue;
1720 0 : return;
1721 : }
1722 0 : break;
1723 :
1724 : case eCSSUnit_Unset:
1725 0 : if (aFlags & SETFCT_UNSET_INHERIT) {
1726 0 : aConditions.SetUncacheable();
1727 0 : aField = aParentValue;
1728 0 : return;
1729 : }
1730 0 : if (aFlags & SETFCT_UNSET_INITIAL) {
1731 0 : aField = aInitialValue;
1732 0 : return;
1733 : }
1734 0 : break;
1735 :
1736 : default:
1737 0 : break;
1738 : }
1739 :
1740 0 : NS_NOTREACHED("SetFactor: inappropriate unit");
1741 : }
1742 :
1743 : static void
1744 680 : SetTransformValue(const nsCSSValue& aValue,
1745 : RefPtr<nsCSSValueSharedList>& aField,
1746 : RuleNodeCacheConditions& aConditions,
1747 : nsCSSValueSharedList* const aParentValue)
1748 : {
1749 : /* Convert the nsCSSValueList into an nsTArray<nsTransformFunction *>. */
1750 680 : switch (aValue.GetUnit()) {
1751 : case eCSSUnit_Null:
1752 664 : break;
1753 :
1754 : case eCSSUnit_Initial:
1755 : case eCSSUnit_Unset:
1756 : case eCSSUnit_None:
1757 0 : aField = nullptr;
1758 0 : break;
1759 :
1760 : case eCSSUnit_Inherit:
1761 0 : aField = aParentValue;
1762 0 : aConditions.SetUncacheable();
1763 0 : break;
1764 :
1765 : case eCSSUnit_SharedList: {
1766 16 : nsCSSValueSharedList* list = aValue.GetSharedListValue();
1767 16 : nsCSSValueList* head = list->mHead;
1768 16 : MOZ_ASSERT(head, "transform list must have at least one item");
1769 : // can get a _None in here from transform animation
1770 16 : if (head->mValue.GetUnit() == eCSSUnit_None) {
1771 0 : MOZ_ASSERT(head->mNext == nullptr, "none must be alone");
1772 0 : aField = nullptr;
1773 : } else {
1774 16 : aField = list;
1775 : }
1776 16 : break;
1777 : }
1778 :
1779 : default:
1780 0 : MOZ_ASSERT(false, "unrecognized transform unit");
1781 : }
1782 680 : }
1783 :
1784 : void*
1785 2022 : nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext)
1786 : {
1787 : // Check the recycle list first.
1788 2022 : return aPresContext->PresShell()->AllocateByObjectID(eArenaObjectID_nsRuleNode, sz);
1789 : }
1790 :
1791 : // Overridden to prevent the global delete from being called, since the memory
1792 : // came out of an nsIArena instead of the global delete operator's heap.
1793 : void
1794 946 : nsRuleNode::Destroy()
1795 : {
1796 : // Destroy ourselves.
1797 946 : this->~nsRuleNode();
1798 :
1799 : // Don't let the memory be freed, since it will be recycled
1800 : // instead. Don't call the global operator delete.
1801 946 : mPresContext->PresShell()->FreeByObjectID(eArenaObjectID_nsRuleNode, this);
1802 946 : }
1803 :
1804 : already_AddRefed<nsRuleNode>
1805 30 : nsRuleNode::CreateRootNode(nsPresContext* aPresContext)
1806 : {
1807 : return do_AddRef(new (aPresContext)
1808 30 : nsRuleNode(aPresContext, nullptr, nullptr, SheetType::Unknown, false));
1809 : }
1810 :
1811 2022 : nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
1812 : nsIStyleRule* aRule, SheetType aLevel,
1813 2022 : bool aIsImportant)
1814 : : mPresContext(aContext),
1815 : mParent(aParent),
1816 : mRule(aRule),
1817 : mNextSibling(nullptr),
1818 4044 : mDependentBits((uint32_t(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
1819 2022 : (aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
1820 2022 : mNoneBits(aParent ? aParent->mNoneBits & NS_RULE_NODE_HAS_ANIMATION_DATA :
1821 : 0),
1822 6066 : mRefCnt(0)
1823 : {
1824 2022 : MOZ_ASSERT(aContext);
1825 2022 : MOZ_ASSERT(IsRoot() == !aRule,
1826 : "non-root rule nodes must have a rule");
1827 :
1828 2022 : mChildren.asVoid = nullptr;
1829 2022 : MOZ_COUNT_CTOR(nsRuleNode);
1830 :
1831 2022 : NS_ASSERTION(IsRoot() || GetLevel() == aLevel, "not enough bits");
1832 2022 : NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes");
1833 2022 : MOZ_ASSERT(aContext->StyleSet()->IsGecko(),
1834 : "ServoStyleSets should not have rule nodes");
1835 2022 : aContext->StyleSet()->AsGecko()->RuleNodeUnused(this, /* aMayGC = */ false);
1836 :
1837 : // nsStyleSet::GetContext depends on there being only one animation
1838 : // rule.
1839 2022 : MOZ_ASSERT(IsRoot() || GetLevel() != SheetType::Animation ||
1840 : mParent->IsRoot() ||
1841 : mParent->GetLevel() != SheetType::Animation,
1842 : "must be only one rule at animation level");
1843 2022 : }
1844 :
1845 1892 : nsRuleNode::~nsRuleNode()
1846 : {
1847 946 : MOZ_ASSERT(!HaveChildren());
1848 946 : MOZ_COUNT_DTOR(nsRuleNode);
1849 946 : if (mParent) {
1850 940 : mParent->RemoveChild(this);
1851 : }
1852 :
1853 946 : if (mStyleData.mResetData || mStyleData.mInheritedData)
1854 516 : mStyleData.Destroy(mDependentBits, mPresContext);
1855 946 : }
1856 :
1857 : nsRuleNode*
1858 11651 : nsRuleNode::Transition(nsIStyleRule* aRule, SheetType aLevel,
1859 : bool aIsImportantRule)
1860 : {
1861 : #ifdef DEBUG
1862 : {
1863 23302 : RefPtr<css::Declaration> declaration(do_QueryObject(aRule));
1864 11651 : MOZ_ASSERT(!declaration || !declaration->IsMutable(),
1865 : "caller must call Declaration::SetImmutable first");
1866 : }
1867 : #endif
1868 :
1869 11651 : nsRuleNode* next = nullptr;
1870 11651 : nsRuleNode::Key key(aRule, aLevel, aIsImportantRule);
1871 :
1872 11651 : if (HaveChildren() && !ChildrenAreHashed()) {
1873 8754 : int32_t numKids = 0;
1874 8754 : nsRuleNode* curr = ChildrenList();
1875 69036 : while (curr && curr->GetKey() != key) {
1876 30141 : curr = curr->mNextSibling;
1877 30141 : ++numKids;
1878 : }
1879 8754 : if (curr)
1880 8118 : next = curr;
1881 636 : else if (numKids >= kMaxChildrenInList)
1882 2 : ConvertChildrenToHash(numKids);
1883 : }
1884 :
1885 11651 : if (ChildrenAreHashed()) {
1886 : auto entry =
1887 1605 : static_cast<ChildrenHashEntry*>(ChildrenHash()->Add(&key, fallible));
1888 1605 : if (!entry) {
1889 0 : NS_WARNING("out of memory");
1890 0 : return this;
1891 : }
1892 1605 : if (entry->mRuleNode)
1893 1541 : next = entry->mRuleNode;
1894 : else {
1895 128 : next = entry->mRuleNode = new (mPresContext)
1896 64 : nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
1897 : }
1898 10046 : } else if (!next) {
1899 : // Create the new entry in our list.
1900 3856 : next = new (mPresContext)
1901 1928 : nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
1902 1928 : next->mNextSibling = ChildrenList();
1903 1928 : SetChildrenList(next);
1904 : }
1905 :
1906 11651 : return next;
1907 : }
1908 :
1909 : nsRuleNode*
1910 1618 : nsRuleNode::RuleTree()
1911 : {
1912 1618 : nsRuleNode* n = this;
1913 15132 : while (n->mParent) {
1914 6757 : n = n->mParent;
1915 : }
1916 1618 : return n;
1917 : }
1918 :
1919 2203 : void nsRuleNode::SetUsedDirectly()
1920 : {
1921 2203 : mDependentBits |= NS_RULE_NODE_USED_DIRECTLY;
1922 :
1923 : // Maintain the invariant that any rule node that is used directly has
1924 : // all structs that live in the rule tree cached (which
1925 : // nsRuleNode::GetStyleData depends on for speed).
1926 2203 : if (mDependentBits & NS_STYLE_INHERIT_MASK) {
1927 29700 : for (nsStyleStructID sid = nsStyleStructID(0); sid < nsStyleStructID_Length;
1928 28512 : sid = nsStyleStructID(sid + 1)) {
1929 28512 : uint32_t bit = nsCachedStyleData::GetBitForSID(sid);
1930 28512 : if (mDependentBits & bit) {
1931 6083 : nsRuleNode *source = mParent;
1932 24701 : while ((source->mDependentBits & bit) && !source->IsUsedDirectly()) {
1933 9309 : source = source->mParent;
1934 : }
1935 6083 : void *data = source->mStyleData.GetStyleData(sid);
1936 6083 : NS_ASSERTION(data, "unexpected null struct");
1937 6083 : mStyleData.SetStyleData(sid, mPresContext, data);
1938 : }
1939 : }
1940 : }
1941 2203 : }
1942 :
1943 : void
1944 2 : nsRuleNode::ConvertChildrenToHash(int32_t aNumKids)
1945 : {
1946 2 : NS_ASSERTION(!ChildrenAreHashed() && HaveChildren(),
1947 : "must have a non-empty list of children");
1948 : PLDHashTable *hash = new PLDHashTable(&ChildrenHashOps,
1949 : sizeof(ChildrenHashEntry),
1950 2 : aNumKids);
1951 66 : for (nsRuleNode* curr = ChildrenList(); curr; curr = curr->mNextSibling) {
1952 64 : Key key = curr->GetKey();
1953 : // This will never fail because of the initial size we gave the table.
1954 : auto entry =
1955 64 : static_cast<ChildrenHashEntry*>(hash->Add(&key));
1956 64 : NS_ASSERTION(!entry->mRuleNode, "duplicate entries in list");
1957 64 : entry->mRuleNode = curr;
1958 : }
1959 2 : SetChildrenHash(hash);
1960 2 : }
1961 :
1962 : void
1963 940 : nsRuleNode::RemoveChild(nsRuleNode* aNode)
1964 : {
1965 940 : MOZ_ASSERT(HaveChildren());
1966 940 : if (ChildrenAreHashed()) {
1967 64 : PLDHashTable* children = ChildrenHash();
1968 64 : Key key = aNode->GetKey();
1969 64 : MOZ_ASSERT(children->Search(&key));
1970 64 : children->Remove(&key);
1971 64 : if (children->EntryCount() == 0) {
1972 1 : delete children;
1973 1 : mChildren.asVoid = nullptr;
1974 : }
1975 : } else {
1976 : // This linear traversal is unfortunate, but we do the same thing when
1977 : // adding nodes. The traversal is bounded by kMaxChildrenInList.
1978 876 : nsRuleNode** curr = &mChildren.asList;
1979 2100 : while (*curr != aNode) {
1980 612 : curr = &((*curr)->mNextSibling);
1981 612 : MOZ_ASSERT(*curr);
1982 : }
1983 876 : *curr = (*curr)->mNextSibling;
1984 :
1985 : // If there was one element in the list, this sets mChildren.asList
1986 : // to 0, and HaveChildren() will return false.
1987 : }
1988 940 : }
1989 :
1990 : inline void
1991 897 : nsRuleNode::PropagateNoneBit(uint32_t aBit, nsRuleNode* aHighestNode)
1992 : {
1993 897 : nsRuleNode* curr = this;
1994 2369 : for (;;) {
1995 3266 : NS_ASSERTION(!(curr->mNoneBits & aBit), "propagating too far");
1996 3266 : curr->mNoneBits |= aBit;
1997 3266 : if (curr == aHighestNode)
1998 897 : break;
1999 2369 : curr = curr->mParent;
2000 : }
2001 897 : }
2002 :
2003 : inline void
2004 5627 : nsRuleNode::PropagateDependentBit(nsStyleStructID aSID, nsRuleNode* aHighestNode,
2005 : void* aStruct)
2006 : {
2007 5627 : NS_ASSERTION(aStruct, "expected struct");
2008 :
2009 5627 : uint32_t bit = nsCachedStyleData::GetBitForSID(aSID);
2010 18129 : for (nsRuleNode* curr = this; curr != aHighestNode; curr = curr->mParent) {
2011 13940 : if (curr->mDependentBits & bit) {
2012 : #ifdef DEBUG
2013 8462 : while (curr != aHighestNode) {
2014 3512 : NS_ASSERTION(curr->mDependentBits & bit, "bit not set");
2015 3512 : curr = curr->mParent;
2016 : }
2017 : #endif
2018 1438 : break;
2019 : }
2020 :
2021 12502 : curr->mDependentBits |= bit;
2022 :
2023 12502 : if (curr->IsUsedDirectly()) {
2024 5112 : curr->mStyleData.SetStyleData(aSID, mPresContext, aStruct);
2025 : }
2026 : }
2027 5627 : }
2028 :
2029 : /* static */ void
2030 0 : nsRuleNode::PropagateGrandancestorBit(GeckoStyleContext* aContext,
2031 : GeckoStyleContext* aContextInheritedFrom)
2032 : {
2033 0 : MOZ_ASSERT(aContext);
2034 0 : MOZ_ASSERT(aContextInheritedFrom &&
2035 : aContextInheritedFrom != aContext,
2036 : "aContextInheritedFrom must be an ancestor of aContext");
2037 :
2038 0 : for (GeckoStyleContext* context = aContext->GetParent();
2039 0 : context != aContextInheritedFrom;
2040 0 : context = context->GetParent()) {
2041 0 : if (!context) {
2042 0 : MOZ_ASSERT(false, "aContextInheritedFrom must be an ancestor of "
2043 : "aContext's parent");
2044 : break;
2045 : }
2046 0 : context->AddStyleBit(NS_STYLE_CHILD_USES_GRANDANCESTOR_STYLE);
2047 : }
2048 0 : }
2049 :
2050 : /*
2051 : * The following "Check" functions are used for determining what type of
2052 : * sharing can be used for the data on this rule node. MORE HERE...
2053 : */
2054 :
2055 : /*
2056 : * a callback function that that can revise the result of
2057 : * CheckSpecifiedProperties before finishing; aResult is the current
2058 : * result, and it returns the revised one.
2059 : */
2060 : typedef nsRuleNode::RuleDetail
2061 : (* CheckCallbackFn)(const nsRuleData* aRuleData,
2062 : nsRuleNode::RuleDetail aResult);
2063 :
2064 : /**
2065 : * @param aValue the value being examined
2066 : * @param aSpecifiedCount to be incremented by one if the value is specified
2067 : * @param aInheritedCount to be incremented by one if the value is set to inherit
2068 : * @param aUnsetCount to be incremented by one if the value is set to unset
2069 : */
2070 : inline void
2071 459071 : ExamineCSSValue(const nsCSSValue& aValue,
2072 : uint32_t& aSpecifiedCount,
2073 : uint32_t& aInheritedCount,
2074 : uint32_t& aUnsetCount)
2075 : {
2076 459071 : if (aValue.GetUnit() != eCSSUnit_Null) {
2077 25104 : ++aSpecifiedCount;
2078 25104 : if (aValue.GetUnit() == eCSSUnit_Inherit) {
2079 2608 : ++aInheritedCount;
2080 22496 : } else if (aValue.GetUnit() == eCSSUnit_Unset) {
2081 0 : ++aUnsetCount;
2082 : }
2083 : }
2084 459071 : }
2085 :
2086 : static nsRuleNode::RuleDetail
2087 640 : CheckFontCallback(const nsRuleData* aRuleData,
2088 : nsRuleNode::RuleDetail aResult)
2089 : {
2090 : // em, ex, percent, 'larger', and 'smaller' values on font-size depend
2091 : // on the parent context's font-size
2092 : // Likewise, 'lighter' and 'bolder' values of 'font-weight', and 'wider'
2093 : // and 'narrower' values of 'font-stretch' depend on the parent.
2094 640 : const nsCSSValue& size = *aRuleData->ValueForFontSize();
2095 640 : const nsCSSValue& weight = *aRuleData->ValueForFontWeight();
2096 1920 : if ((size.IsRelativeLengthUnit() && size.GetUnit() != eCSSUnit_RootEM) ||
2097 1280 : size.GetUnit() == eCSSUnit_Percent ||
2098 640 : (size.GetUnit() == eCSSUnit_Enumerated &&
2099 0 : (size.GetIntValue() == NS_STYLE_FONT_SIZE_SMALLER ||
2100 640 : size.GetIntValue() == NS_STYLE_FONT_SIZE_LARGER)) ||
2101 1920 : aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Integer ||
2102 640 : (weight.GetUnit() == eCSSUnit_Enumerated &&
2103 0 : (weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_BOLDER ||
2104 0 : weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_LIGHTER))) {
2105 0 : NS_ASSERTION(aResult == nsRuleNode::eRulePartialReset ||
2106 : aResult == nsRuleNode::eRuleFullReset ||
2107 : aResult == nsRuleNode::eRulePartialMixed ||
2108 : aResult == nsRuleNode::eRuleFullMixed,
2109 : "we know we already have a reset-counted property");
2110 : // Promote reset to mixed since we have something that depends on
2111 : // the parent. But never promote to inherited since that could
2112 : // cause inheritance of the exact value.
2113 0 : if (aResult == nsRuleNode::eRulePartialReset)
2114 0 : aResult = nsRuleNode::eRulePartialMixed;
2115 0 : else if (aResult == nsRuleNode::eRuleFullReset)
2116 0 : aResult = nsRuleNode::eRuleFullMixed;
2117 : }
2118 :
2119 640 : return aResult;
2120 : }
2121 :
2122 : static nsRuleNode::RuleDetail
2123 279 : CheckColorCallback(const nsRuleData* aRuleData,
2124 : nsRuleNode::RuleDetail aResult)
2125 : {
2126 : // currentColor values for color require inheritance
2127 279 : const nsCSSValue* colorValue = aRuleData->ValueForColor();
2128 289 : if (colorValue->GetUnit() == eCSSUnit_EnumColor &&
2129 10 : colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
2130 0 : NS_ASSERTION(aResult == nsRuleNode::eRuleFullReset,
2131 : "we should already be counted as full-reset");
2132 0 : aResult = nsRuleNode::eRuleFullInherited;
2133 : }
2134 :
2135 279 : return aResult;
2136 : }
2137 :
2138 : static nsRuleNode::RuleDetail
2139 950 : CheckTextCallback(const nsRuleData* aRuleData,
2140 : nsRuleNode::RuleDetail aResult)
2141 : {
2142 950 : const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
2143 958 : if (textAlignValue->GetUnit() == eCSSUnit_Enumerated &&
2144 8 : (textAlignValue->GetIntValue() ==
2145 8 : NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT ||
2146 8 : textAlignValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_MATCH_PARENT)) {
2147 : // Promote reset to mixed since we have something that depends on
2148 : // the parent.
2149 0 : if (aResult == nsRuleNode::eRulePartialReset)
2150 0 : aResult = nsRuleNode::eRulePartialMixed;
2151 0 : else if (aResult == nsRuleNode::eRuleFullReset)
2152 0 : aResult = nsRuleNode::eRuleFullMixed;
2153 : }
2154 :
2155 950 : return aResult;
2156 : }
2157 :
2158 : static nsRuleNode::RuleDetail
2159 576 : CheckVariablesCallback(const nsRuleData* aRuleData,
2160 : nsRuleNode::RuleDetail aResult)
2161 : {
2162 : // We don't actually have any properties on nsStyleVariables, so we do
2163 : // all of the RuleDetail calculation in here.
2164 576 : if (aRuleData->mVariables) {
2165 72 : return nsRuleNode::eRulePartialMixed;
2166 : }
2167 504 : return nsRuleNode::eRuleNone;
2168 : }
2169 :
2170 : #define FLAG_DATA_FOR_PROPERTY(name_, id_, method_, flags_, pref_, \
2171 : parsevariant_, kwtable_, stylestructoffset_, \
2172 : animtype_) \
2173 : flags_,
2174 :
2175 : // The order here must match the enums in *CheckCounter in nsCSSProps.cpp.
2176 :
2177 : static const uint32_t gFontFlags[] = {
2178 : #define CSS_PROP_FONT FLAG_DATA_FOR_PROPERTY
2179 : #include "nsCSSPropList.h"
2180 : #undef CSS_PROP_FONT
2181 : };
2182 :
2183 : static const uint32_t gDisplayFlags[] = {
2184 : #define CSS_PROP_DISPLAY FLAG_DATA_FOR_PROPERTY
2185 : #include "nsCSSPropList.h"
2186 : #undef CSS_PROP_DISPLAY
2187 : };
2188 :
2189 : static const uint32_t gVisibilityFlags[] = {
2190 : #define CSS_PROP_VISIBILITY FLAG_DATA_FOR_PROPERTY
2191 : #include "nsCSSPropList.h"
2192 : #undef CSS_PROP_VISIBILITY
2193 : };
2194 :
2195 : static const uint32_t gMarginFlags[] = {
2196 : #define CSS_PROP_MARGIN FLAG_DATA_FOR_PROPERTY
2197 : #include "nsCSSPropList.h"
2198 : #undef CSS_PROP_MARGIN
2199 : };
2200 :
2201 : static const uint32_t gBorderFlags[] = {
2202 : #define CSS_PROP_BORDER FLAG_DATA_FOR_PROPERTY
2203 : #include "nsCSSPropList.h"
2204 : #undef CSS_PROP_BORDER
2205 : };
2206 :
2207 : static const uint32_t gPaddingFlags[] = {
2208 : #define CSS_PROP_PADDING FLAG_DATA_FOR_PROPERTY
2209 : #include "nsCSSPropList.h"
2210 : #undef CSS_PROP_PADDING
2211 : };
2212 :
2213 : static const uint32_t gOutlineFlags[] = {
2214 : #define CSS_PROP_OUTLINE FLAG_DATA_FOR_PROPERTY
2215 : #include "nsCSSPropList.h"
2216 : #undef CSS_PROP_OUTLINE
2217 : };
2218 :
2219 : static const uint32_t gListFlags[] = {
2220 : #define CSS_PROP_LIST FLAG_DATA_FOR_PROPERTY
2221 : #include "nsCSSPropList.h"
2222 : #undef CSS_PROP_LIST
2223 : };
2224 :
2225 : static const uint32_t gColorFlags[] = {
2226 : #define CSS_PROP_COLOR FLAG_DATA_FOR_PROPERTY
2227 : #include "nsCSSPropList.h"
2228 : #undef CSS_PROP_COLOR
2229 : };
2230 :
2231 : static const uint32_t gBackgroundFlags[] = {
2232 : #define CSS_PROP_BACKGROUND FLAG_DATA_FOR_PROPERTY
2233 : #include "nsCSSPropList.h"
2234 : #undef CSS_PROP_BACKGROUND
2235 : };
2236 :
2237 : static const uint32_t gPositionFlags[] = {
2238 : #define CSS_PROP_POSITION FLAG_DATA_FOR_PROPERTY
2239 : #include "nsCSSPropList.h"
2240 : #undef CSS_PROP_POSITION
2241 : };
2242 :
2243 : static const uint32_t gTableFlags[] = {
2244 : #define CSS_PROP_TABLE FLAG_DATA_FOR_PROPERTY
2245 : #include "nsCSSPropList.h"
2246 : #undef CSS_PROP_TABLE
2247 : };
2248 :
2249 : static const uint32_t gTableBorderFlags[] = {
2250 : #define CSS_PROP_TABLEBORDER FLAG_DATA_FOR_PROPERTY
2251 : #include "nsCSSPropList.h"
2252 : #undef CSS_PROP_TABLEBORDER
2253 : };
2254 :
2255 : static const uint32_t gContentFlags[] = {
2256 : #define CSS_PROP_CONTENT FLAG_DATA_FOR_PROPERTY
2257 : #include "nsCSSPropList.h"
2258 : #undef CSS_PROP_CONTENT
2259 : };
2260 :
2261 : static const uint32_t gTextFlags[] = {
2262 : #define CSS_PROP_TEXT FLAG_DATA_FOR_PROPERTY
2263 : #include "nsCSSPropList.h"
2264 : #undef CSS_PROP_TEXT
2265 : };
2266 :
2267 : static const uint32_t gTextResetFlags[] = {
2268 : #define CSS_PROP_TEXTRESET FLAG_DATA_FOR_PROPERTY
2269 : #include "nsCSSPropList.h"
2270 : #undef CSS_PROP_TEXTRESET
2271 : };
2272 :
2273 : static const uint32_t gUserInterfaceFlags[] = {
2274 : #define CSS_PROP_USERINTERFACE FLAG_DATA_FOR_PROPERTY
2275 : #include "nsCSSPropList.h"
2276 : #undef CSS_PROP_USERINTERFACE
2277 : };
2278 :
2279 : static const uint32_t gUIResetFlags[] = {
2280 : #define CSS_PROP_UIRESET FLAG_DATA_FOR_PROPERTY
2281 : #include "nsCSSPropList.h"
2282 : #undef CSS_PROP_UIRESET
2283 : };
2284 :
2285 : static const uint32_t gXULFlags[] = {
2286 : #define CSS_PROP_XUL FLAG_DATA_FOR_PROPERTY
2287 : #include "nsCSSPropList.h"
2288 : #undef CSS_PROP_XUL
2289 : };
2290 :
2291 : static const uint32_t gSVGFlags[] = {
2292 : #define CSS_PROP_SVG FLAG_DATA_FOR_PROPERTY
2293 : #include "nsCSSPropList.h"
2294 : #undef CSS_PROP_SVG
2295 : };
2296 :
2297 : static const uint32_t gSVGResetFlags[] = {
2298 : #define CSS_PROP_SVGRESET FLAG_DATA_FOR_PROPERTY
2299 : #include "nsCSSPropList.h"
2300 : #undef CSS_PROP_SVGRESET
2301 : };
2302 :
2303 : static const uint32_t gColumnFlags[] = {
2304 : #define CSS_PROP_COLUMN FLAG_DATA_FOR_PROPERTY
2305 : #include "nsCSSPropList.h"
2306 : #undef CSS_PROP_COLUMN
2307 : };
2308 :
2309 : // There are no properties in nsStyleVariables, but we can't have a
2310 : // zero length array.
2311 : static const uint32_t gVariablesFlags[] = {
2312 : 0,
2313 : #define CSS_PROP_VARIABLES FLAG_DATA_FOR_PROPERTY
2314 : #include "nsCSSPropList.h"
2315 : #undef CSS_PROP_VARIABLES
2316 : };
2317 : static_assert(sizeof(gVariablesFlags) == sizeof(uint32_t),
2318 : "if nsStyleVariables has properties now you can remove the dummy "
2319 : "gVariablesFlags entry");
2320 :
2321 : static const uint32_t gEffectsFlags[] = {
2322 : #define CSS_PROP_EFFECTS FLAG_DATA_FOR_PROPERTY
2323 : #include "nsCSSPropList.h"
2324 : #undef CSS_PROP_EFFECTS
2325 : };
2326 :
2327 : #undef FLAG_DATA_FOR_PROPERTY
2328 :
2329 : static const uint32_t* gFlagsByStruct[] = {
2330 :
2331 : #define STYLE_STRUCT(name, checkdata_cb) \
2332 : g##name##Flags,
2333 : #include "nsStyleStructList.h"
2334 : #undef STYLE_STRUCT
2335 :
2336 : };
2337 :
2338 : static const CheckCallbackFn gCheckCallbacks[] = {
2339 :
2340 : #define STYLE_STRUCT(name, checkdata_cb) \
2341 : checkdata_cb,
2342 : #include "nsStyleStructList.h"
2343 : #undef STYLE_STRUCT
2344 :
2345 : };
2346 :
2347 : #ifdef DEBUG
2348 : static bool
2349 640 : AreAllMathMLPropertiesUndefined(const nsRuleData* aRuleData)
2350 : {
2351 : return
2352 1280 : aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Null &&
2353 1280 : aRuleData->ValueForScriptSizeMultiplier()->GetUnit() == eCSSUnit_Null &&
2354 1280 : aRuleData->ValueForScriptMinSize()->GetUnit() == eCSSUnit_Null &&
2355 1920 : aRuleData->ValueForMathVariant()->GetUnit() == eCSSUnit_Null &&
2356 1280 : aRuleData->ValueForMathDisplay()->GetUnit() == eCSSUnit_Null;
2357 : }
2358 : #endif
2359 :
2360 : inline nsRuleNode::RuleDetail
2361 33232 : nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID,
2362 : const nsRuleData* aRuleData)
2363 : {
2364 : // Build a count of the:
2365 33232 : uint32_t total = 0, // total number of props in the struct
2366 33232 : specified = 0, // number that were specified for this node
2367 33232 : inherited = 0, // number that were 'inherit' (and not
2368 : // eCSSUnit_Inherit) for this node
2369 33232 : unset = 0; // number that were 'unset'
2370 :
2371 : // See comment in nsRuleData.h above mValueOffsets.
2372 33232 : MOZ_ASSERT(aRuleData->mValueOffsets[aSID] == 0,
2373 : "we assume the value offset is zero instead of adding it");
2374 492303 : for (nsCSSValue *values = aRuleData->mValueStorage,
2375 33232 : *values_end = values + nsCSSProps::PropertyCountInStruct(aSID);
2376 492303 : values != values_end; ++values) {
2377 459071 : ++total;
2378 459071 : ExamineCSSValue(*values, specified, inherited, unset);
2379 : }
2380 :
2381 33232 : if (!nsCachedStyleData::IsReset(aSID)) {
2382 : // For inherited properties, 'unset' means the same as 'inherit'.
2383 14084 : inherited += unset;
2384 14084 : unset = 0;
2385 : }
2386 :
2387 : #if 0
2388 : printf("CheckSpecifiedProperties: SID=%d total=%d spec=%d inh=%d.\n",
2389 : aSID, total, specified, inherited);
2390 : #endif
2391 :
2392 33232 : NS_ASSERTION(aSID != eStyleStruct_Font ||
2393 : mPresContext->Document()->GetMathMLEnabled() ||
2394 : AreAllMathMLPropertiesUndefined(aRuleData),
2395 : "MathML style property was defined even though MathML is disabled");
2396 :
2397 : /*
2398 : * Return the most specific information we can: prefer None or Full
2399 : * over Partial, and Reset or Inherited over Mixed, since we can
2400 : * optimize based on the edge cases and not the in-between cases.
2401 : */
2402 : nsRuleNode::RuleDetail result;
2403 33232 : if (inherited == total)
2404 648 : result = eRuleFullInherited;
2405 65168 : else if (specified == total
2406 : // MathML defines 5 properties in Font that will never be set when
2407 : // MathML is not in use. Therefore if all but five
2408 : // properties have been set, and MathML is not enabled, we can treat
2409 : // this as fully specified. Code in nsMathMLElementFactory will
2410 : // rebuild the rule tree and style data when MathML is first enabled
2411 : // (see nsMathMLElement::BindToTree).
2412 32584 : || (aSID == eStyleStruct_Font && specified + 5 == total &&
2413 0 : !mPresContext->Document()->GetMathMLEnabled())
2414 : ) {
2415 281 : if (inherited == 0)
2416 281 : result = eRuleFullReset;
2417 : else
2418 0 : result = eRuleFullMixed;
2419 32303 : } else if (specified == 0)
2420 22989 : result = eRuleNone;
2421 9314 : else if (specified == inherited)
2422 570 : result = eRulePartialInherited;
2423 8744 : else if (inherited == 0)
2424 8581 : result = eRulePartialReset;
2425 : else
2426 163 : result = eRulePartialMixed;
2427 :
2428 33232 : CheckCallbackFn cb = gCheckCallbacks[aSID];
2429 33232 : if (cb) {
2430 2445 : result = (*cb)(aRuleData, result);
2431 : }
2432 :
2433 33232 : return result;
2434 : }
2435 :
2436 : // If we need to restrict which properties apply to the style context,
2437 : // return the bit to check in nsCSSProp's flags table. Otherwise,
2438 : // return 0.
2439 : inline uint32_t
2440 11850 : GetPseudoRestriction(GeckoStyleContext *aContext)
2441 : {
2442 : // This needs to match nsStyleSet::WalkRestrictionRule.
2443 11850 : uint32_t pseudoRestriction = 0;
2444 11850 : nsIAtom *pseudoType = aContext->GetPseudo();
2445 11850 : if (pseudoType) {
2446 2149 : if (pseudoType == nsCSSPseudoElements::firstLetter) {
2447 0 : pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LETTER;
2448 2149 : } else if (pseudoType == nsCSSPseudoElements::firstLine) {
2449 0 : pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LINE;
2450 2149 : } else if (pseudoType == nsCSSPseudoElements::placeholder) {
2451 63 : pseudoRestriction = CSS_PROPERTY_APPLIES_TO_PLACEHOLDER;
2452 : }
2453 : }
2454 11850 : return pseudoRestriction;
2455 : }
2456 :
2457 : static void
2458 63 : UnsetPropertiesWithoutFlags(const nsStyleStructID aSID,
2459 : nsRuleData* aRuleData,
2460 : uint32_t aFlags)
2461 : {
2462 63 : NS_ASSERTION(aFlags != 0, "aFlags must be nonzero");
2463 :
2464 63 : const uint32_t *flagData = gFlagsByStruct[aSID];
2465 :
2466 : // See comment in nsRuleData.h above mValueOffsets.
2467 63 : MOZ_ASSERT(aRuleData->mValueOffsets[aSID] == 0,
2468 : "we assume the value offset is zero instead of adding it");
2469 63 : nsCSSValue *values = aRuleData->mValueStorage;
2470 :
2471 1053 : for (size_t i = 0, i_end = nsCSSProps::PropertyCountInStruct(aSID);
2472 1053 : i != i_end; ++i) {
2473 990 : if ((flagData[i] & aFlags) != aFlags)
2474 696 : values[i].Reset();
2475 : }
2476 63 : }
2477 :
2478 11858 : AutoCSSValueArray::AutoCSSValueArray(void* aStorage, size_t aCount)
2479 : {
2480 11858 : MOZ_ASSERT(size_t(aStorage) % NS_ALIGNMENT_OF(nsCSSValue) == 0,
2481 : "bad alignment from alloca");
2482 11858 : mCount = aCount;
2483 : // Don't use placement new[], since it might store extra data
2484 : // for the count (on Windows!).
2485 11858 : mArray = static_cast<nsCSSValue*>(aStorage);
2486 171067 : for (size_t i = 0; i < mCount; ++i) {
2487 159209 : new (KnownNotNull, mArray + i) nsCSSValue();
2488 : }
2489 11858 : }
2490 :
2491 23716 : AutoCSSValueArray::~AutoCSSValueArray()
2492 : {
2493 171067 : for (size_t i = 0; i < mCount; ++i) {
2494 159209 : mArray[i].~nsCSSValue();
2495 : }
2496 11858 : }
2497 :
2498 : /* static */ bool
2499 11551 : nsRuleNode::ResolveVariableReferences(const nsStyleStructID aSID,
2500 : nsRuleData* aRuleData,
2501 : GeckoStyleContext* aContext)
2502 : {
2503 11551 : MOZ_ASSERT(aSID != eStyleStruct_Variables);
2504 11551 : MOZ_ASSERT(aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(aSID));
2505 11551 : MOZ_ASSERT(aRuleData->mValueOffsets[aSID] == 0);
2506 :
2507 23102 : nsCSSParser parser;
2508 11551 : bool anyTokenStreams = false;
2509 :
2510 : // Look at each property in the nsRuleData for the given style struct.
2511 11551 : size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
2512 170720 : for (nsCSSValue* value = aRuleData->mValueStorage,
2513 11551 : *values_end = aRuleData->mValueStorage + nprops;
2514 170720 : value != values_end; value++) {
2515 159169 : if (value->GetUnit() != eCSSUnit_TokenStream) {
2516 158286 : continue;
2517 : }
2518 :
2519 : const CSSVariableValues* variables =
2520 883 : &aContext->StyleVariables()->mVariables;
2521 883 : nsCSSValueTokenStream* tokenStream = value->GetTokenStreamValue();
2522 :
2523 883 : MOZ_ASSERT(tokenStream->mLevel != SheetType::Count,
2524 : "Token stream should have a defined level");
2525 :
2526 1766 : AutoRestore<SheetType> saveLevel(aRuleData->mLevel);
2527 883 : aRuleData->mLevel = tokenStream->mLevel;
2528 :
2529 : // Note that ParsePropertyWithVariableReferences relies on the fact
2530 : // that the nsCSSValue in aRuleData for the property we are re-parsing
2531 : // is still the token stream value. When
2532 : // ParsePropertyWithVariableReferences calls
2533 : // nsCSSExpandedDataBlock::MapRuleInfoInto, that function will add
2534 : // the ImageValue that is created into the token stream object's
2535 : // mImageValues table; see the comment above mImageValues for why.
2536 :
2537 : // XXX Should pass in sheet here (see bug 952338).
2538 883 : parser.ParsePropertyWithVariableReferences(
2539 : tokenStream->mPropertyID, tokenStream->mShorthandPropertyID,
2540 : tokenStream->mTokenStream, variables, aRuleData,
2541 : tokenStream->mSheetURI, tokenStream->mBaseURI,
2542 : tokenStream->mSheetPrincipal, nullptr,
2543 883 : tokenStream->mLineNumber, tokenStream->mLineOffset);
2544 883 : aRuleData->mConditions.SetUncacheable();
2545 883 : anyTokenStreams = true;
2546 : }
2547 :
2548 23102 : return anyTokenStreams;
2549 : }
2550 :
2551 : const void*
2552 11850 : nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
2553 : GeckoStyleContext* aContext)
2554 : {
2555 : // use placement new[] on the result of alloca() to allocate a
2556 : // variable-sized stack array, including execution of constructors,
2557 : // and use an RAII class to run the destructors too.
2558 11850 : size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
2559 11850 : void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
2560 23700 : AutoCSSValueArray dataArray(dataStorage, nprops);
2561 :
2562 : nsRuleData ruleData(nsCachedStyleData::GetBitForSID(aSID),
2563 23700 : dataArray.get(), mPresContext, aContext);
2564 11850 : ruleData.mValueOffsets[aSID] = 0;
2565 :
2566 : // We start at the most specific rule in the tree.
2567 11850 : void* startStruct = nullptr;
2568 :
2569 11850 : nsRuleNode* ruleNode = this;
2570 11850 : nsRuleNode* highestNode = nullptr; // The highest node in the rule tree
2571 : // that has the same properties
2572 : // specified for struct |aSID| as
2573 : // |this| does.
2574 11850 : nsRuleNode* rootNode = this; // After the loop below, this will be the
2575 : // highest node that we've walked without
2576 : // finding cached data on the rule tree.
2577 : // If we don't find any cached data, it
2578 : // will be the root. (XXX misnamed)
2579 11850 : RuleDetail detail = eRuleNone;
2580 11850 : uint32_t bit = nsCachedStyleData::GetBitForSID(aSID);
2581 :
2582 77024 : while (ruleNode) {
2583 : // See if this rule node has cached the fact that the remaining
2584 : // nodes along this path specify no data whatsoever.
2585 43802 : if (ruleNode->mNoneBits & bit)
2586 5224 : break;
2587 :
2588 : // If the dependent bit is set on a rule node for this struct, that
2589 : // means its rule won't have any information to add, so skip it.
2590 : // NOTE: If we exit the loop because of the !IsUsedDirectly() check,
2591 : // then we're guaranteed to break immediately afterwards due to a
2592 : // non-null startStruct.
2593 46246 : while ((ruleNode->mDependentBits & bit) && !ruleNode->IsUsedDirectly()) {
2594 3834 : NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nullptr,
2595 : "dependent bit with cached data makes no sense");
2596 : // Climb up to the next rule in the tree (a less specific rule).
2597 3834 : rootNode = ruleNode;
2598 3834 : ruleNode = ruleNode->mParent;
2599 3834 : NS_ASSERTION(!(ruleNode->mNoneBits & bit), "can't have both bits set");
2600 : }
2601 :
2602 : // Check for cached data after the inner loop above -- otherwise
2603 : // we'll miss it.
2604 38578 : startStruct = ruleNode->mStyleData.GetStyleData(aSID);
2605 38578 : if (startStruct)
2606 5705 : break; // We found a rule with fully specified data. We don't
2607 : // need to go up the tree any further, since the remainder
2608 : // of this branch has already been computed.
2609 :
2610 : // Ask the rule to fill in the properties that it specifies.
2611 32873 : nsIStyleRule *rule = ruleNode->mRule;
2612 32873 : if (rule) {
2613 32238 : ruleData.mLevel = ruleNode->GetLevel();
2614 32238 : ruleData.mIsImportantRule = ruleNode->IsImportantRule();
2615 32238 : rule->MapRuleInfoInto(&ruleData);
2616 : }
2617 :
2618 : // Now we check to see how many properties have been specified by
2619 : // the rules we've examined so far.
2620 32873 : RuleDetail oldDetail = detail;
2621 32873 : detail = CheckSpecifiedProperties(aSID, &ruleData);
2622 :
2623 32873 : if (oldDetail == eRuleNone && detail != eRuleNone)
2624 3847 : highestNode = ruleNode;
2625 :
2626 32873 : if (detail == eRuleFullReset ||
2627 32653 : detail == eRuleFullMixed ||
2628 : detail == eRuleFullInherited)
2629 : break; // We don't need to examine any more rules. All properties
2630 : // have been fully specified.
2631 :
2632 : // Climb up to the next rule in the tree (a less specific rule).
2633 32587 : rootNode = ruleNode;
2634 32587 : ruleNode = ruleNode->mParent;
2635 : }
2636 :
2637 11850 : bool recomputeDetail = false;
2638 :
2639 : // If we are computing a style struct other than nsStyleVariables, and
2640 : // ruleData has any properties with variable references (nsCSSValues of
2641 : // type eCSSUnit_TokenStream), then we need to resolve these.
2642 11850 : if (aSID != eStyleStruct_Variables) {
2643 : // A property's value might have became 'inherit' after resolving
2644 : // variable references. (This happens when an inherited property
2645 : // fails to parse its resolved value.) We need to recompute
2646 : // |detail| in case this happened.
2647 11551 : recomputeDetail = ResolveVariableReferences(aSID, &ruleData, aContext);
2648 : }
2649 :
2650 : // If needed, unset the properties that don't have a flag that allows
2651 : // them to be set for this style context. (For example, only some
2652 : // properties apply to :first-line and :first-letter.)
2653 11850 : uint32_t pseudoRestriction = GetPseudoRestriction(aContext);
2654 11850 : if (pseudoRestriction) {
2655 63 : UnsetPropertiesWithoutFlags(aSID, &ruleData, pseudoRestriction);
2656 :
2657 : // We need to recompute |detail| based on the restrictions we just applied.
2658 : // We can adjust |detail| arbitrarily because of the restriction
2659 : // rule added in nsStyleSet::WalkRestrictionRule.
2660 63 : recomputeDetail = true;
2661 : }
2662 :
2663 11850 : if (recomputeDetail) {
2664 359 : detail = CheckSpecifiedProperties(aSID, &ruleData);
2665 : }
2666 :
2667 11850 : NS_ASSERTION(!startStruct || (detail != eRuleFullReset &&
2668 : detail != eRuleFullMixed &&
2669 : detail != eRuleFullInherited),
2670 : "can't have start struct and be fully specified");
2671 :
2672 11850 : bool isReset = nsCachedStyleData::IsReset(aSID);
2673 11850 : if (!highestNode)
2674 8003 : highestNode = rootNode;
2675 :
2676 11850 : MOZ_ASSERT(!(aSID == eStyleStruct_Variables && startStruct),
2677 : "if we start caching Variables structs in the rule tree, then "
2678 : "not forcing detail to eRulePartialMixed just below is no "
2679 : "longer valid");
2680 :
2681 11850 : if (detail == eRuleNone && isReset) {
2682 : // We specified absolutely no rule information for a reset struct, and we
2683 : // may or may not have found a parent rule in the tree that specified all
2684 : // the rule information. Regardless, we don't need to use any cache
2685 : // conditions if we cache this struct in the rule tree.
2686 : //
2687 : // Normally ruleData.mConditions would already indicate that the struct
2688 : // is cacheable without conditions if detail is eRuleNone, but because
2689 : // of the UnsetPropertiesWithoutFlags call above, we may have encountered
2690 : // some rules with dependencies, which we then cleared out of ruleData.
2691 : //
2692 : // ruleData.mConditions could also indicate we are not cacheable at all,
2693 : // such as when AnimValuesStyleRule prevents us from caching structs
2694 : // when attempting to apply animations to pseudos.
2695 : //
2696 : // So if we we are uncacheable, we leave it, but if we are cacheable
2697 : // with dependencies, we convert that to cacheable without dependencies.
2698 4512 : if (ruleData.mConditions.CacheableWithDependencies()) {
2699 0 : MOZ_ASSERT(pseudoRestriction,
2700 : "should only be cacheable with dependencies if we had a "
2701 : "pseudo restriction");
2702 0 : ruleData.mConditions.Clear();
2703 : } else {
2704 : // XXXheycam We shouldn't have `|| GetLevel() == SheetType::Transition`
2705 : // in the assertion condition, but rule nodes created by
2706 : // ResolveStyleByAddingRules don't call SetIsAnimationRule().
2707 4512 : MOZ_ASSERT(ruleData.mConditions.CacheableWithoutDependencies() ||
2708 : ((HasAnimationData() ||
2709 : GetLevel() == SheetType::Transition) &&
2710 : aContext->GetParent() &&
2711 : aContext->GetParent()->HasPseudoElementData()),
2712 : "should only be uncacheable if we had an animation rule "
2713 : "and we're inside a pseudo");
2714 : }
2715 : }
2716 :
2717 11850 : if (!ruleData.mConditions.CacheableWithoutDependencies() &&
2718 : aSID != eStyleStruct_Variables) {
2719 : // Treat as though some data is specified to avoid the optimizations and
2720 : // force data computation.
2721 : //
2722 : // We don't need to do this for Variables structs since we know those are
2723 : // never cached in the rule tree, and it avoids wasteful computation of a
2724 : // new Variables struct when we have no additional variable declarations,
2725 : // which otherwise could happen when there is an AnimValuesStyleRule
2726 : // (which calls SetUncacheable for style contexts with pseudo data).
2727 358 : detail = eRulePartialMixed;
2728 : }
2729 :
2730 11850 : if (detail == eRuleNone && startStruct) {
2731 : // We specified absolutely no rule information, but a parent rule in the tree
2732 : // specified all the rule information. We set a bit along the branch from our
2733 : // node in the tree to the node that specified the data that tells nodes on that
2734 : // branch that they never need to examine their rules for this particular struct type
2735 : // ever again.
2736 4216 : PropagateDependentBit(aSID, ruleNode, startStruct);
2737 : // For inherited structs, mark the struct (which will be set on
2738 : // the context by our caller) as not being owned by the context.
2739 4216 : if (!isReset) {
2740 3 : aContext->AddStyleBit(nsCachedStyleData::GetBitForSID(aSID));
2741 4213 : } else if (HasAnimationData()) {
2742 : // If we have animation data, the struct should be cached on the style
2743 : // context so that we can peek the struct.
2744 : // See comment in AnimValuesStyleRule::MapRuleInfoInto.
2745 76 : StoreStyleOnContext(aContext, aSID, startStruct);
2746 : }
2747 :
2748 4216 : return startStruct;
2749 : }
2750 7634 : if ((!startStruct && !isReset &&
2751 1913 : (detail == eRuleNone || detail == eRulePartialInherited)) ||
2752 : detail == eRuleFullInherited) {
2753 : // We specified no non-inherited information and neither did any of
2754 : // our parent rules.
2755 :
2756 : // We set a bit along the branch from the highest node (ruleNode)
2757 : // down to our node (this) indicating that no non-inherited data was
2758 : // specified. This bit is guaranteed to be set already on the path
2759 : // from the highest node to the root node in the case where
2760 : // (detail == eRuleNone), which is the most common case here.
2761 : // We must check |!isReset| because the Compute*Data functions for
2762 : // reset structs wouldn't handle none bits correctly.
2763 3559 : if (highestNode != this && !isReset)
2764 897 : PropagateNoneBit(bit, highestNode);
2765 :
2766 : // All information must necessarily be inherited from our parent style context.
2767 : // In the absence of any computed data in the rule tree and with
2768 : // no rules specified that didn't have values of 'inherit', we should check our parent.
2769 3559 : GeckoStyleContext* parentContext = aContext->GetParent();
2770 3559 : if (isReset) {
2771 : /* Reset structs don't inherit from first-line. */
2772 : /* See similar code in COMPUTE_START_RESET */
2773 122 : while (parentContext &&
2774 61 : parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) {
2775 0 : parentContext = parentContext->GetParent();
2776 : }
2777 61 : if (parentContext && parentContext != aContext->GetParent()) {
2778 0 : PropagateGrandancestorBit(aContext, parentContext);
2779 : }
2780 : }
2781 3559 : if (parentContext) {
2782 : // We have a parent, and so we should just inherit from the parent.
2783 : // Set the inherit bits on our context. These bits tell the style context that
2784 : // it never has to go back to the rule tree for data. Instead the style context tree
2785 : // should be walked to find the data.
2786 3145 : const void* parentStruct = parentContext->StyleData(aSID);
2787 3145 : aContext->AddStyleBit(bit); // makes const_cast OK.
2788 3145 : aContext->SetStyle(aSID, const_cast<void*>(parentStruct));
2789 3145 : if (isReset) {
2790 61 : parentContext->AddStyleBit(NS_STYLE_HAS_CHILD_THAT_USES_RESET_STYLE);
2791 : }
2792 3145 : return parentStruct;
2793 : }
2794 : else
2795 : // We are the root. In the case of fonts, the default values just
2796 : // come from the pres context.
2797 414 : return SetDefaultOnRoot(aSID, aContext);
2798 : }
2799 :
2800 : typedef const void* (nsRuleNode::*ComputeFunc)(void*, const nsRuleData*,
2801 : GeckoStyleContext*, nsRuleNode*,
2802 : RuleDetail,
2803 : const RuleNodeCacheConditions);
2804 : static const ComputeFunc sComputeFuncs[] = {
2805 : #define STYLE_STRUCT(name, checkdata_cb) &nsRuleNode::Compute##name##Data,
2806 : #include "nsStyleStructList.h"
2807 : #undef STYLE_STRUCT
2808 : };
2809 :
2810 : // We need to compute the data from the information that the rules specified.
2811 12225 : return (this->*sComputeFuncs[aSID])(startStruct, &ruleData, aContext,
2812 : highestNode, detail,
2813 12225 : ruleData.mConditions);
2814 : }
2815 :
2816 : const void*
2817 414 : nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, GeckoStyleContext* aContext)
2818 : {
2819 414 : switch (aSID) {
2820 : case eStyleStruct_Font:
2821 : {
2822 8 : nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
2823 8 : nscoord minimumFontSize = mPresContext->MinFontSize(fontData->mLanguage);
2824 :
2825 8 : if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
2826 0 : fontData->mFont.size = std::max(fontData->mSize, minimumFontSize);
2827 : }
2828 : else {
2829 8 : fontData->mFont.size = fontData->mSize;
2830 : }
2831 8 : aContext->SetStyle(eStyleStruct_Font, fontData);
2832 8 : return fontData;
2833 : }
2834 : case eStyleStruct_Display:
2835 : {
2836 0 : nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay(mPresContext);
2837 0 : aContext->SetStyle(eStyleStruct_Display, disp);
2838 0 : return disp;
2839 : }
2840 : case eStyleStruct_Visibility:
2841 : {
2842 129 : nsStyleVisibility* vis = new (mPresContext) nsStyleVisibility(mPresContext);
2843 129 : aContext->SetStyle(eStyleStruct_Visibility, vis);
2844 129 : return vis;
2845 : }
2846 : case eStyleStruct_Text:
2847 : {
2848 52 : nsStyleText* text = new (mPresContext) nsStyleText(mPresContext);
2849 52 : aContext->SetStyle(eStyleStruct_Text, text);
2850 52 : return text;
2851 : }
2852 : case eStyleStruct_TextReset:
2853 : {
2854 0 : nsStyleTextReset* text = new (mPresContext) nsStyleTextReset(mPresContext);
2855 0 : aContext->SetStyle(eStyleStruct_TextReset, text);
2856 0 : return text;
2857 : }
2858 : case eStyleStruct_Color:
2859 : {
2860 25 : nsStyleColor* color = new (mPresContext) nsStyleColor(mPresContext);
2861 25 : aContext->SetStyle(eStyleStruct_Color, color);
2862 25 : return color;
2863 : }
2864 : case eStyleStruct_Background:
2865 : {
2866 0 : nsStyleBackground* bg = new (mPresContext) nsStyleBackground(mPresContext);
2867 0 : aContext->SetStyle(eStyleStruct_Background, bg);
2868 0 : return bg;
2869 : }
2870 : case eStyleStruct_Margin:
2871 : {
2872 0 : nsStyleMargin* margin = new (mPresContext) nsStyleMargin(mPresContext);
2873 0 : aContext->SetStyle(eStyleStruct_Margin, margin);
2874 0 : return margin;
2875 : }
2876 : case eStyleStruct_Border:
2877 : {
2878 0 : nsStyleBorder* border = new (mPresContext) nsStyleBorder(mPresContext);
2879 0 : aContext->SetStyle(eStyleStruct_Border, border);
2880 0 : return border;
2881 : }
2882 : case eStyleStruct_Padding:
2883 : {
2884 0 : nsStylePadding* padding = new (mPresContext) nsStylePadding(mPresContext);
2885 0 : aContext->SetStyle(eStyleStruct_Padding, padding);
2886 0 : return padding;
2887 : }
2888 : case eStyleStruct_Outline:
2889 : {
2890 0 : nsStyleOutline* outline = new (mPresContext) nsStyleOutline(mPresContext);
2891 0 : aContext->SetStyle(eStyleStruct_Outline, outline);
2892 0 : return outline;
2893 : }
2894 : case eStyleStruct_List:
2895 : {
2896 3 : nsStyleList* list = new (mPresContext) nsStyleList(mPresContext);
2897 3 : aContext->SetStyle(eStyleStruct_List, list);
2898 3 : return list;
2899 : }
2900 : case eStyleStruct_Position:
2901 : {
2902 0 : nsStylePosition* pos = new (mPresContext) nsStylePosition(mPresContext);
2903 0 : aContext->SetStyle(eStyleStruct_Position, pos);
2904 0 : return pos;
2905 : }
2906 : case eStyleStruct_Table:
2907 : {
2908 0 : nsStyleTable* table = new (mPresContext) nsStyleTable(mPresContext);
2909 0 : aContext->SetStyle(eStyleStruct_Table, table);
2910 0 : return table;
2911 : }
2912 : case eStyleStruct_TableBorder:
2913 : {
2914 0 : nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder(mPresContext);
2915 0 : aContext->SetStyle(eStyleStruct_TableBorder, table);
2916 0 : return table;
2917 : }
2918 : case eStyleStruct_Content:
2919 : {
2920 0 : nsStyleContent* content = new (mPresContext) nsStyleContent(mPresContext);
2921 0 : aContext->SetStyle(eStyleStruct_Content, content);
2922 0 : return content;
2923 : }
2924 : case eStyleStruct_UserInterface:
2925 : {
2926 174 : nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface(mPresContext);
2927 174 : aContext->SetStyle(eStyleStruct_UserInterface, ui);
2928 174 : return ui;
2929 : }
2930 : case eStyleStruct_UIReset:
2931 : {
2932 0 : nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset(mPresContext);
2933 0 : aContext->SetStyle(eStyleStruct_UIReset, ui);
2934 0 : return ui;
2935 : }
2936 : case eStyleStruct_XUL:
2937 : {
2938 0 : nsStyleXUL* xul = new (mPresContext) nsStyleXUL(mPresContext);
2939 0 : aContext->SetStyle(eStyleStruct_XUL, xul);
2940 0 : return xul;
2941 : }
2942 : case eStyleStruct_Column:
2943 : {
2944 0 : nsStyleColumn* column = new (mPresContext) nsStyleColumn(mPresContext);
2945 0 : aContext->SetStyle(eStyleStruct_Column, column);
2946 0 : return column;
2947 : }
2948 : case eStyleStruct_SVG:
2949 : {
2950 23 : nsStyleSVG* svg = new (mPresContext) nsStyleSVG(mPresContext);
2951 23 : aContext->SetStyle(eStyleStruct_SVG, svg);
2952 23 : return svg;
2953 : }
2954 : case eStyleStruct_SVGReset:
2955 : {
2956 0 : nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset(mPresContext);
2957 0 : aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
2958 0 : return svgReset;
2959 : }
2960 : case eStyleStruct_Variables:
2961 : {
2962 0 : nsStyleVariables* vars = new (mPresContext) nsStyleVariables(mPresContext);
2963 0 : aContext->SetStyle(eStyleStruct_Variables, vars);
2964 0 : return vars;
2965 : }
2966 : case eStyleStruct_Effects:
2967 : {
2968 0 : nsStyleEffects* effects = new (mPresContext) nsStyleEffects(mPresContext);
2969 0 : aContext->SetStyle(eStyleStruct_Effects, effects);
2970 0 : return effects;
2971 : }
2972 : default:
2973 : /*
2974 : * unhandled case: nsStyleStructID_Length.
2975 : * last item of nsStyleStructID, to know its length.
2976 : */
2977 0 : MOZ_ASSERT(false, "unexpected SID");
2978 : return nullptr;
2979 : }
2980 : return nullptr;
2981 : }
2982 :
2983 : /**
2984 : * Begin an nsRuleNode::Compute*Data function for an inherited struct.
2985 : *
2986 : * @param type_ The nsStyle* type this function computes.
2987 : * @param data_ Variable (declared here) holding the result of this
2988 : * function.
2989 : * @param parentdata_ Variable (declared here) holding the parent style
2990 : * context's data for this struct.
2991 : */
2992 : #define COMPUTE_START_INHERITED(type_, data_, parentdata_) \
2993 : NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
2994 : "should not have bothered calling Compute*Data"); \
2995 : \
2996 : GeckoStyleContext* parentContext = aContext->GetParent(); \
2997 : \
2998 : nsStyle##type_* data_ = nullptr; \
2999 : mozilla::Maybe<nsStyle##type_> maybeFakeParentData; \
3000 : const nsStyle##type_* parentdata_ = nullptr; \
3001 : RuleNodeCacheConditions conditions = aConditions; \
3002 : \
3003 : /* If |conditions.Cacheable()| might be true by the time we're done, we */ \
3004 : /* can't call parentContext->Style##type_() since it could recur into */ \
3005 : /* setting the same struct on the same rule node, causing a leak. */ \
3006 : if (aRuleDetail != eRuleFullReset && \
3007 : (!aStartStruct || (aRuleDetail != eRulePartialReset && \
3008 : aRuleDetail != eRuleNone))) { \
3009 : if (parentContext) { \
3010 : parentdata_ = parentContext->Style##type_(); \
3011 : } else { \
3012 : maybeFakeParentData.emplace(mPresContext); \
3013 : parentdata_ = maybeFakeParentData.ptr(); \
3014 : } \
3015 : } \
3016 : if (eStyleStruct_##type_ == eStyleStruct_Variables) \
3017 : /* no need to copy construct an nsStyleVariables, as we will copy */ \
3018 : /* inherited variables (and call SetUncacheable()) in */ \
3019 : /* ComputeVariablesData */ \
3020 : data_ = new (mPresContext) nsStyle##type_(mPresContext); \
3021 : else if (aStartStruct) \
3022 : /* We only need to compute the delta between this computed data and */ \
3023 : /* our computed data. */ \
3024 : data_ = new (mPresContext) \
3025 : nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
3026 : else { \
3027 : if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) { \
3028 : /* No question. We will have to inherit. Go ahead and init */ \
3029 : /* with inherited vals from parent. */ \
3030 : conditions.SetUncacheable(); \
3031 : if (parentdata_) \
3032 : data_ = new (mPresContext) nsStyle##type_(*parentdata_); \
3033 : else \
3034 : data_ = new (mPresContext) nsStyle##type_(mPresContext); \
3035 : } \
3036 : else \
3037 : data_ = new (mPresContext) nsStyle##type_(mPresContext); \
3038 : } \
3039 : \
3040 : if (!parentdata_) \
3041 : parentdata_ = data_;
3042 :
3043 : /**
3044 : * Begin an nsRuleNode::Compute*Data function for a reset struct.
3045 : *
3046 : * @param type_ The nsStyle* type this function computes.
3047 : * @param data_ Variable (declared here) holding the result of this
3048 : * function.
3049 : * @param parentdata_ Variable (declared here) holding the parent style
3050 : * context's data for this struct.
3051 : */
3052 : #define COMPUTE_START_RESET(type_, data_, parentdata_) \
3053 : NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
3054 : "should not have bothered calling Compute*Data"); \
3055 : \
3056 : GeckoStyleContext* parentContext = aContext->GetParent(); \
3057 : /* Reset structs don't inherit from first-line */ \
3058 : /* See similar code in WalkRuleTree */ \
3059 : while (parentContext && \
3060 : parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) { \
3061 : parentContext = parentContext->GetParent(); \
3062 : } \
3063 : \
3064 : nsStyle##type_* data_; \
3065 : if (aStartStruct) \
3066 : /* We only need to compute the delta between this computed data and */ \
3067 : /* our computed data. */ \
3068 : data_ = new (mPresContext) \
3069 : nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
3070 : else \
3071 : data_ = new (mPresContext) nsStyle##type_(mPresContext); \
3072 : \
3073 : /* If |conditions.Cacheable()| might be true by the time we're done, we */ \
3074 : /* can't call parentContext->Style##type_() since it could recur into */ \
3075 : /* setting the same struct on the same rule node, causing a leak. */ \
3076 : mozilla::Maybe<nsStyle##type_> maybeFakeParentData; \
3077 : const nsStyle##type_* parentdata_ = data_; \
3078 : if (aRuleDetail != eRuleFullReset && \
3079 : aRuleDetail != eRulePartialReset && \
3080 : aRuleDetail != eRuleNone) { \
3081 : if (parentContext) { \
3082 : parentdata_ = parentContext->Style##type_(); \
3083 : } else { \
3084 : maybeFakeParentData.emplace(mPresContext); \
3085 : parentdata_ = maybeFakeParentData.ptr(); \
3086 : } \
3087 : } \
3088 : RuleNodeCacheConditions conditions = aConditions;
3089 :
3090 : /**
3091 : * End an nsRuleNode::Compute*Data function for an inherited struct.
3092 : *
3093 : * @param type_ The nsStyle* type this function computes.
3094 : * @param data_ Variable holding the result of this function.
3095 : */
3096 : #define COMPUTE_END_INHERITED(type_, data_) \
3097 : NS_POSTCONDITION(!conditions.CacheableWithoutDependencies() || \
3098 : aRuleDetail == eRuleFullReset || \
3099 : (aStartStruct && aRuleDetail == eRulePartialReset), \
3100 : "conditions.CacheableWithoutDependencies() must be false " \
3101 : "for inherited structs unless all properties have been " \
3102 : "specified with values other than inherit"); \
3103 : if (conditions.CacheableWithoutDependencies()) { \
3104 : /* We were fully specified and can therefore be cached right on the */ \
3105 : /* rule node. */ \
3106 : if (!aHighestNode->mStyleData.mInheritedData) { \
3107 : aHighestNode->mStyleData.mInheritedData = \
3108 : new (mPresContext) nsInheritedStyleData; \
3109 : } \
3110 : NS_ASSERTION(!aHighestNode->mStyleData.mInheritedData-> \
3111 : mStyleStructs[eStyleStruct_##type_], \
3112 : "Going to leak style data"); \
3113 : aHighestNode->mStyleData.mInheritedData-> \
3114 : mStyleStructs[eStyleStruct_##type_] = data_; \
3115 : /* Propagate the bit down. */ \
3116 : PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_); \
3117 : /* Tell the style context that it doesn't own the data */ \
3118 : aContext->AddStyleBit(NS_STYLE_INHERIT_BIT(type_)); \
3119 : } \
3120 : /* For inherited structs, our caller will cache the data on the */ \
3121 : /* style context */ \
3122 : \
3123 : return data_;
3124 :
3125 : /**
3126 : * End an nsRuleNode::Compute*Data function for a reset struct.
3127 : *
3128 : * @param type_ The nsStyle* type this function computes.
3129 : * @param data_ Variable holding the result of this function.
3130 : */
3131 : #define COMPUTE_END_RESET(type_, data_) \
3132 : NS_POSTCONDITION(!conditions.CacheableWithoutDependencies() || \
3133 : aRuleDetail == eRuleNone || \
3134 : aRuleDetail == eRulePartialReset || \
3135 : aRuleDetail == eRuleFullReset, \
3136 : "conditions.CacheableWithoutDependencies() must be false " \
3137 : "for reset structs if any properties were specified as " \
3138 : "inherit"); \
3139 : if (conditions.CacheableWithoutDependencies()) { \
3140 : /* We were fully specified and can therefore be cached right on the */ \
3141 : /* rule node. */ \
3142 : if (!aHighestNode->mStyleData.mResetData) { \
3143 : aHighestNode->mStyleData.mResetData = \
3144 : new (mPresContext) nsConditionalResetStyleData; \
3145 : } \
3146 : NS_ASSERTION(!aHighestNode->mStyleData.mResetData-> \
3147 : GetStyleData(eStyleStruct_##type_), \
3148 : "Going to leak style data"); \
3149 : aHighestNode->mStyleData.mResetData-> \
3150 : SetStyleData(eStyleStruct_##type_, data_); \
3151 : /* Propagate the bit down. */ \
3152 : PropagateDependentBit(eStyleStruct_##type_, aHighestNode, data_); \
3153 : if (HasAnimationData()) { \
3154 : /* If we have animation data, the struct should be cached on the */ \
3155 : /* style context so that we can peek the struct. */ \
3156 : /* See comment in AnimValuesStyleRule::MapRuleInfoInto. */ \
3157 : StoreStyleOnContext(aContext, eStyleStruct_##type_, data_); \
3158 : } \
3159 : } else if (conditions.Cacheable()) { \
3160 : if (!mStyleData.mResetData) { \
3161 : mStyleData.mResetData = new (mPresContext) nsConditionalResetStyleData; \
3162 : } \
3163 : mStyleData.mResetData-> \
3164 : SetStyleData(eStyleStruct_##type_, mPresContext, data_, conditions); \
3165 : /* Tell the style context that it doesn't own the data */ \
3166 : aContext->AddStyleBit(NS_STYLE_INHERIT_BIT(type_)); \
3167 : aContext->SetStyle(eStyleStruct_##type_, data_); \
3168 : } else { \
3169 : /* We can't be cached in the rule node. We have to be put right */ \
3170 : /* on the style context. */ \
3171 : aContext->SetStyle(eStyleStruct_##type_, data_); \
3172 : if (aContext->GetParent()) { \
3173 : /* This is pessimistic; we could be uncacheable because we had a */ \
3174 : /* relative font-weight, for example, which does not need to defeat */ \
3175 : /* the restyle optimizations in RestyleManager.cpp that look at */ \
3176 : /* NS_STYLE_HAS_CHILD_THAT_USES_RESET_STYLE. */ \
3177 : aContext->GetParent()-> \
3178 : AddStyleBit(NS_STYLE_HAS_CHILD_THAT_USES_RESET_STYLE); \
3179 : } \
3180 : } \
3181 : \
3182 : return data_;
3183 :
3184 : // This function figures out how much scaling should be suppressed to
3185 : // satisfy scriptminsize. This is our attempt to implement
3186 : // http://www.w3.org/TR/MathML2/chapter3.html#id.3.3.4.2.2
3187 : // This is called after mScriptLevel, mScriptMinSize and mScriptSizeMultiplier
3188 : // have been set in aFont.
3189 : //
3190 : // Here are the invariants we enforce:
3191 : // 1) A decrease in size must not reduce the size below minscriptsize.
3192 : // 2) An increase in size must not increase the size above the size we would
3193 : // have if minscriptsize had not been applied anywhere.
3194 : // 3) The scriptlevel-induced size change must between 1.0 and the parent's
3195 : // scriptsizemultiplier^(new script level - old script level), as close to the
3196 : // latter as possible subject to constraints 1 and 2.
3197 : static nscoord
3198 12 : ComputeScriptLevelSize(const nsStyleFont* aFont, const nsStyleFont* aParentFont,
3199 : nsPresContext* aPresContext, nscoord* aUnconstrainedSize)
3200 : {
3201 : int32_t scriptLevelChange =
3202 12 : aFont->mScriptLevel - aParentFont->mScriptLevel;
3203 12 : if (scriptLevelChange == 0) {
3204 12 : *aUnconstrainedSize = aParentFont->mScriptUnconstrainedSize;
3205 : // Constraint #3 says that we cannot change size, and #1 and #2 are always
3206 : // satisfied with no change. It's important this be fast because it covers
3207 : // all non-MathML content.
3208 12 : return aParentFont->mSize;
3209 : }
3210 :
3211 : // Compute actual value of minScriptSize
3212 0 : nscoord minScriptSize = aParentFont->mScriptMinSize;
3213 0 : if (aFont->mAllowZoom) {
3214 0 : minScriptSize = nsStyleFont::ZoomText(aPresContext, minScriptSize);
3215 : }
3216 :
3217 : double scriptLevelScale =
3218 0 : pow(aParentFont->mScriptSizeMultiplier, scriptLevelChange);
3219 : // Compute the size we would have had if minscriptsize had never been
3220 : // applied, also prevent overflow (bug 413274)
3221 0 : *aUnconstrainedSize =
3222 0 : NSToCoordRoundWithClamp(aParentFont->mScriptUnconstrainedSize*scriptLevelScale);
3223 : // Compute the size we could get via scriptlevel change
3224 : nscoord scriptLevelSize =
3225 0 : NSToCoordRoundWithClamp(aParentFont->mSize*scriptLevelScale);
3226 0 : if (scriptLevelScale <= 1.0) {
3227 0 : if (aParentFont->mSize <= minScriptSize) {
3228 : // We can't decrease the font size at all, so just stick to no change
3229 : // (authors are allowed to explicitly set the font size smaller than
3230 : // minscriptsize)
3231 0 : return aParentFont->mSize;
3232 : }
3233 : // We can decrease, so apply constraint #1
3234 0 : return std::max(minScriptSize, scriptLevelSize);
3235 : } else {
3236 : // scriptminsize can only make sizes larger than the unconstrained size
3237 0 : NS_ASSERTION(*aUnconstrainedSize <= scriptLevelSize, "How can this ever happen?");
3238 : // Apply constraint #2
3239 0 : return std::min(scriptLevelSize, std::max(*aUnconstrainedSize, minScriptSize));
3240 : }
3241 : }
3242 :
3243 :
3244 : /* static */ nscoord
3245 0 : nsRuleNode::CalcFontPointSize(int32_t aHTMLSize, int32_t aBasePointSize,
3246 : nsPresContext* aPresContext,
3247 : nsFontSizeType aFontSizeType)
3248 : {
3249 : #define sFontSizeTableMin 9
3250 : #define sFontSizeTableMax 16
3251 :
3252 : // This table seems to be the one used by MacIE5. We hope its adoption in Mozilla
3253 : // and eventually in WinIE5.5 will help to establish a standard rendering across
3254 : // platforms and browsers. For now, it is used only in Strict mode. More can be read
3255 : // in the document written by Todd Farhner at:
3256 : // http://style.verso.com/font_size_intervals/altintervals.html
3257 : //
3258 : static int32_t sStrictFontSizeTable[sFontSizeTableMax - sFontSizeTableMin + 1][8] =
3259 : {
3260 : { 9, 9, 9, 9, 11, 14, 18, 27},
3261 : { 9, 9, 9, 10, 12, 15, 20, 30},
3262 : { 9, 9, 10, 11, 13, 17, 22, 33},
3263 : { 9, 9, 10, 12, 14, 18, 24, 36},
3264 : { 9, 10, 12, 13, 16, 20, 26, 39},
3265 : { 9, 10, 12, 14, 17, 21, 28, 42},
3266 : { 9, 10, 13, 15, 18, 23, 30, 45},
3267 : { 9, 10, 13, 16, 18, 24, 32, 48}
3268 : };
3269 : // HTML 1 2 3 4 5 6 7
3270 : // CSS xxs xs s m l xl xxl
3271 : // |
3272 : // user pref
3273 : //
3274 : //------------------------------------------------------------
3275 : //
3276 : // This table gives us compatibility with WinNav4 for the default fonts only.
3277 : // In WinNav4, the default fonts were:
3278 : //
3279 : // Times/12pt == Times/16px at 96ppi
3280 : // Courier/10pt == Courier/13px at 96ppi
3281 : //
3282 : // The 2 lines below marked "anchored" have the exact pixel sizes used by
3283 : // WinNav4 for Times/12pt and Courier/10pt at 96ppi. As you can see, the
3284 : // HTML size 3 (user pref) for those 2 anchored lines is 13px and 16px.
3285 : //
3286 : // All values other than the anchored values were filled in by hand, never
3287 : // going below 9px, and maintaining a "diagonal" relationship. See for
3288 : // example the 13s -- they follow a diagonal line through the table.
3289 : //
3290 : static int32_t sQuirksFontSizeTable[sFontSizeTableMax - sFontSizeTableMin + 1][8] =
3291 : {
3292 : { 9, 9, 9, 9, 11, 14, 18, 28 },
3293 : { 9, 9, 9, 10, 12, 15, 20, 31 },
3294 : { 9, 9, 9, 11, 13, 17, 22, 34 },
3295 : { 9, 9, 10, 12, 14, 18, 24, 37 },
3296 : { 9, 9, 10, 13, 16, 20, 26, 40 }, // anchored (13)
3297 : { 9, 9, 11, 14, 17, 21, 28, 42 },
3298 : { 9, 10, 12, 15, 17, 23, 30, 45 },
3299 : { 9, 10, 13, 16, 18, 24, 32, 48 } // anchored (16)
3300 : };
3301 : // HTML 1 2 3 4 5 6 7
3302 : // CSS xxs xs s m l xl xxl
3303 : // |
3304 : // user pref
3305 :
3306 : #if 0
3307 : //
3308 : // These are the exact pixel values used by WinIE5 at 96ppi.
3309 : //
3310 : { ?, 8, 11, 12, 13, 16, 21, 32 }, // smallest
3311 : { ?, 9, 12, 13, 16, 21, 27, 40 }, // smaller
3312 : { ?, 10, 13, 16, 18, 24, 32, 48 }, // medium
3313 : { ?, 13, 16, 19, 21, 27, 37, ?? }, // larger
3314 : { ?, 16, 19, 21, 24, 32, 43, ?? } // largest
3315 : //
3316 : // HTML 1 2 3 4 5 6 7
3317 : // CSS ? ? ? ? ? ? ? ?
3318 : //
3319 : // (CSS not tested yet.)
3320 : //
3321 : #endif
3322 :
3323 : static int32_t sFontSizeFactors[8] = { 60,75,89,100,120,150,200,300 };
3324 :
3325 : static int32_t sCSSColumns[7] = {0, 1, 2, 3, 4, 5, 6}; // xxs...xxl
3326 : static int32_t sHTMLColumns[7] = {1, 2, 3, 4, 5, 6, 7}; // 1...7
3327 :
3328 : double dFontSize;
3329 :
3330 0 : if (aFontSizeType == eFontSize_HTML) {
3331 0 : aHTMLSize--; // input as 1-7
3332 : }
3333 :
3334 0 : if (aHTMLSize < 0)
3335 0 : aHTMLSize = 0;
3336 0 : else if (aHTMLSize > 6)
3337 0 : aHTMLSize = 6;
3338 :
3339 : int32_t* column;
3340 0 : switch (aFontSizeType)
3341 : {
3342 0 : case eFontSize_HTML: column = sHTMLColumns; break;
3343 0 : case eFontSize_CSS: column = sCSSColumns; break;
3344 : }
3345 :
3346 : // Make special call specifically for fonts (needed PrintPreview)
3347 0 : int32_t fontSize = nsPresContext::AppUnitsToIntCSSPixels(aBasePointSize);
3348 :
3349 0 : if ((fontSize >= sFontSizeTableMin) && (fontSize <= sFontSizeTableMax))
3350 : {
3351 0 : int32_t row = fontSize - sFontSizeTableMin;
3352 :
3353 0 : if (aPresContext->CompatibilityMode() == eCompatibility_NavQuirks) {
3354 0 : dFontSize = nsPresContext::CSSPixelsToAppUnits(sQuirksFontSizeTable[row][column[aHTMLSize]]);
3355 : } else {
3356 0 : dFontSize = nsPresContext::CSSPixelsToAppUnits(sStrictFontSizeTable[row][column[aHTMLSize]]);
3357 0 : }
3358 : }
3359 : else
3360 : {
3361 0 : int32_t factor = sFontSizeFactors[column[aHTMLSize]];
3362 0 : dFontSize = (factor * aBasePointSize) / 100;
3363 : }
3364 :
3365 :
3366 0 : if (1.0 < dFontSize) {
3367 0 : return (nscoord)dFontSize;
3368 : }
3369 0 : return (nscoord)1;
3370 : }
3371 :
3372 : struct SetFontSizeCalcOps : public css::BasicCoordCalcOps,
3373 : public css::FloatCoeffsAlreadyNormalizedOps
3374 : {
3375 : // Declare that we have floats as coefficients so that we unambiguously
3376 : // resolve coeff_type (BasicCoordCalcOps and FloatCoeffsAlreadyNormalizedOps
3377 : // both have |typedef float coeff_type|).
3378 : typedef float coeff_type;
3379 :
3380 : // The parameters beyond aValue that we need for CalcLengthWith.
3381 : const nscoord mParentSize;
3382 : const nsStyleFont* const mParentFont;
3383 : nsPresContext* const mPresContext;
3384 : GeckoStyleContext* const mStyleContext;
3385 : const bool mAtRoot;
3386 : RuleNodeCacheConditions& mConditions;
3387 :
3388 0 : SetFontSizeCalcOps(nscoord aParentSize, const nsStyleFont* aParentFont,
3389 : nsPresContext* aPresContext,
3390 : GeckoStyleContext* aStyleContext,
3391 : bool aAtRoot,
3392 : RuleNodeCacheConditions& aConditions)
3393 0 : : mParentSize(aParentSize),
3394 : mParentFont(aParentFont),
3395 : mPresContext(aPresContext),
3396 : mStyleContext(aStyleContext),
3397 : mAtRoot(aAtRoot),
3398 0 : mConditions(aConditions)
3399 : {
3400 0 : }
3401 :
3402 0 : result_type ComputeLeafValue(const nsCSSValue& aValue)
3403 : {
3404 : nscoord size;
3405 0 : if (aValue.IsLengthUnit()) {
3406 : // Note that font-based length units use the parent's size
3407 : // unadjusted for scriptlevel changes. A scriptlevel change
3408 : // between us and the parent is simply ignored.
3409 0 : size = CalcLengthWith(aValue, mParentSize,
3410 0 : mParentFont,
3411 0 : mStyleContext, mPresContext, mAtRoot,
3412 0 : true, mConditions);
3413 0 : if (!aValue.IsRelativeLengthUnit() && mParentFont->mAllowZoom) {
3414 0 : size = nsStyleFont::ZoomText(mPresContext, size);
3415 : }
3416 : }
3417 0 : else if (eCSSUnit_Percent == aValue.GetUnit()) {
3418 0 : mConditions.SetUncacheable();
3419 : // Note that % units use the parent's size unadjusted for scriptlevel
3420 : // changes. A scriptlevel change between us and the parent is simply
3421 : // ignored.
3422 : // aValue.GetPercentValue() may be negative for, e.g., calc(-50%)
3423 0 : size = NSCoordSaturatingMultiply(mParentSize, aValue.GetPercentValue());
3424 : } else {
3425 0 : MOZ_ASSERT(false, "unexpected value");
3426 : size = mParentSize;
3427 : }
3428 :
3429 0 : return size;
3430 : }
3431 : };
3432 :
3433 : /* static */ void
3434 12 : nsRuleNode::SetFontSize(nsPresContext* aPresContext,
3435 : GeckoStyleContext* aContext,
3436 : const nsRuleData* aRuleData,
3437 : const nsStyleFont* aFont,
3438 : const nsStyleFont* aParentFont,
3439 : nscoord* aSize,
3440 : const nsFont& aSystemFont,
3441 : nscoord aParentSize,
3442 : nscoord aScriptLevelAdjustedParentSize,
3443 : bool aUsedStartStruct,
3444 : bool aAtRoot,
3445 : RuleNodeCacheConditions& aConditions)
3446 : {
3447 : // If false, means that *aSize has not been zoomed. If true, means that
3448 : // *aSize has been zoomed iff aParentFont->mAllowZoom is true.
3449 12 : bool sizeIsZoomedAccordingToParent = false;
3450 :
3451 : int32_t baseSize = (int32_t) aPresContext->
3452 12 : GetDefaultFont(aFont->mGenericID, aFont->mLanguage)->size;
3453 12 : const nsCSSValue* sizeValue = aRuleData->ValueForFontSize();
3454 12 : if (eCSSUnit_Enumerated == sizeValue->GetUnit()) {
3455 0 : int32_t value = sizeValue->GetIntValue();
3456 :
3457 0 : if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) &&
3458 : (value <= NS_STYLE_FONT_SIZE_XXLARGE)) {
3459 0 : *aSize = CalcFontPointSize(value, baseSize,
3460 0 : aPresContext, eFontSize_CSS);
3461 : }
3462 0 : else if (NS_STYLE_FONT_SIZE_XXXLARGE == value) {
3463 : // <font size="7"> is not specified in CSS, so we don't use eFontSize_CSS.
3464 0 : *aSize = CalcFontPointSize(value, baseSize, aPresContext);
3465 : }
3466 0 : else if (NS_STYLE_FONT_SIZE_LARGER == value ||
3467 : NS_STYLE_FONT_SIZE_SMALLER == value) {
3468 0 : aConditions.SetUncacheable();
3469 :
3470 : // Un-zoom so we use the tables correctly. We'll then rezoom due
3471 : // to the |zoom = true| above.
3472 : // Note that relative units here use the parent's size unadjusted
3473 : // for scriptlevel changes. A scriptlevel change between us and the parent
3474 : // is simply ignored.
3475 0 : nscoord parentSize = aParentSize;
3476 0 : if (aParentFont->mAllowZoom) {
3477 0 : parentSize = nsStyleFont::UnZoomText(aPresContext, parentSize);
3478 : }
3479 :
3480 0 : float factor = (NS_STYLE_FONT_SIZE_LARGER == value) ? 1.2f : (1.0f / 1.2f);
3481 :
3482 0 : *aSize = parentSize * factor;
3483 :
3484 : } else {
3485 0 : NS_NOTREACHED("unexpected value");
3486 : }
3487 : }
3488 36 : else if (sizeValue->IsLengthUnit() ||
3489 24 : sizeValue->GetUnit() == eCSSUnit_Percent ||
3490 12 : sizeValue->IsCalcUnit()) {
3491 : SetFontSizeCalcOps ops(aParentSize, aParentFont,
3492 : aPresContext, aContext,
3493 : aAtRoot,
3494 0 : aConditions);
3495 0 : *aSize = css::ComputeCalc(*sizeValue, ops);
3496 0 : if (*aSize < 0) {
3497 0 : MOZ_ASSERT(sizeValue->IsCalcUnit(),
3498 : "negative lengths and percents should be rejected by parser");
3499 0 : *aSize = 0;
3500 : }
3501 : // The calc ops will always zoom its result according to the value
3502 : // of aParentFont->mAllowZoom.
3503 0 : sizeIsZoomedAccordingToParent = true;
3504 : }
3505 12 : else if (eCSSUnit_System_Font == sizeValue->GetUnit()) {
3506 : // this becomes our cascading size
3507 6 : *aSize = aSystemFont.size;
3508 : }
3509 6 : else if (eCSSUnit_Inherit == sizeValue->GetUnit() ||
3510 0 : eCSSUnit_Unset == sizeValue->GetUnit()) {
3511 6 : aConditions.SetUncacheable();
3512 : // We apply scriptlevel change for this case, because the default is
3513 : // to inherit and we don't want explicit "inherit" to differ from the
3514 : // default.
3515 6 : *aSize = aScriptLevelAdjustedParentSize;
3516 6 : sizeIsZoomedAccordingToParent = true;
3517 : }
3518 0 : else if (eCSSUnit_Initial == sizeValue->GetUnit()) {
3519 : // The initial value is 'medium', which has magical sizing based on
3520 : // the generic font family, so do that here too.
3521 0 : *aSize = baseSize;
3522 : } else {
3523 0 : NS_ASSERTION(eCSSUnit_Null == sizeValue->GetUnit(),
3524 : "What kind of font-size value is this?");
3525 : // if aUsedStartStruct is true, then every single property in the
3526 : // font struct is being set all at once. This means scriptlevel is not
3527 : // going to have any influence on the font size; there is no need to
3528 : // do anything here.
3529 0 : if (!aUsedStartStruct && aParentSize != aScriptLevelAdjustedParentSize) {
3530 : // There was no rule affecting the size but the size has been
3531 : // affected by the parent's size via scriptlevel change. So we cannot
3532 : // store the data in the rule tree.
3533 0 : aConditions.SetUncacheable();
3534 0 : *aSize = aScriptLevelAdjustedParentSize;
3535 0 : sizeIsZoomedAccordingToParent = true;
3536 : } else {
3537 0 : return;
3538 : }
3539 : }
3540 :
3541 : // We want to zoom the cascaded size so that em-based measurements,
3542 : // line-heights, etc., work.
3543 18 : bool currentlyZoomed = sizeIsZoomedAccordingToParent &&
3544 18 : aParentFont->mAllowZoom;
3545 12 : if (!currentlyZoomed && aFont->mAllowZoom) {
3546 6 : *aSize = nsStyleFont::ZoomText(aPresContext, *aSize);
3547 6 : } else if (currentlyZoomed && !aFont->mAllowZoom) {
3548 0 : *aSize = nsStyleFont::UnZoomText(aPresContext, *aSize);
3549 : }
3550 : }
3551 :
3552 0 : static int8_t ClampTo8Bit(int32_t aValue) {
3553 0 : if (aValue < -128)
3554 0 : return -128;
3555 0 : if (aValue > 127)
3556 0 : return 127;
3557 0 : return int8_t(aValue);
3558 : }
3559 :
3560 : /* static */ void
3561 6 : nsRuleNode::ComputeSystemFont(nsFont* aSystemFont, LookAndFeel::FontID aFontID,
3562 : const nsPresContext* aPresContext,
3563 : const nsFont* aDefaultVariableFont)
3564 : {
3565 12 : gfxFontStyle fontStyle;
3566 : float devPerCSS =
3567 12 : (float)nsPresContext::AppUnitsPerCSSPixel() /
3568 12 : aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
3569 12 : nsAutoString systemFontName;
3570 6 : if (LookAndFeel::GetFont(aFontID, systemFontName, fontStyle, devPerCSS)) {
3571 6 : systemFontName.Trim("\"'");
3572 6 : aSystemFont->fontlist = FontFamilyList(systemFontName, eUnquotedName);
3573 6 : aSystemFont->fontlist.SetDefaultFontType(eFamily_none);
3574 6 : aSystemFont->style = fontStyle.style;
3575 6 : aSystemFont->systemFont = fontStyle.systemFont;
3576 6 : aSystemFont->weight = fontStyle.weight;
3577 6 : aSystemFont->stretch = fontStyle.stretch;
3578 6 : aSystemFont->size =
3579 6 : NSFloatPixelsToAppUnits(fontStyle.size,
3580 : aPresContext->DeviceContext()->
3581 6 : AppUnitsPerDevPixelAtUnitFullZoom());
3582 : //aSystemFont->langGroup = fontStyle.langGroup;
3583 6 : aSystemFont->sizeAdjust = fontStyle.sizeAdjust;
3584 :
3585 : #ifdef XP_WIN
3586 : // XXXldb This platform-specific stuff should be in the
3587 : // LookAndFeel implementation, not here.
3588 : // XXXzw Should we even still *have* this code? It looks to be making
3589 : // old, probably obsolete assumptions.
3590 :
3591 : if (aFontID == LookAndFeel::eFont_Field ||
3592 : aFontID == LookAndFeel::eFont_Button ||
3593 : aFontID == LookAndFeel::eFont_List) {
3594 : // As far as I can tell the system default fonts and sizes
3595 : // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
3596 : // all pre-determined and cannot be changed by either the control panel
3597 : // or programmatically.
3598 : // Fields (text fields)
3599 : // Button and Selects (listboxes/comboboxes)
3600 : // We use whatever font is defined by the system. Which it appears
3601 : // (and the assumption is) it is always a proportional font. Then we
3602 : // always use 2 points smaller than what the browser has defined as
3603 : // the default proportional font.
3604 : // Assumption: system defined font is proportional
3605 : aSystemFont->size =
3606 : std::max(aDefaultVariableFont->size -
3607 : nsPresContext::CSSPointsToAppUnits(2), 0);
3608 : }
3609 : #endif
3610 : }
3611 6 : }
3612 :
3613 : /* static */ void
3614 12 : nsRuleNode::SetFont(nsPresContext* aPresContext, GeckoStyleContext* aContext,
3615 : uint8_t aGenericFontID, const nsRuleData* aRuleData,
3616 : const nsStyleFont* aParentFont,
3617 : nsStyleFont* aFont, bool aUsedStartStruct,
3618 : RuleNodeCacheConditions& aConditions)
3619 : {
3620 12 : bool atRoot = !aContext->GetParent();
3621 :
3622 : // -x-text-zoom: none, inherit, initial
3623 : bool allowZoom;
3624 12 : const nsCSSValue* textZoomValue = aRuleData->ValueForTextZoom();
3625 12 : if (eCSSUnit_Null != textZoomValue->GetUnit()) {
3626 0 : if (eCSSUnit_Inherit == textZoomValue->GetUnit()) {
3627 0 : allowZoom = aParentFont->mAllowZoom;
3628 0 : } else if (eCSSUnit_None == textZoomValue->GetUnit()) {
3629 0 : allowZoom = false;
3630 : } else {
3631 0 : MOZ_ASSERT(eCSSUnit_Initial == textZoomValue->GetUnit(),
3632 : "unexpected unit");
3633 0 : allowZoom = true;
3634 : }
3635 0 : aFont->EnableZoom(aPresContext, allowZoom);
3636 : }
3637 :
3638 : // mLanguage must be set before before any of the CalcLengthWith calls
3639 : // (direct calls or calls via SetFontSize) for the cases where |aParentFont|
3640 : // is the same as |aFont|.
3641 : //
3642 : // -x-lang: string, inherit
3643 : // This is not a real CSS property, it is an HTML attribute mapped to CSS.
3644 12 : const nsCSSValue* langValue = aRuleData->ValueForLang();
3645 12 : if (eCSSUnit_AtomIdent == langValue->GetUnit()) {
3646 0 : aFont->mLanguage = langValue->GetAtomValue();
3647 0 : aFont->mExplicitLanguage = true;
3648 : }
3649 :
3650 : const nsFont* defaultVariableFont =
3651 12 : aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
3652 12 : aFont->mLanguage);
3653 :
3654 : // -moz-system-font: enum (never inherit!)
3655 : static_assert(
3656 : NS_STYLE_FONT_CAPTION == LookAndFeel::eFont_Caption &&
3657 : NS_STYLE_FONT_ICON == LookAndFeel::eFont_Icon &&
3658 : NS_STYLE_FONT_MENU == LookAndFeel::eFont_Menu &&
3659 : NS_STYLE_FONT_MESSAGE_BOX == LookAndFeel::eFont_MessageBox &&
3660 : NS_STYLE_FONT_SMALL_CAPTION == LookAndFeel::eFont_SmallCaption &&
3661 : NS_STYLE_FONT_STATUS_BAR == LookAndFeel::eFont_StatusBar &&
3662 : NS_STYLE_FONT_WINDOW == LookAndFeel::eFont_Window &&
3663 : NS_STYLE_FONT_DOCUMENT == LookAndFeel::eFont_Document &&
3664 : NS_STYLE_FONT_WORKSPACE == LookAndFeel::eFont_Workspace &&
3665 : NS_STYLE_FONT_DESKTOP == LookAndFeel::eFont_Desktop &&
3666 : NS_STYLE_FONT_INFO == LookAndFeel::eFont_Info &&
3667 : NS_STYLE_FONT_DIALOG == LookAndFeel::eFont_Dialog &&
3668 : NS_STYLE_FONT_BUTTON == LookAndFeel::eFont_Button &&
3669 : NS_STYLE_FONT_PULL_DOWN_MENU == LookAndFeel::eFont_PullDownMenu &&
3670 : NS_STYLE_FONT_LIST == LookAndFeel::eFont_List &&
3671 : NS_STYLE_FONT_FIELD == LookAndFeel::eFont_Field,
3672 : "LookAndFeel.h system-font constants out of sync with nsStyleConsts.h");
3673 :
3674 : // Fall back to defaultVariableFont.
3675 24 : nsFont systemFont = *defaultVariableFont;
3676 12 : const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
3677 12 : if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
3678 : LookAndFeel::FontID fontID =
3679 6 : (LookAndFeel::FontID)systemFontValue->GetIntValue();
3680 6 : ComputeSystemFont(&systemFont, fontID, aPresContext, defaultVariableFont);
3681 : }
3682 :
3683 : // font-family: font family list, enum, inherit
3684 12 : const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
3685 12 : NS_ASSERTION(eCSSUnit_Enumerated != familyValue->GetUnit(),
3686 : "system fonts should not be in mFamily anymore");
3687 12 : if (eCSSUnit_FontFamilyList == familyValue->GetUnit()) {
3688 : // set the correct font if we are using DocumentFonts OR we are overriding for XUL
3689 : // MJA: bug 31816
3690 0 : nsRuleNode::FixupNoneGeneric(&aFont->mFont, aPresContext,
3691 0 : aGenericFontID, defaultVariableFont);
3692 :
3693 0 : aFont->mFont.systemFont = false;
3694 : // Technically this is redundant with the code below, but it's good
3695 : // to have since we'll still want it once we get rid of
3696 : // SetGenericFont (bug 380915).
3697 0 : aFont->mGenericID = aGenericFontID;
3698 : }
3699 12 : else if (eCSSUnit_System_Font == familyValue->GetUnit()) {
3700 6 : aFont->mFont.fontlist = systemFont.fontlist;
3701 6 : aFont->mFont.systemFont = true;
3702 6 : aFont->mGenericID = kGenericFont_NONE;
3703 : }
3704 6 : else if (eCSSUnit_Inherit == familyValue->GetUnit() ||
3705 0 : eCSSUnit_Unset == familyValue->GetUnit()) {
3706 6 : aConditions.SetUncacheable();
3707 6 : aFont->mFont.fontlist = aParentFont->mFont.fontlist;
3708 6 : aFont->mFont.systemFont = aParentFont->mFont.systemFont;
3709 6 : aFont->mGenericID = aParentFont->mGenericID;
3710 : }
3711 0 : else if (eCSSUnit_Initial == familyValue->GetUnit()) {
3712 0 : aFont->mFont.fontlist = defaultVariableFont->fontlist;
3713 0 : aFont->mFont.systemFont = defaultVariableFont->systemFont;
3714 0 : aFont->mGenericID = kGenericFont_NONE;
3715 : }
3716 :
3717 : // When we're in the loop in SetGenericFont, we must ensure that we
3718 : // always keep aFont->mFlags set to the correct generic. But we have
3719 : // to be careful not to touch it when we're called directly from
3720 : // ComputeFontData, because we could have a start struct.
3721 12 : if (aGenericFontID != kGenericFont_NONE) {
3722 0 : aFont->mGenericID = aGenericFontID;
3723 : }
3724 :
3725 : // -moz-math-variant: enum, inherit, initial
3726 12 : SetValue(*aRuleData->ValueForMathVariant(), aFont->mMathVariant,
3727 : aConditions,
3728 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
3729 24 : aParentFont->mMathVariant, NS_MATHML_MATHVARIANT_NONE);
3730 :
3731 : // -moz-math-display: enum, inherit, initial
3732 12 : SetValue(*aRuleData->ValueForMathDisplay(), aFont->mMathDisplay,
3733 : aConditions,
3734 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
3735 24 : aParentFont->mMathDisplay, NS_MATHML_DISPLAYSTYLE_INLINE);
3736 :
3737 : // font-smoothing: enum, inherit, initial
3738 24 : SetValue(*aRuleData->ValueForOsxFontSmoothing(),
3739 : aFont->mFont.smoothing, aConditions,
3740 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
3741 12 : aParentFont->mFont.smoothing,
3742 24 : defaultVariableFont->smoothing);
3743 :
3744 : // font-style: enum, inherit, initial, -moz-system-font
3745 12 : if (aFont->mMathVariant != NS_MATHML_MATHVARIANT_NONE) {
3746 : // -moz-math-variant overrides font-style
3747 0 : aFont->mFont.style = NS_FONT_STYLE_NORMAL;
3748 : } else {
3749 36 : SetValue(*aRuleData->ValueForFontStyle(),
3750 : aFont->mFont.style, aConditions,
3751 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
3752 12 : aParentFont->mFont.style,
3753 12 : defaultVariableFont->style,
3754 24 : Unused, Unused, Unused, systemFont.style);
3755 : }
3756 :
3757 : // font-weight: int, enum, inherit, initial, -moz-system-font
3758 : // special handling for enum
3759 12 : const nsCSSValue* weightValue = aRuleData->ValueForFontWeight();
3760 12 : if (aFont->mMathVariant != NS_MATHML_MATHVARIANT_NONE) {
3761 : // -moz-math-variant overrides font-weight
3762 0 : aFont->mFont.weight = NS_FONT_WEIGHT_NORMAL;
3763 12 : } else if (eCSSUnit_Enumerated == weightValue->GetUnit()) {
3764 0 : int32_t value = weightValue->GetIntValue();
3765 0 : switch (value) {
3766 : case NS_STYLE_FONT_WEIGHT_NORMAL:
3767 : case NS_STYLE_FONT_WEIGHT_BOLD:
3768 0 : aFont->mFont.weight = value;
3769 0 : break;
3770 : case NS_STYLE_FONT_WEIGHT_BOLDER: {
3771 0 : aConditions.SetUncacheable();
3772 0 : int32_t inheritedValue = aParentFont->mFont.weight;
3773 0 : if (inheritedValue <= 300) {
3774 0 : aFont->mFont.weight = 400;
3775 0 : } else if (inheritedValue <= 500) {
3776 0 : aFont->mFont.weight = 700;
3777 : } else {
3778 0 : aFont->mFont.weight = 900;
3779 : }
3780 0 : break;
3781 : }
3782 : case NS_STYLE_FONT_WEIGHT_LIGHTER: {
3783 0 : aConditions.SetUncacheable();
3784 0 : int32_t inheritedValue = aParentFont->mFont.weight;
3785 0 : if (inheritedValue < 600) {
3786 0 : aFont->mFont.weight = 100;
3787 0 : } else if (inheritedValue < 800) {
3788 0 : aFont->mFont.weight = 400;
3789 : } else {
3790 0 : aFont->mFont.weight = 700;
3791 : }
3792 0 : break;
3793 : }
3794 : }
3795 : } else
3796 36 : SetValue(*weightValue, aFont->mFont.weight, aConditions,
3797 : SETVAL_INTEGER | SETVAL_UNSET_INHERIT,
3798 12 : aParentFont->mFont.weight,
3799 12 : defaultVariableFont->weight,
3800 24 : Unused, Unused, Unused, systemFont.weight);
3801 :
3802 : // font-stretch: enum, inherit, initial, -moz-system-font
3803 36 : SetValue(*aRuleData->ValueForFontStretch(),
3804 : aFont->mFont.stretch, aConditions,
3805 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
3806 12 : aParentFont->mFont.stretch,
3807 12 : defaultVariableFont->stretch,
3808 24 : Unused, Unused, Unused, systemFont.stretch);
3809 :
3810 : // Compute scriptlevel, scriptminsize and scriptsizemultiplier now so
3811 : // they're available for font-size computation.
3812 :
3813 : // -moz-script-min-size: length
3814 12 : const nsCSSValue* scriptMinSizeValue = aRuleData->ValueForScriptMinSize();
3815 12 : if (scriptMinSizeValue->IsLengthUnit()) {
3816 : // scriptminsize in font units (em, ex) has to be interpreted relative
3817 : // to the parent font, or the size definitions are circular and we
3818 : //
3819 0 : aFont->mScriptMinSize =
3820 0 : CalcLengthWith(*scriptMinSizeValue, aParentFont->mSize,
3821 : aParentFont,
3822 : aContext, aPresContext, atRoot, true /* aUseUserFontSet */,
3823 : aConditions);
3824 : }
3825 :
3826 : // -moz-script-size-multiplier: factor, inherit, initial
3827 12 : SetFactor(*aRuleData->ValueForScriptSizeMultiplier(),
3828 : aFont->mScriptSizeMultiplier,
3829 12 : aConditions, aParentFont->mScriptSizeMultiplier,
3830 : NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER,
3831 12 : SETFCT_POSITIVE | SETFCT_UNSET_INHERIT);
3832 :
3833 : // -moz-script-level: integer, number, inherit
3834 12 : const nsCSSValue* scriptLevelValue = aRuleData->ValueForScriptLevel();
3835 12 : if (eCSSUnit_Integer == scriptLevelValue->GetUnit()) {
3836 : // "relative"
3837 0 : aConditions.SetUncacheable();
3838 0 : aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel + scriptLevelValue->GetIntValue());
3839 : }
3840 12 : else if (eCSSUnit_Number == scriptLevelValue->GetUnit()) {
3841 : // "absolute"
3842 0 : aFont->mScriptLevel = ClampTo8Bit(int32_t(scriptLevelValue->GetFloatValue()));
3843 : }
3844 12 : else if (eCSSUnit_Auto == scriptLevelValue->GetUnit()) {
3845 : // auto
3846 0 : aConditions.SetUncacheable();
3847 0 : aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel +
3848 0 : (aParentFont->mMathDisplay ==
3849 0 : NS_MATHML_DISPLAYSTYLE_INLINE ? 1 : 0));
3850 : }
3851 24 : else if (eCSSUnit_Inherit == scriptLevelValue->GetUnit() ||
3852 12 : eCSSUnit_Unset == scriptLevelValue->GetUnit()) {
3853 0 : aConditions.SetUncacheable();
3854 0 : aFont->mScriptLevel = aParentFont->mScriptLevel;
3855 : }
3856 12 : else if (eCSSUnit_Initial == scriptLevelValue->GetUnit()) {
3857 0 : aFont->mScriptLevel = 0;
3858 : }
3859 :
3860 : // font-kerning: none, enum, inherit, initial, -moz-system-font
3861 36 : SetValue(*aRuleData->ValueForFontKerning(),
3862 : aFont->mFont.kerning, aConditions,
3863 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
3864 12 : aParentFont->mFont.kerning,
3865 12 : defaultVariableFont->kerning,
3866 24 : Unused, Unused, Unused, systemFont.kerning);
3867 :
3868 : // font-synthesis: none, enum (bit field), inherit, initial
3869 24 : SetValue(*aRuleData->ValueForFontSynthesis(),
3870 : aFont->mFont.synthesis, aConditions,
3871 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
3872 12 : aParentFont->mFont.synthesis,
3873 12 : defaultVariableFont->synthesis,
3874 12 : Unused, /* none */ 0, Unused, Unused);
3875 :
3876 : // font-variant-alternates: normal, enum (bit field) + functions, inherit,
3877 : // initial, -moz-system-font
3878 : const nsCSSValue* variantAlternatesValue =
3879 12 : aRuleData->ValueForFontVariantAlternates();
3880 12 : int32_t variantAlternates = 0;
3881 :
3882 12 : switch (variantAlternatesValue->GetUnit()) {
3883 : case eCSSUnit_Inherit:
3884 : case eCSSUnit_Unset:
3885 6 : aFont->mFont.CopyAlternates(aParentFont->mFont);
3886 6 : aConditions.SetUncacheable();
3887 6 : break;
3888 :
3889 : case eCSSUnit_Initial:
3890 : case eCSSUnit_Normal:
3891 0 : aFont->mFont.variantAlternates = 0;
3892 0 : aFont->mFont.alternateValues.Clear();
3893 0 : aFont->mFont.featureValueLookup = nullptr;
3894 0 : break;
3895 :
3896 : case eCSSUnit_Pair:
3897 0 : NS_ASSERTION(variantAlternatesValue->GetPairValue().mXValue.GetUnit() ==
3898 : eCSSUnit_Enumerated, "strange unit for variantAlternates");
3899 : variantAlternates =
3900 0 : variantAlternatesValue->GetPairValue().mXValue.GetIntValue();
3901 0 : aFont->mFont.variantAlternates = variantAlternates;
3902 :
3903 0 : if (variantAlternates & NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK) {
3904 : // fetch the feature lookup object from the styleset
3905 0 : MOZ_ASSERT(aPresContext->StyleSet()->IsGecko(),
3906 : "ServoStyleSets should not have rule nodes");
3907 : aFont->mFont.featureValueLookup =
3908 0 : aPresContext->StyleSet()->AsGecko()->GetFontFeatureValuesLookup();
3909 :
3910 0 : NS_ASSERTION(variantAlternatesValue->GetPairValue().mYValue.GetUnit() ==
3911 : eCSSUnit_List, "function list not a list value");
3912 0 : nsStyleUtil::ComputeFunctionalAlternates(
3913 0 : variantAlternatesValue->GetPairValue().mYValue.GetListValue(),
3914 0 : aFont->mFont.alternateValues);
3915 : }
3916 0 : break;
3917 :
3918 : default:
3919 6 : break;
3920 : }
3921 :
3922 : // font-variant-caps: normal, enum, inherit, initial, -moz-system-font
3923 36 : SetValue(*aRuleData->ValueForFontVariantCaps(),
3924 : aFont->mFont.variantCaps, aConditions,
3925 : SETVAL_ENUMERATED |SETVAL_UNSET_INHERIT,
3926 12 : aParentFont->mFont.variantCaps,
3927 12 : defaultVariableFont->variantCaps,
3928 24 : Unused, Unused, /* normal */ 0, systemFont.variantCaps);
3929 :
3930 : // font-variant-east-asian: normal, enum (bit field), inherit, initial,
3931 : // -moz-system-font
3932 36 : SetValue(*aRuleData->ValueForFontVariantEastAsian(),
3933 : aFont->mFont.variantEastAsian, aConditions,
3934 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
3935 12 : aParentFont->mFont.variantEastAsian,
3936 12 : defaultVariableFont->variantEastAsian,
3937 24 : Unused, Unused, /* normal */ 0, systemFont.variantEastAsian);
3938 :
3939 : // font-variant-ligatures: normal, none, enum (bit field), inherit, initial,
3940 : // -moz-system-font
3941 36 : SetValue(*aRuleData->ValueForFontVariantLigatures(),
3942 : aFont->mFont.variantLigatures, aConditions,
3943 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
3944 12 : aParentFont->mFont.variantLigatures,
3945 12 : defaultVariableFont->variantLigatures,
3946 : Unused, NS_FONT_VARIANT_LIGATURES_NONE, /* normal */ 0,
3947 24 : systemFont.variantLigatures);
3948 :
3949 : // font-variant-numeric: normal, enum (bit field), inherit, initial,
3950 : // -moz-system-font
3951 36 : SetValue(*aRuleData->ValueForFontVariantNumeric(),
3952 : aFont->mFont.variantNumeric, aConditions,
3953 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
3954 12 : aParentFont->mFont.variantNumeric,
3955 12 : defaultVariableFont->variantNumeric,
3956 24 : Unused, Unused, /* normal */ 0, systemFont.variantNumeric);
3957 :
3958 : // font-variant-position: normal, enum, inherit, initial,
3959 : // -moz-system-font
3960 36 : SetValue(*aRuleData->ValueForFontVariantPosition(),
3961 : aFont->mFont.variantPosition, aConditions,
3962 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
3963 12 : aParentFont->mFont.variantPosition,
3964 12 : defaultVariableFont->variantPosition,
3965 24 : Unused, Unused, /* normal */ 0, systemFont.variantPosition);
3966 :
3967 : // font-feature-settings
3968 : const nsCSSValue* featureSettingsValue =
3969 12 : aRuleData->ValueForFontFeatureSettings();
3970 :
3971 12 : switch (featureSettingsValue->GetUnit()) {
3972 : case eCSSUnit_Null:
3973 0 : break;
3974 :
3975 : case eCSSUnit_Normal:
3976 : case eCSSUnit_Initial:
3977 0 : aFont->mFont.fontFeatureSettings.Clear();
3978 0 : break;
3979 :
3980 : case eCSSUnit_Inherit:
3981 : case eCSSUnit_Unset:
3982 6 : aConditions.SetUncacheable();
3983 6 : aFont->mFont.fontFeatureSettings = aParentFont->mFont.fontFeatureSettings;
3984 6 : break;
3985 :
3986 : case eCSSUnit_System_Font:
3987 6 : aFont->mFont.fontFeatureSettings = systemFont.fontFeatureSettings;
3988 6 : break;
3989 :
3990 : case eCSSUnit_PairList:
3991 : case eCSSUnit_PairListDep:
3992 0 : ComputeFontFeatures(featureSettingsValue->GetPairListValue(),
3993 0 : aFont->mFont.fontFeatureSettings);
3994 0 : break;
3995 :
3996 : default:
3997 0 : MOZ_ASSERT(false, "unexpected value unit");
3998 : break;
3999 : }
4000 :
4001 : // font-variation-settings
4002 : const nsCSSValue* variationSettingsValue =
4003 12 : aRuleData->ValueForFontVariationSettings();
4004 :
4005 12 : switch (variationSettingsValue->GetUnit()) {
4006 : case eCSSUnit_Null:
4007 12 : break;
4008 :
4009 : case eCSSUnit_Normal:
4010 : case eCSSUnit_Initial:
4011 0 : aFont->mFont.fontVariationSettings.Clear();
4012 0 : break;
4013 :
4014 : case eCSSUnit_Inherit:
4015 : case eCSSUnit_Unset:
4016 0 : aConditions.SetUncacheable();
4017 : aFont->mFont.fontVariationSettings =
4018 0 : aParentFont->mFont.fontVariationSettings;
4019 0 : break;
4020 :
4021 : case eCSSUnit_System_Font:
4022 0 : aFont->mFont.fontVariationSettings = systemFont.fontVariationSettings;
4023 0 : break;
4024 :
4025 : case eCSSUnit_PairList:
4026 : case eCSSUnit_PairListDep:
4027 0 : ComputeFontVariations(variationSettingsValue->GetPairListValue(),
4028 0 : aFont->mFont.fontVariationSettings);
4029 0 : break;
4030 :
4031 : default:
4032 0 : MOZ_ASSERT(false, "unexpected value unit");
4033 : break;
4034 : }
4035 :
4036 : // font-language-override
4037 : const nsCSSValue* languageOverrideValue =
4038 12 : aRuleData->ValueForFontLanguageOverride();
4039 18 : if (eCSSUnit_Inherit == languageOverrideValue->GetUnit() ||
4040 6 : eCSSUnit_Unset == languageOverrideValue->GetUnit()) {
4041 6 : aConditions.SetUncacheable();
4042 6 : aFont->mFont.languageOverride = aParentFont->mFont.languageOverride;
4043 12 : } else if (eCSSUnit_Normal == languageOverrideValue->GetUnit() ||
4044 6 : eCSSUnit_Initial == languageOverrideValue->GetUnit()) {
4045 0 : aFont->mFont.languageOverride = NO_FONT_LANGUAGE_OVERRIDE;
4046 6 : } else if (eCSSUnit_System_Font == languageOverrideValue->GetUnit()) {
4047 6 : aFont->mFont.languageOverride = systemFont.languageOverride;
4048 0 : } else if (eCSSUnit_String == languageOverrideValue->GetUnit()) {
4049 0 : nsAutoString lang;
4050 0 : languageOverrideValue->GetStringValue(lang);
4051 0 : aFont->mFont.languageOverride = ParseFontLanguageOverride(lang);
4052 : }
4053 :
4054 : // -moz-min-font-size-ratio: percent, inherit
4055 12 : const nsCSSValue* minFontSizeRatio = aRuleData->ValueForMinFontSizeRatio();
4056 12 : switch (minFontSizeRatio->GetUnit()) {
4057 : case eCSSUnit_Null:
4058 12 : break;
4059 : case eCSSUnit_Unset:
4060 : case eCSSUnit_Inherit:
4061 0 : aFont->mMinFontSizeRatio = aParentFont->mMinFontSizeRatio;
4062 0 : aConditions.SetUncacheable();
4063 0 : break;
4064 : case eCSSUnit_Initial:
4065 0 : aFont->mMinFontSizeRatio = 100; // 100%
4066 0 : break;
4067 : case eCSSUnit_Percent: {
4068 : // While percentages are parsed as floating point numbers, we
4069 : // only store an integer in the range [0, 255] since that's all
4070 : // we need for now.
4071 0 : float percent = minFontSizeRatio->GetPercentValue() * 100;
4072 0 : if (percent < 0) {
4073 0 : percent = 0;
4074 0 : } else if (percent > 255) {
4075 0 : percent = 255;
4076 : }
4077 0 : aFont->mMinFontSizeRatio = uint8_t(percent);
4078 0 : break;
4079 : }
4080 : default:
4081 0 : MOZ_ASSERT_UNREACHABLE("Unknown unit for -moz-min-font-size-ratio");
4082 : }
4083 :
4084 : nscoord scriptLevelAdjustedUnconstrainedParentSize;
4085 :
4086 : // font-size: enum, length, percent, inherit
4087 : nscoord scriptLevelAdjustedParentSize =
4088 : ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
4089 12 : &scriptLevelAdjustedUnconstrainedParentSize);
4090 12 : NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
4091 : "If we have a start struct, we should have reset everything coming in here");
4092 :
4093 : // Compute whether we're affected by scriptMinSize *before* calling
4094 : // SetFontSize, since aParentFont might be the same as aFont. If it
4095 : // is, calling SetFontSize might throw off our calculation.
4096 : bool affectedByScriptMinSize =
4097 24 : aParentFont->mSize != aParentFont->mScriptUnconstrainedSize ||
4098 12 : scriptLevelAdjustedParentSize !=
4099 12 : scriptLevelAdjustedUnconstrainedParentSize;
4100 :
4101 24 : SetFontSize(aPresContext, aContext,
4102 : aRuleData, aFont, aParentFont,
4103 : &aFont->mSize,
4104 12 : systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
4105 12 : aUsedStartStruct, atRoot, aConditions);
4106 12 : if (!aPresContext->Document()->GetMathMLEnabled()) {
4107 12 : MOZ_ASSERT(!affectedByScriptMinSize);
4108 : // If MathML is not enabled, we don't need to mark this node as
4109 : // uncacheable. If it becomes enabled, code in
4110 : // nsMathMLElementFactory will rebuild the rule tree and style data
4111 : // when MathML is first enabled (see nsMathMLElement::BindToTree).
4112 12 : aFont->mScriptUnconstrainedSize = aFont->mSize;
4113 0 : } else if (!affectedByScriptMinSize) {
4114 : // Fast path: we have not been affected by scriptminsize so we don't
4115 : // need to call SetFontSize again to compute the
4116 : // scriptminsize-unconstrained size. This is OK even if we have a
4117 : // start struct, because if we have a start struct then 'font-size'
4118 : // was specified and so scriptminsize has no effect.
4119 0 : aFont->mScriptUnconstrainedSize = aFont->mSize;
4120 : // It's possible we could, in the future, have a different parent,
4121 : // which would lead to a different affectedByScriptMinSize.
4122 0 : aConditions.SetUncacheable();
4123 : } else {
4124 : // see previous else-if
4125 0 : aConditions.SetUncacheable();
4126 :
4127 : // Use a separate conditions object because it might get a
4128 : // *different* font-size dependency. We can ignore it because we've
4129 : // already called SetUncacheable.
4130 0 : RuleNodeCacheConditions unconstrainedConditions;
4131 :
4132 0 : SetFontSize(aPresContext, aContext,
4133 : aRuleData, aFont, aParentFont,
4134 : &aFont->mScriptUnconstrainedSize,
4135 0 : systemFont, aParentFont->mScriptUnconstrainedSize,
4136 : scriptLevelAdjustedUnconstrainedParentSize,
4137 0 : aUsedStartStruct, atRoot, unconstrainedConditions);
4138 : }
4139 12 : NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
4140 : "scriptminsize should never be making things bigger");
4141 :
4142 12 : nsRuleNode::ApplyMinFontSize(aFont, aPresContext,
4143 12 : aPresContext->MinFontSize(aFont->mLanguage));
4144 :
4145 : // font-size-adjust: number, none, inherit, initial, -moz-system-font
4146 12 : const nsCSSValue* sizeAdjustValue = aRuleData->ValueForFontSizeAdjust();
4147 12 : if (eCSSUnit_System_Font == sizeAdjustValue->GetUnit()) {
4148 6 : aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
4149 : } else
4150 6 : SetFactor(*sizeAdjustValue, aFont->mFont.sizeAdjust,
4151 6 : aConditions, aParentFont->mFont.sizeAdjust, -1.0f,
4152 6 : SETFCT_NONE | SETFCT_UNSET_INHERIT);
4153 12 : }
4154 :
4155 : static inline void
4156 0 : AssertValidFontTag(const nsString& aString)
4157 : {
4158 : // To be valid as a font feature tag, a string MUST be:
4159 0 : MOZ_ASSERT(aString.Length() == 4 && // (1) exactly 4 chars long
4160 : NS_IsAscii(aString.BeginReading()) && // (2) entirely ASCII
4161 : isprint(aString[0]) && // (3) all printable chars
4162 : isprint(aString[1]) &&
4163 : isprint(aString[2]) &&
4164 : isprint(aString[3]));
4165 0 : }
4166 :
4167 : /* static */ void
4168 0 : nsRuleNode::ComputeFontFeatures(const nsCSSValuePairList *aFeaturesList,
4169 : nsTArray<gfxFontFeature>& aFeatureSettings)
4170 : {
4171 0 : aFeatureSettings.Clear();
4172 0 : for (const nsCSSValuePairList* p = aFeaturesList; p; p = p->mNext) {
4173 : gfxFontFeature feat;
4174 :
4175 0 : MOZ_ASSERT(aFeaturesList->mXValue.GetUnit() == eCSSUnit_String,
4176 : "unexpected value unit");
4177 :
4178 : // tag is a 4-byte ASCII sequence
4179 0 : nsAutoString tag;
4180 0 : p->mXValue.GetStringValue(tag);
4181 0 : AssertValidFontTag(tag);
4182 0 : if (tag.Length() != 4) {
4183 0 : continue;
4184 : }
4185 : // parsing validates that these are ASCII chars
4186 : // tags are always big-endian
4187 0 : feat.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8) | tag[3];
4188 :
4189 : // value
4190 0 : NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Integer,
4191 : "should have found an integer unit");
4192 0 : feat.mValue = p->mYValue.GetIntValue();
4193 :
4194 0 : aFeatureSettings.AppendElement(feat);
4195 : }
4196 0 : }
4197 :
4198 : /* static */ void
4199 0 : nsRuleNode::ComputeFontVariations(const nsCSSValuePairList* aVariationsList,
4200 : nsTArray<gfxFontVariation>& aVariationSettings)
4201 : {
4202 0 : aVariationSettings.Clear();
4203 0 : for (const nsCSSValuePairList* p = aVariationsList; p; p = p->mNext) {
4204 : gfxFontVariation var;
4205 :
4206 0 : MOZ_ASSERT(aVariationsList->mXValue.GetUnit() == eCSSUnit_String,
4207 : "unexpected value unit");
4208 :
4209 : // tag is a 4-byte ASCII sequence
4210 0 : nsAutoString tag;
4211 0 : p->mXValue.GetStringValue(tag);
4212 0 : AssertValidFontTag(tag);
4213 0 : if (tag.Length() != 4) {
4214 0 : continue;
4215 : }
4216 : // parsing validates that these are ASCII chars
4217 : // tags are always big-endian
4218 0 : var.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8) | tag[3];
4219 :
4220 : // value
4221 0 : NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Number,
4222 : "should have found a number unit");
4223 0 : var.mValue = p->mYValue.GetFloatValue();
4224 :
4225 0 : aVariationSettings.AppendElement(var);
4226 : }
4227 0 : }
4228 :
4229 : // This should die (bug 380915).
4230 : //
4231 : // SetGenericFont:
4232 : // - backtrack to an ancestor with the same generic font name (possibly
4233 : // up to the root where default values come from the presentation context)
4234 : // - re-apply cascading rules from there without caching intermediate values
4235 : /* static */ void
4236 0 : nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
4237 : GeckoStyleContext* aContext,
4238 : uint8_t aGenericFontID,
4239 : nsStyleFont* aFont)
4240 : {
4241 : // walk up the contexts until a context with the desired generic font
4242 0 : AutoTArray<GeckoStyleContext*, 8> contextPath;
4243 0 : contextPath.AppendElement(aContext);
4244 0 : GeckoStyleContext* higherContext = aContext->GetParent();
4245 0 : while (higherContext) {
4246 0 : if (higherContext->StyleFont()->mGenericID == aGenericFontID) {
4247 : // done walking up the higher contexts
4248 0 : break;
4249 : }
4250 0 : contextPath.AppendElement(higherContext);
4251 0 : higherContext = higherContext->GetParent();
4252 : }
4253 :
4254 : // re-apply the cascading rules, starting from the higher context
4255 :
4256 : // If we stopped earlier because we reached the root of the style tree,
4257 : // we will start with the default generic font from the presentation
4258 : // context. Otherwise we start with the higher context.
4259 : const nsFont* defaultFont =
4260 0 : aPresContext->GetDefaultFont(aGenericFontID, aFont->mLanguage);
4261 0 : nsStyleFont parentFont(*defaultFont, aPresContext);
4262 0 : if (higherContext) {
4263 0 : const nsStyleFont* tmpFont = higherContext->StyleFont();
4264 0 : parentFont = *tmpFont;
4265 : }
4266 0 : *aFont = parentFont;
4267 :
4268 0 : uint32_t fontBit = nsCachedStyleData::GetBitForSID(eStyleStruct_Font);
4269 :
4270 : // use placement new[] on the result of alloca() to allocate a
4271 : // variable-sized stack array, including execution of constructors,
4272 : // and use an RAII class to run the destructors too.
4273 0 : size_t nprops = nsCSSProps::PropertyCountInStruct(eStyleStruct_Font);
4274 0 : void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
4275 :
4276 0 : for (int32_t i = contextPath.Length() - 1; i >= 0; --i) {
4277 0 : GeckoStyleContext* context = contextPath[i];
4278 0 : AutoCSSValueArray dataArray(dataStorage, nprops);
4279 :
4280 : nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), dataArray.get(),
4281 0 : aPresContext, context);
4282 0 : ruleData.mValueOffsets[eStyleStruct_Font] = 0;
4283 :
4284 : // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
4285 : // Note that we *do* need to do this for our own data, since what is
4286 : // in |fontData| in ComputeFontData is only for the rules below
4287 : // aStartStruct.
4288 0 : for (nsRuleNode* ruleNode = context->RuleNode(); ruleNode;
4289 : ruleNode = ruleNode->GetParent()) {
4290 0 : if (ruleNode->mNoneBits & fontBit)
4291 : // no more font rules on this branch, get out
4292 0 : break;
4293 :
4294 0 : nsIStyleRule *rule = ruleNode->GetRule();
4295 0 : if (rule) {
4296 0 : ruleData.mLevel = ruleNode->GetLevel();
4297 0 : ruleData.mIsImportantRule = ruleNode->IsImportantRule();
4298 0 : rule->MapRuleInfoInto(&ruleData);
4299 : }
4300 : }
4301 :
4302 : // Compute the delta from the information that the rules specified
4303 :
4304 : // Avoid unnecessary operations in SetFont(). But we care if it's
4305 : // the final value that we're computing.
4306 0 : if (i != 0)
4307 0 : ruleData.ValueForFontFamily()->Reset();
4308 :
4309 0 : ResolveVariableReferences(eStyleStruct_Font, &ruleData, aContext);
4310 :
4311 0 : RuleNodeCacheConditions dummy;
4312 0 : nsRuleNode::SetFont(aPresContext, context,
4313 : aGenericFontID, &ruleData, &parentFont, aFont,
4314 0 : false, dummy);
4315 :
4316 0 : parentFont = *aFont;
4317 : }
4318 :
4319 0 : if (higherContext && contextPath.Length() > 1) {
4320 : // contextPath is a list of all ancestor style contexts, so it must have
4321 : // at least two elements for it to result in a dependency on grandancestor
4322 : // styles.
4323 0 : PropagateGrandancestorBit(aContext, higherContext);
4324 : }
4325 0 : }
4326 :
4327 : const void*
4328 12 : nsRuleNode::ComputeFontData(void* aStartStruct,
4329 : const nsRuleData* aRuleData,
4330 : GeckoStyleContext* aContext,
4331 : nsRuleNode* aHighestNode,
4332 : const RuleDetail aRuleDetail,
4333 : const RuleNodeCacheConditions aConditions)
4334 : {
4335 24 : COMPUTE_START_INHERITED(Font, font, parentFont)
4336 :
4337 : // NOTE: The |aRuleDetail| passed in is a little bit conservative due
4338 : // to the -moz-system-font property. We really don't need to consider
4339 : // it here in determining whether to cache in the rule tree. However,
4340 : // we do need to consider it in WalkRuleTree when deciding whether to
4341 : // walk further up the tree. So this means that when the font struct
4342 : // is fully specified using *longhand* properties (excluding
4343 : // -moz-system-font), we won't cache in the rule tree even though we
4344 : // could. However, it's pretty unlikely authors will do that
4345 : // (although there is a pretty good chance they'll fully specify it
4346 : // using the 'font' shorthand).
4347 :
4348 : // Figure out if we are a generic font
4349 12 : uint8_t generic = kGenericFont_NONE;
4350 : // XXXldb What if we would have had a string if we hadn't been doing
4351 : // the optimization with a non-null aStartStruct?
4352 12 : const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
4353 12 : if (eCSSUnit_FontFamilyList == familyValue->GetUnit()) {
4354 0 : const FontFamilyList* fontlist = familyValue->GetFontFamilyListValue();
4355 0 : FontFamilyList& fl = font->mFont.fontlist;
4356 0 : fl = *fontlist;
4357 :
4358 : // extract the first generic in the fontlist, if exists
4359 0 : FontFamilyType fontType = fontlist->FirstGeneric();
4360 :
4361 : // if only a single generic, set the generic type
4362 0 : if (fontlist->Length() == 1) {
4363 0 : switch (fontType) {
4364 : case eFamily_serif:
4365 0 : generic = kGenericFont_serif;
4366 0 : break;
4367 : case eFamily_sans_serif:
4368 0 : generic = kGenericFont_sans_serif;
4369 0 : break;
4370 : case eFamily_monospace:
4371 0 : generic = kGenericFont_monospace;
4372 0 : break;
4373 : case eFamily_cursive:
4374 0 : generic = kGenericFont_cursive;
4375 0 : break;
4376 : case eFamily_fantasy:
4377 0 : generic = kGenericFont_fantasy;
4378 0 : break;
4379 : case eFamily_moz_fixed:
4380 0 : generic = kGenericFont_moz_fixed;
4381 0 : break;
4382 : default:
4383 0 : break;
4384 : }
4385 : }
4386 : }
4387 :
4388 : // Now compute our font struct
4389 12 : if (generic == kGenericFont_NONE) {
4390 : // continue the normal processing
4391 12 : nsRuleNode::SetFont(mPresContext, aContext, generic,
4392 : aRuleData, parentFont, font,
4393 12 : aStartStruct != nullptr, conditions);
4394 : }
4395 : else {
4396 : // re-calculate the font as a generic font
4397 0 : conditions.SetUncacheable();
4398 0 : nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
4399 0 : font);
4400 : }
4401 :
4402 24 : COMPUTE_END_INHERITED(Font, font)
4403 : }
4404 :
4405 : /*static*/ uint32_t
4406 0 : nsRuleNode::ParseFontLanguageOverride(const nsAString& aLangTag)
4407 : {
4408 0 : if (!aLangTag.Length() || aLangTag.Length() > 4) {
4409 0 : return NO_FONT_LANGUAGE_OVERRIDE;
4410 : }
4411 0 : uint32_t index, result = 0;
4412 0 : for (index = 0; index < aLangTag.Length(); ++index) {
4413 0 : char16_t ch = aLangTag[index];
4414 0 : if (!nsCRT::IsAscii(ch)) { // valid tags are pure ASCII
4415 0 : return NO_FONT_LANGUAGE_OVERRIDE;
4416 : }
4417 0 : result = (result << 8) + ch;
4418 : }
4419 0 : while (index++ < 4) {
4420 0 : result = (result << 8) + 0x20;
4421 : }
4422 0 : return result;
4423 : }
4424 :
4425 : template <typename T>
4426 267 : inline uint32_t ListLength(const T* aList)
4427 : {
4428 267 : uint32_t len = 0;
4429 915 : while (aList) {
4430 324 : len++;
4431 324 : aList = aList->mNext;
4432 : }
4433 267 : return len;
4434 : }
4435 :
4436 : static already_AddRefed<nsCSSShadowArray>
4437 6 : GetShadowData(const nsCSSValueList* aList,
4438 : GeckoStyleContext* aContext,
4439 : bool aIsBoxShadow,
4440 : nsPresContext* aPresContext,
4441 : RuleNodeCacheConditions& aConditions)
4442 : {
4443 6 : uint32_t arrayLength = ListLength(aList);
4444 :
4445 6 : MOZ_ASSERT(arrayLength > 0,
4446 : "Non-null text-shadow list, yet we counted 0 items.");
4447 : RefPtr<nsCSSShadowArray> shadowList =
4448 12 : new(arrayLength) nsCSSShadowArray(arrayLength);
4449 :
4450 6 : if (!shadowList)
4451 0 : return nullptr;
4452 :
4453 12 : nsStyleCoord tempCoord;
4454 12 : DebugOnly<bool> unitOK;
4455 12 : for (nsCSSShadowItem* item = shadowList->ShadowAt(0);
4456 12 : aList;
4457 6 : aList = aList->mNext, ++item) {
4458 6 : MOZ_ASSERT(aList->mValue.GetUnit() == eCSSUnit_Array,
4459 : "expecting a plain array value");
4460 6 : nsCSSValue::Array *arr = aList->mValue.GetArrayValue();
4461 : // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
4462 12 : unitOK = SetCoord(arr->Item(0), tempCoord, nsStyleCoord(),
4463 : SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
4464 6 : aContext, aPresContext, aConditions);
4465 6 : NS_ASSERTION(unitOK, "unexpected unit");
4466 6 : item->mXOffset = tempCoord.GetCoordValue();
4467 :
4468 12 : unitOK = SetCoord(arr->Item(1), tempCoord, nsStyleCoord(),
4469 : SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
4470 6 : aContext, aPresContext, aConditions);
4471 6 : NS_ASSERTION(unitOK, "unexpected unit");
4472 6 : item->mYOffset = tempCoord.GetCoordValue();
4473 :
4474 : // Blur radius is optional in the current box-shadow spec
4475 6 : if (arr->Item(2).GetUnit() != eCSSUnit_Null) {
4476 12 : unitOK = SetCoord(arr->Item(2), tempCoord, nsStyleCoord(),
4477 : SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY |
4478 : SETCOORD_CALC_CLAMP_NONNEGATIVE,
4479 6 : aContext, aPresContext, aConditions);
4480 6 : NS_ASSERTION(unitOK, "unexpected unit");
4481 6 : item->mRadius = tempCoord.GetCoordValue();
4482 : } else {
4483 0 : item->mRadius = 0;
4484 : }
4485 :
4486 : // Find the spread radius
4487 6 : if (aIsBoxShadow && arr->Item(3).GetUnit() != eCSSUnit_Null) {
4488 0 : unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(),
4489 : SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
4490 0 : aContext, aPresContext, aConditions);
4491 0 : NS_ASSERTION(unitOK, "unexpected unit");
4492 0 : item->mSpread = tempCoord.GetCoordValue();
4493 : } else {
4494 6 : item->mSpread = 0;
4495 : }
4496 :
4497 6 : if (arr->Item(4).GetUnit() != eCSSUnit_Null) {
4498 6 : item->mHasColor = true;
4499 : // 2nd argument can be bogus since inherit is not a valid color
4500 12 : unitOK = SetColor(arr->Item(4), 0, aPresContext, aContext, item->mColor,
4501 6 : aConditions);
4502 6 : NS_ASSERTION(unitOK, "unexpected unit");
4503 : }
4504 :
4505 6 : if (aIsBoxShadow && arr->Item(5).GetUnit() == eCSSUnit_Enumerated) {
4506 2 : NS_ASSERTION(arr->Item(5).GetIntValue()
4507 : == uint8_t(StyleBoxShadowType::Inset),
4508 : "invalid keyword type for box shadow");
4509 2 : item->mInset = true;
4510 : } else {
4511 4 : item->mInset = false;
4512 : }
4513 : }
4514 :
4515 6 : return shadowList.forget();
4516 : }
4517 :
4518 : struct TextEmphasisChars
4519 : {
4520 : const char16_t* mFilled;
4521 : const char16_t* mOpen;
4522 : };
4523 :
4524 : #define TEXT_EMPHASIS_CHARS_LIST() \
4525 : TEXT_EMPHASIS_CHARS_ITEM(u"", u"", NONE) \
4526 : TEXT_EMPHASIS_CHARS_ITEM(u"\u2022", u"\u25e6", DOT) \
4527 : TEXT_EMPHASIS_CHARS_ITEM(u"\u25cf", u"\u25cb", CIRCLE) \
4528 : TEXT_EMPHASIS_CHARS_ITEM(u"\u25c9", u"\u25ce", DOUBLE_CIRCLE) \
4529 : TEXT_EMPHASIS_CHARS_ITEM(u"\u25b2", u"\u25b3", TRIANGLE) \
4530 : TEXT_EMPHASIS_CHARS_ITEM(u"\ufe45", u"\ufe46", SESAME)
4531 :
4532 : static constexpr TextEmphasisChars kTextEmphasisChars[] =
4533 : {
4534 : #define TEXT_EMPHASIS_CHARS_ITEM(filled_, open_, type_) \
4535 : { filled_, open_ }, // type_
4536 : TEXT_EMPHASIS_CHARS_LIST()
4537 : #undef TEXT_EMPHASIS_CHARS_ITEM
4538 : };
4539 :
4540 : #define TEXT_EMPHASIS_CHARS_ITEM(filled_, open_, type_) \
4541 : static_assert(ArrayLength(filled_) <= 2 && \
4542 : ArrayLength(open_) <= 2, \
4543 : "emphasis marks should have no more than one char"); \
4544 : static_assert( \
4545 : *kTextEmphasisChars[NS_STYLE_TEXT_EMPHASIS_STYLE_##type_].mFilled == \
4546 : *filled_, "filled " #type_ " should be " #filled_); \
4547 : static_assert( \
4548 : *kTextEmphasisChars[NS_STYLE_TEXT_EMPHASIS_STYLE_##type_].mOpen == \
4549 : *open_, "open " #type_ " should be " #open_);
4550 : TEXT_EMPHASIS_CHARS_LIST()
4551 : #undef TEXT_EMPHASIS_CHARS_ITEM
4552 :
4553 : #undef TEXT_EMPHASIS_CHARS_LIST
4554 :
4555 : static void
4556 0 : TruncateStringToSingleGrapheme(nsAString& aStr)
4557 : {
4558 0 : unicode::ClusterIterator iter(aStr.Data(), aStr.Length());
4559 0 : if (!iter.AtEnd()) {
4560 0 : iter.Next();
4561 0 : if (!iter.AtEnd()) {
4562 : // Not mutating the string for common cases helps memory use
4563 : // since we share the buffer from the specified style into the
4564 : // computed style.
4565 0 : aStr.Truncate(iter - aStr.Data());
4566 : }
4567 : }
4568 0 : }
4569 :
4570 : struct LengthNumberCalcObj
4571 : {
4572 : float mValue;
4573 : bool mIsNumber;
4574 : };
4575 :
4576 : struct LengthNumberCalcOps : public css::FloatCoeffsAlreadyNormalizedOps
4577 : {
4578 : typedef LengthNumberCalcObj result_type;
4579 : GeckoStyleContext* const mStyleContext;
4580 : nsPresContext* const mPresContext;
4581 : RuleNodeCacheConditions& mConditions;
4582 :
4583 0 : LengthNumberCalcOps(GeckoStyleContext* aStyleContext,
4584 : nsPresContext* aPresContext,
4585 : RuleNodeCacheConditions& aConditions)
4586 0 : : mStyleContext(aStyleContext),
4587 : mPresContext(aPresContext),
4588 0 : mConditions(aConditions)
4589 : {
4590 0 : }
4591 :
4592 : result_type
4593 0 : MergeAdditive(nsCSSUnit aCalcFunction,
4594 : result_type aValue1, result_type aValue2)
4595 : {
4596 0 : MOZ_ASSERT(aValue1.mIsNumber == aValue2.mIsNumber);
4597 :
4598 : LengthNumberCalcObj result;
4599 0 : result.mIsNumber = aValue1.mIsNumber;
4600 0 : if (aCalcFunction == eCSSUnit_Calc_Plus) {
4601 0 : result.mValue = aValue1.mValue + aValue2.mValue;
4602 0 : return result;
4603 : }
4604 0 : MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Minus,
4605 : "unexpected unit");
4606 0 : result.mValue = aValue1.mValue - aValue2.mValue;
4607 0 : return result;
4608 : }
4609 :
4610 : result_type
4611 0 : MergeMultiplicativeL(nsCSSUnit aCalcFunction,
4612 : float aValue1, result_type aValue2)
4613 : {
4614 0 : MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_L,
4615 : "unexpected unit");
4616 : LengthNumberCalcObj result;
4617 0 : result.mIsNumber = aValue2.mIsNumber;
4618 0 : result.mValue = aValue1 * aValue2.mValue;
4619 0 : return result;
4620 : }
4621 :
4622 : result_type
4623 0 : MergeMultiplicativeR(nsCSSUnit aCalcFunction,
4624 : result_type aValue1, float aValue2)
4625 : {
4626 : LengthNumberCalcObj result;
4627 0 : result.mIsNumber = aValue1.mIsNumber;
4628 0 : if (aCalcFunction == eCSSUnit_Calc_Times_R) {
4629 0 : result.mValue = aValue1.mValue * aValue2;
4630 0 : return result;
4631 : }
4632 0 : MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Divided,
4633 : "unexpected unit");
4634 0 : result.mValue = aValue1.mValue / aValue2;
4635 0 : return result;
4636 : }
4637 :
4638 0 : result_type ComputeLeafValue(const nsCSSValue& aValue)
4639 : {
4640 : LengthNumberCalcObj result;
4641 0 : if (aValue.IsLengthUnit()) {
4642 0 : result.mIsNumber = false;
4643 0 : result.mValue = CalcLength(aValue, mStyleContext,
4644 0 : mPresContext, mConditions);
4645 : }
4646 0 : else if (eCSSUnit_Number == aValue.GetUnit()) {
4647 0 : result.mIsNumber = true;
4648 0 : result.mValue = aValue.GetFloatValue();
4649 : } else {
4650 0 : MOZ_ASSERT(false, "unexpected value");
4651 : result.mIsNumber = true;
4652 : result.mValue = 1.0f;
4653 : }
4654 :
4655 0 : return result;
4656 : }
4657 : };
4658 :
4659 : struct SetLineHeightCalcOps : public LengthNumberCalcOps
4660 : {
4661 0 : SetLineHeightCalcOps(GeckoStyleContext* aStyleContext,
4662 : nsPresContext* aPresContext,
4663 : RuleNodeCacheConditions& aConditions)
4664 0 : : LengthNumberCalcOps(aStyleContext, aPresContext, aConditions)
4665 : {
4666 0 : }
4667 :
4668 0 : result_type ComputeLeafValue(const nsCSSValue& aValue)
4669 : {
4670 : LengthNumberCalcObj result;
4671 0 : if (aValue.IsLengthUnit()) {
4672 0 : result.mIsNumber = false;
4673 0 : result.mValue = CalcLength(aValue, mStyleContext,
4674 0 : mPresContext, mConditions);
4675 : }
4676 0 : else if (eCSSUnit_Percent == aValue.GetUnit()) {
4677 0 : mConditions.SetUncacheable();
4678 0 : result.mIsNumber = false;
4679 0 : nscoord fontSize = mStyleContext->StyleFont()->mFont.size;
4680 0 : result.mValue = fontSize * aValue.GetPercentValue();
4681 : }
4682 0 : else if (eCSSUnit_Number == aValue.GetUnit()) {
4683 0 : result.mIsNumber = true;
4684 0 : result.mValue = aValue.GetFloatValue();
4685 : } else {
4686 0 : MOZ_ASSERT(false, "unexpected value");
4687 : result.mIsNumber = true;
4688 : result.mValue = 1.0f;
4689 : }
4690 :
4691 0 : return result;
4692 : }
4693 : };
4694 :
4695 : const void*
4696 46 : nsRuleNode::ComputeTextData(void* aStartStruct,
4697 : const nsRuleData* aRuleData,
4698 : GeckoStyleContext* aContext,
4699 : nsRuleNode* aHighestNode,
4700 : const RuleDetail aRuleDetail,
4701 : const RuleNodeCacheConditions aConditions)
4702 : {
4703 92 : COMPUTE_START_INHERITED(Text, text, parentText)
4704 :
4705 : auto setComplexColor = [&](const nsCSSValue* aValue,
4706 138 : StyleComplexColor nsStyleText::* aField) {
4707 276 : SetComplexColor<eUnsetInherit>(*aValue, parentText->*aField,
4708 276 : StyleComplexColor::CurrentColor(),
4709 414 : mPresContext, text->*aField, conditions);
4710 184 : };
4711 :
4712 : // tab-size: number, length, calc, inherit
4713 46 : const nsCSSValue* tabSizeValue = aRuleData->ValueForTabSize();
4714 46 : if (tabSizeValue->GetUnit() == eCSSUnit_Initial) {
4715 0 : text->mTabSize = nsStyleCoord(float(NS_STYLE_TABSIZE_INITIAL), eStyleUnit_Factor);
4716 46 : } else if (eCSSUnit_Calc == tabSizeValue->GetUnit()) {
4717 0 : LengthNumberCalcOps ops(aContext, mPresContext, conditions);
4718 0 : LengthNumberCalcObj obj = css::ComputeCalc(*tabSizeValue, ops);
4719 0 : float value = obj.mValue < 0 ? 0 : obj.mValue;
4720 0 : if (obj.mIsNumber) {
4721 0 : text->mTabSize.SetFactorValue(value);
4722 : } else {
4723 0 : text->mTabSize.SetCoordValue(
4724 0 : NSToCoordRoundWithClamp(value));
4725 : }
4726 : } else {
4727 46 : SetCoord(*tabSizeValue, text->mTabSize, parentText->mTabSize,
4728 : SETCOORD_LH | SETCOORD_FACTOR | SETCOORD_UNSET_INHERIT,
4729 92 : aContext, mPresContext, conditions);
4730 : }
4731 :
4732 : // letter-spacing: normal, length, inherit
4733 92 : SetCoord(*aRuleData->ValueForLetterSpacing(),
4734 92 : text->mLetterSpacing, parentText->mLetterSpacing,
4735 : SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
4736 : SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INHERIT,
4737 92 : aContext, mPresContext, conditions);
4738 :
4739 : // text-shadow: none, list, inherit, initial
4740 46 : const nsCSSValue* textShadowValue = aRuleData->ValueForTextShadow();
4741 46 : if (textShadowValue->GetUnit() != eCSSUnit_Null) {
4742 15 : text->mTextShadow = nullptr;
4743 :
4744 : // Don't need to handle none/initial explicitly: The above assignment
4745 : // takes care of that
4746 24 : if (textShadowValue->GetUnit() == eCSSUnit_Inherit ||
4747 9 : textShadowValue->GetUnit() == eCSSUnit_Unset) {
4748 6 : conditions.SetUncacheable();
4749 6 : text->mTextShadow = parentText->mTextShadow;
4750 18 : } else if (textShadowValue->GetUnit() == eCSSUnit_List ||
4751 9 : textShadowValue->GetUnit() == eCSSUnit_ListDep) {
4752 : // List of arrays
4753 0 : text->mTextShadow = GetShadowData(textShadowValue->GetListValue(),
4754 0 : aContext, false, mPresContext, conditions);
4755 : }
4756 : }
4757 :
4758 : // line-height: normal, number, length, percent, calc, inherit
4759 46 : const nsCSSValue* lineHeightValue = aRuleData->ValueForLineHeight();
4760 46 : if (eCSSUnit_Percent == lineHeightValue->GetUnit()) {
4761 0 : conditions.SetUncacheable();
4762 : // Use |mFont.size| to pick up minimum font size.
4763 0 : text->mLineHeight.SetCoordValue(
4764 0 : NSToCoordRound(float(aContext->StyleFont()->mFont.size) *
4765 0 : lineHeightValue->GetPercentValue()));
4766 : }
4767 92 : else if (eCSSUnit_Initial == lineHeightValue->GetUnit() ||
4768 46 : eCSSUnit_System_Font == lineHeightValue->GetUnit()) {
4769 6 : text->mLineHeight.SetNormalValue();
4770 : }
4771 40 : else if (eCSSUnit_Calc == lineHeightValue->GetUnit()) {
4772 0 : SetLineHeightCalcOps ops(aContext, mPresContext, conditions);
4773 0 : LengthNumberCalcObj obj = css::ComputeCalc(*lineHeightValue, ops);
4774 0 : if (obj.mIsNumber) {
4775 0 : text->mLineHeight.SetFactorValue(obj.mValue);
4776 : } else {
4777 0 : text->mLineHeight.SetCoordValue(
4778 0 : NSToCoordRoundWithClamp(obj.mValue));
4779 : }
4780 : }
4781 : else {
4782 40 : SetCoord(*lineHeightValue, text->mLineHeight, parentText->mLineHeight,
4783 : SETCOORD_LEH | SETCOORD_FACTOR | SETCOORD_NORMAL |
4784 : SETCOORD_UNSET_INHERIT,
4785 80 : aContext, mPresContext, conditions);
4786 40 : if (lineHeightValue->IsLengthUnit() &&
4787 0 : !lineHeightValue->IsRelativeLengthUnit()) {
4788 0 : nscoord lh = nsStyleFont::ZoomText(mPresContext,
4789 0 : text->mLineHeight.GetCoordValue());
4790 :
4791 0 : conditions.SetUncacheable();
4792 0 : const nsStyleFont *font = aContext->StyleFont();
4793 0 : nscoord minimumFontSize = mPresContext->MinFontSize(font->mLanguage);
4794 :
4795 0 : if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
4796 0 : if (font->mSize != 0) {
4797 0 : lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
4798 : } else {
4799 0 : lh = minimumFontSize;
4800 : }
4801 : }
4802 0 : text->mLineHeight.SetCoordValue(lh);
4803 : }
4804 : }
4805 :
4806 :
4807 : // text-align: enum, string, pair(enum|string), inherit, initial
4808 : // NOTE: string is not implemented yet.
4809 46 : const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
4810 46 : text->mTextAlignTrue = false;
4811 46 : if (eCSSUnit_String == textAlignValue->GetUnit()) {
4812 0 : NS_NOTYETIMPLEMENTED("align string");
4813 50 : } else if (eCSSUnit_Enumerated == textAlignValue->GetUnit() &&
4814 : NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT ==
4815 4 : textAlignValue->GetIntValue()) {
4816 0 : conditions.SetUncacheable();
4817 0 : uint8_t parentAlign = parentText->mTextAlign;
4818 0 : text->mTextAlign = (NS_STYLE_TEXT_ALIGN_START == parentAlign) ?
4819 0 : NS_STYLE_TEXT_ALIGN_CENTER : parentAlign;
4820 50 : } else if (eCSSUnit_Enumerated == textAlignValue->GetUnit() &&
4821 : NS_STYLE_TEXT_ALIGN_MATCH_PARENT ==
4822 4 : textAlignValue->GetIntValue()) {
4823 0 : conditions.SetUncacheable();
4824 0 : GeckoStyleContext* parent = aContext->GetParent();
4825 0 : if (parent) {
4826 0 : uint8_t parentAlign = parentText->mTextAlign;
4827 0 : uint8_t parentDirection = parent->StyleVisibility()->mDirection;
4828 0 : switch (parentAlign) {
4829 : case NS_STYLE_TEXT_ALIGN_START:
4830 0 : text->mTextAlign = parentDirection == NS_STYLE_DIRECTION_RTL ?
4831 0 : NS_STYLE_TEXT_ALIGN_RIGHT : NS_STYLE_TEXT_ALIGN_LEFT;
4832 0 : break;
4833 :
4834 : case NS_STYLE_TEXT_ALIGN_END:
4835 0 : text->mTextAlign = parentDirection == NS_STYLE_DIRECTION_RTL ?
4836 0 : NS_STYLE_TEXT_ALIGN_LEFT : NS_STYLE_TEXT_ALIGN_RIGHT;
4837 0 : break;
4838 :
4839 : default:
4840 0 : text->mTextAlign = parentAlign;
4841 : }
4842 : }
4843 : } else {
4844 46 : if (eCSSUnit_Pair == textAlignValue->GetUnit()) {
4845 : // Two values were specified, one must be 'true'.
4846 0 : text->mTextAlignTrue = true;
4847 0 : const nsCSSValuePair& textAlignValuePair = textAlignValue->GetPairValue();
4848 0 : textAlignValue = &textAlignValuePair.mXValue;
4849 0 : if (eCSSUnit_Enumerated == textAlignValue->GetUnit()) {
4850 0 : if (textAlignValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_UNSAFE) {
4851 0 : textAlignValue = &textAlignValuePair.mYValue;
4852 : }
4853 0 : } else if (eCSSUnit_String == textAlignValue->GetUnit()) {
4854 0 : NS_NOTYETIMPLEMENTED("align string");
4855 : }
4856 86 : } else if (eCSSUnit_Inherit == textAlignValue->GetUnit() ||
4857 40 : eCSSUnit_Unset == textAlignValue->GetUnit()) {
4858 6 : text->mTextAlignTrue = parentText->mTextAlignTrue;
4859 : }
4860 46 : SetValue(*textAlignValue, text->mTextAlign, conditions,
4861 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4862 46 : parentText->mTextAlign,
4863 46 : NS_STYLE_TEXT_ALIGN_START);
4864 : }
4865 :
4866 : // text-align-last: enum, pair(enum), inherit, initial
4867 46 : const nsCSSValue* textAlignLastValue = aRuleData->ValueForTextAlignLast();
4868 46 : text->mTextAlignLastTrue = false;
4869 46 : if (eCSSUnit_Pair == textAlignLastValue->GetUnit()) {
4870 : // Two values were specified, one must be 'true'.
4871 0 : text->mTextAlignLastTrue = true;
4872 0 : const nsCSSValuePair& textAlignLastValuePair = textAlignLastValue->GetPairValue();
4873 0 : textAlignLastValue = &textAlignLastValuePair.mXValue;
4874 0 : if (eCSSUnit_Enumerated == textAlignLastValue->GetUnit()) {
4875 0 : if (textAlignLastValue->GetIntValue() == NS_STYLE_TEXT_ALIGN_UNSAFE) {
4876 0 : textAlignLastValue = &textAlignLastValuePair.mYValue;
4877 : }
4878 : }
4879 92 : } else if (eCSSUnit_Inherit == textAlignLastValue->GetUnit() ||
4880 46 : eCSSUnit_Unset == textAlignLastValue->GetUnit()) {
4881 0 : text->mTextAlignLastTrue = parentText->mTextAlignLastTrue;
4882 : }
4883 46 : SetValue(*textAlignLastValue, text->mTextAlignLast,
4884 : conditions,
4885 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4886 46 : parentText->mTextAlignLast,
4887 46 : NS_STYLE_TEXT_ALIGN_AUTO);
4888 :
4889 : // text-indent: length, percent, calc, inherit, initial
4890 46 : SetCoord(*aRuleData->ValueForTextIndent(), text->mTextIndent, parentText->mTextIndent,
4891 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
4892 : SETCOORD_UNSET_INHERIT,
4893 92 : aContext, mPresContext, conditions);
4894 :
4895 : // text-justify: enum, inherit, initial
4896 92 : SetValue(*aRuleData->ValueForTextJustify(), text->mTextJustify, conditions,
4897 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4898 46 : parentText->mTextJustify,
4899 46 : StyleTextJustify::Auto);
4900 :
4901 : // text-transform: enum, inherit, initial
4902 46 : SetValue(*aRuleData->ValueForTextTransform(), text->mTextTransform, conditions,
4903 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4904 46 : parentText->mTextTransform,
4905 46 : NS_STYLE_TEXT_TRANSFORM_NONE);
4906 :
4907 : // white-space: enum, inherit, initial
4908 92 : SetValue(*aRuleData->ValueForWhiteSpace(), text->mWhiteSpace, conditions,
4909 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4910 46 : parentText->mWhiteSpace,
4911 46 : StyleWhiteSpace::Normal);
4912 :
4913 : // word-break: enum, inherit, initial
4914 46 : SetValue(*aRuleData->ValueForWordBreak(), text->mWordBreak, conditions,
4915 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4916 46 : parentText->mWordBreak,
4917 46 : NS_STYLE_WORDBREAK_NORMAL);
4918 :
4919 : // word-spacing: normal, length, percent, inherit
4920 46 : const nsCSSValue* wordSpacingValue = aRuleData->ValueForWordSpacing();
4921 46 : if (wordSpacingValue->GetUnit() == eCSSUnit_Normal) {
4922 : // Do this so that "normal" computes to 0px, as the CSS 2.1 spec requires.
4923 6 : text->mWordSpacing.SetCoordValue(0);
4924 : } else {
4925 80 : SetCoord(*aRuleData->ValueForWordSpacing(),
4926 80 : text->mWordSpacing, parentText->mWordSpacing,
4927 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
4928 : SETCOORD_STORE_CALC | SETCOORD_UNSET_INHERIT,
4929 80 : aContext, mPresContext, conditions);
4930 : }
4931 :
4932 : // overflow-wrap: enum, inherit, initial
4933 46 : SetValue(*aRuleData->ValueForOverflowWrap(), text->mOverflowWrap, conditions,
4934 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4935 46 : parentText->mOverflowWrap,
4936 46 : NS_STYLE_OVERFLOWWRAP_NORMAL);
4937 :
4938 : // hyphens: enum, inherit, initial
4939 92 : SetValue(*aRuleData->ValueForHyphens(), text->mHyphens, conditions,
4940 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4941 46 : parentText->mHyphens,
4942 46 : StyleHyphens::Manual);
4943 :
4944 : // ruby-align: enum, inherit, initial
4945 92 : SetValue(*aRuleData->ValueForRubyAlign(),
4946 46 : text->mRubyAlign, conditions,
4947 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4948 46 : parentText->mRubyAlign,
4949 46 : NS_STYLE_RUBY_ALIGN_SPACE_AROUND);
4950 :
4951 : // ruby-position: enum, inherit, initial
4952 92 : SetValue(*aRuleData->ValueForRubyPosition(),
4953 46 : text->mRubyPosition, conditions,
4954 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4955 46 : parentText->mRubyPosition,
4956 46 : NS_STYLE_RUBY_POSITION_OVER);
4957 :
4958 : // text-size-adjust: enum, inherit, initial
4959 92 : SetValue(*aRuleData->ValueForTextSizeAdjust(),
4960 46 : text->mTextSizeAdjust, conditions,
4961 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4962 46 : parentText->mTextSizeAdjust,
4963 46 : NS_STYLE_TEXT_SIZE_ADJUST_AUTO);
4964 :
4965 : // text-combine-upright: enum, inherit, initial
4966 92 : SetValue(*aRuleData->ValueForTextCombineUpright(),
4967 46 : text->mTextCombineUpright,
4968 : conditions,
4969 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4970 46 : parentText->mTextCombineUpright,
4971 46 : NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE);
4972 :
4973 : // text-emphasis-color: color, string, inherit, initial
4974 46 : setComplexColor(aRuleData->ValueForTextEmphasisColor(),
4975 46 : &nsStyleText::mTextEmphasisColor);
4976 :
4977 : // text-emphasis-position: enum, inherit, initial
4978 92 : SetValue(*aRuleData->ValueForTextEmphasisPosition(),
4979 46 : text->mTextEmphasisPosition,
4980 : conditions,
4981 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
4982 46 : parentText->mTextEmphasisPosition,
4983 : NS_STYLE_TEXT_EMPHASIS_POSITION_OVER |
4984 46 : NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT);
4985 :
4986 : // text-emphasis-style: string, enum, inherit, initial
4987 : const nsCSSValue* textEmphasisStyleValue =
4988 46 : aRuleData->ValueForTextEmphasisStyle();
4989 46 : switch (textEmphasisStyleValue->GetUnit()) {
4990 : case eCSSUnit_Null:
4991 46 : break;
4992 : case eCSSUnit_Initial:
4993 : case eCSSUnit_None: {
4994 0 : text->mTextEmphasisStyle = NS_STYLE_TEXT_EMPHASIS_STYLE_NONE;
4995 0 : text->mTextEmphasisStyleString = u"";
4996 0 : break;
4997 : }
4998 : case eCSSUnit_Inherit:
4999 : case eCSSUnit_Unset: {
5000 0 : conditions.SetUncacheable();
5001 0 : text->mTextEmphasisStyle = parentText->mTextEmphasisStyle;
5002 0 : text->mTextEmphasisStyleString = parentText->mTextEmphasisStyleString;
5003 0 : break;
5004 : }
5005 : case eCSSUnit_Enumerated: {
5006 0 : auto style = textEmphasisStyleValue->GetIntValue();
5007 : // If shape part is not specified, compute it according to the
5008 : // writing-mode. Note that, if the fill part (filled/open) is not
5009 : // specified, we compute it to filled per spec. Since that value
5010 : // is zero, no additional computation is needed. See the assertion
5011 : // in CSSParserImpl::ParseTextEmphasisStyle().
5012 0 : if (!(style & NS_STYLE_TEXT_EMPHASIS_STYLE_SHAPE_MASK)) {
5013 0 : conditions.SetUncacheable();
5014 0 : if (WritingMode(aContext).IsVertical()) {
5015 0 : style |= NS_STYLE_TEXT_EMPHASIS_STYLE_SESAME;
5016 : } else {
5017 0 : style |= NS_STYLE_TEXT_EMPHASIS_STYLE_CIRCLE;
5018 : }
5019 : }
5020 0 : text->mTextEmphasisStyle = style;
5021 0 : size_t shape = style & NS_STYLE_TEXT_EMPHASIS_STYLE_SHAPE_MASK;
5022 0 : MOZ_ASSERT(shape > 0 && shape < ArrayLength(kTextEmphasisChars));
5023 0 : const TextEmphasisChars& chars = kTextEmphasisChars[shape];
5024 0 : text->mTextEmphasisStyleString =
5025 0 : (style & NS_STYLE_TEXT_EMPHASIS_STYLE_FILL_MASK) ==
5026 0 : NS_STYLE_TEXT_EMPHASIS_STYLE_FILLED ? chars.mFilled : chars.mOpen;
5027 0 : break;
5028 : }
5029 : case eCSSUnit_String: {
5030 0 : text->mTextEmphasisStyle = NS_STYLE_TEXT_EMPHASIS_STYLE_STRING;
5031 0 : nsString strValue;
5032 0 : textEmphasisStyleValue->GetStringValue(strValue);
5033 0 : TruncateStringToSingleGrapheme(strValue);
5034 0 : text->mTextEmphasisStyleString = strValue;
5035 0 : break;
5036 : }
5037 : default:
5038 0 : MOZ_ASSERT_UNREACHABLE("Unknown value unit type");
5039 : }
5040 :
5041 : // text-rendering: enum, inherit, initial
5042 92 : SetValue(*aRuleData->ValueForTextRendering(),
5043 46 : text->mTextRendering, conditions,
5044 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
5045 46 : parentText->mTextRendering,
5046 46 : NS_STYLE_TEXT_RENDERING_AUTO);
5047 :
5048 : // -webkit-text-fill-color: color, string, inherit, initial
5049 46 : setComplexColor(aRuleData->ValueForWebkitTextFillColor(),
5050 46 : &nsStyleText::mWebkitTextFillColor);
5051 :
5052 : // -webkit-text-stroke-color: color, string, inherit, initial
5053 46 : setComplexColor(aRuleData->ValueForWebkitTextStrokeColor(),
5054 46 : &nsStyleText::mWebkitTextStrokeColor);
5055 :
5056 : // -webkit-text-stroke-width: length, inherit, initial, enum
5057 : Maybe<nscoord> coord =
5058 : ComputeLineWidthValue<eUnsetInherit>(
5059 46 : *aRuleData->ValueForWebkitTextStrokeWidth(),
5060 46 : parentText->mWebkitTextStrokeWidth, 0,
5061 138 : aContext, mPresContext, conditions);
5062 46 : if (coord.isSome()) {
5063 0 : text->mWebkitTextStrokeWidth = *coord;
5064 : }
5065 :
5066 : // -moz-control-character-visibility: enum, inherit, initial
5067 138 : SetValue(*aRuleData->ValueForControlCharacterVisibility(),
5068 46 : text->mControlCharacterVisibility,
5069 : conditions,
5070 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
5071 46 : parentText->mControlCharacterVisibility,
5072 92 : nsCSSParser::ControlCharVisibilityDefault());
5073 :
5074 92 : COMPUTE_END_INHERITED(Text, text)
5075 : }
5076 :
5077 : const void*
5078 121 : nsRuleNode::ComputeTextResetData(void* aStartStruct,
5079 : const nsRuleData* aRuleData,
5080 : GeckoStyleContext* aContext,
5081 : nsRuleNode* aHighestNode,
5082 : const RuleDetail aRuleDetail,
5083 : const RuleNodeCacheConditions aConditions)
5084 : {
5085 242 : COMPUTE_START_RESET(TextReset, text, parentText)
5086 :
5087 : // text-decoration-line: enum (bit field), inherit, initial
5088 : const nsCSSValue* decorationLineValue =
5089 121 : aRuleData->ValueForTextDecorationLine();
5090 121 : if (eCSSUnit_Enumerated == decorationLineValue->GetUnit()) {
5091 0 : text->mTextDecorationLine = decorationLineValue->GetIntValue();
5092 121 : } else if (eCSSUnit_Inherit == decorationLineValue->GetUnit()) {
5093 12 : conditions.SetUncacheable();
5094 12 : text->mTextDecorationLine = parentText->mTextDecorationLine;
5095 218 : } else if (eCSSUnit_Initial == decorationLineValue->GetUnit() ||
5096 109 : eCSSUnit_Unset == decorationLineValue->GetUnit()) {
5097 0 : text->mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
5098 : }
5099 :
5100 : // text-decoration-color: color, string, enum, inherit, initial
5101 242 : SetComplexColor<eUnsetInitial>(*aRuleData->ValueForTextDecorationColor(),
5102 : parentText->mTextDecorationColor,
5103 242 : StyleComplexColor::CurrentColor(),
5104 121 : mPresContext,
5105 121 : text->mTextDecorationColor, conditions);
5106 :
5107 : // text-decoration-style: enum, inherit, initial
5108 : const nsCSSValue* decorationStyleValue =
5109 121 : aRuleData->ValueForTextDecorationStyle();
5110 121 : if (eCSSUnit_Enumerated == decorationStyleValue->GetUnit()) {
5111 0 : text->mTextDecorationStyle = decorationStyleValue->GetIntValue();
5112 121 : } else if (eCSSUnit_Inherit == decorationStyleValue->GetUnit()) {
5113 12 : text->mTextDecorationStyle = parentText->mTextDecorationStyle;
5114 12 : conditions.SetUncacheable();
5115 218 : } else if (eCSSUnit_Initial == decorationStyleValue->GetUnit() ||
5116 109 : eCSSUnit_Unset == decorationStyleValue->GetUnit()) {
5117 0 : text->mTextDecorationStyle = NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
5118 : }
5119 :
5120 : // text-overflow: enum, string, pair(enum|string), inherit, initial
5121 : const nsCSSValue* textOverflowValue =
5122 121 : aRuleData->ValueForTextOverflow();
5123 242 : if (eCSSUnit_Initial == textOverflowValue->GetUnit() ||
5124 121 : eCSSUnit_Unset == textOverflowValue->GetUnit()) {
5125 0 : text->mTextOverflow = nsStyleTextOverflow();
5126 121 : } else if (eCSSUnit_Inherit == textOverflowValue->GetUnit()) {
5127 88 : conditions.SetUncacheable();
5128 88 : text->mTextOverflow = parentText->mTextOverflow;
5129 33 : } else if (eCSSUnit_Enumerated == textOverflowValue->GetUnit()) {
5130 : // A single enumerated value.
5131 0 : SetValue(*textOverflowValue, text->mTextOverflow.mRight.mType,
5132 : conditions,
5133 0 : SETVAL_ENUMERATED, parentText->mTextOverflow.mRight.mType,
5134 0 : NS_STYLE_TEXT_OVERFLOW_CLIP);
5135 0 : text->mTextOverflow.mRight.mString.Truncate();
5136 0 : text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
5137 0 : text->mTextOverflow.mLeft.mString.Truncate();
5138 0 : text->mTextOverflow.mLogicalDirections = true;
5139 33 : } else if (eCSSUnit_String == textOverflowValue->GetUnit()) {
5140 : // A single string value.
5141 0 : text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
5142 0 : textOverflowValue->GetStringValue(text->mTextOverflow.mRight.mString);
5143 0 : text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
5144 0 : text->mTextOverflow.mLeft.mString.Truncate();
5145 0 : text->mTextOverflow.mLogicalDirections = true;
5146 33 : } else if (eCSSUnit_Pair == textOverflowValue->GetUnit()) {
5147 : // Two values were specified.
5148 0 : text->mTextOverflow.mLogicalDirections = false;
5149 : const nsCSSValuePair& textOverflowValuePair =
5150 0 : textOverflowValue->GetPairValue();
5151 :
5152 0 : const nsCSSValue *textOverflowLeftValue = &textOverflowValuePair.mXValue;
5153 0 : if (eCSSUnit_Enumerated == textOverflowLeftValue->GetUnit()) {
5154 0 : SetValue(*textOverflowLeftValue, text->mTextOverflow.mLeft.mType,
5155 : conditions,
5156 0 : SETVAL_ENUMERATED, parentText->mTextOverflow.mLeft.mType,
5157 0 : NS_STYLE_TEXT_OVERFLOW_CLIP);
5158 0 : text->mTextOverflow.mLeft.mString.Truncate();
5159 0 : } else if (eCSSUnit_String == textOverflowLeftValue->GetUnit()) {
5160 0 : textOverflowLeftValue->GetStringValue(text->mTextOverflow.mLeft.mString);
5161 0 : text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
5162 : }
5163 :
5164 0 : const nsCSSValue *textOverflowRightValue = &textOverflowValuePair.mYValue;
5165 0 : if (eCSSUnit_Enumerated == textOverflowRightValue->GetUnit()) {
5166 0 : SetValue(*textOverflowRightValue, text->mTextOverflow.mRight.mType,
5167 : conditions,
5168 0 : SETVAL_ENUMERATED, parentText->mTextOverflow.mRight.mType,
5169 0 : NS_STYLE_TEXT_OVERFLOW_CLIP);
5170 0 : text->mTextOverflow.mRight.mString.Truncate();
5171 0 : } else if (eCSSUnit_String == textOverflowRightValue->GetUnit()) {
5172 0 : textOverflowRightValue->GetStringValue(text->mTextOverflow.mRight.mString);
5173 0 : text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
5174 : }
5175 : }
5176 :
5177 : // unicode-bidi: enum, inherit, initial
5178 121 : SetValue(*aRuleData->ValueForUnicodeBidi(), text->mUnicodeBidi, conditions,
5179 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
5180 121 : parentText->mUnicodeBidi,
5181 121 : NS_STYLE_UNICODE_BIDI_NORMAL);
5182 :
5183 : // initial-letter: normal, number, array(number, integer?), initial
5184 121 : const nsCSSValue* initialLetterValue = aRuleData->ValueForInitialLetter();
5185 121 : if (initialLetterValue->GetUnit() == eCSSUnit_Null) {
5186 : // We don't want to change anything in this case.
5187 0 : } else if (initialLetterValue->GetUnit() == eCSSUnit_Inherit) {
5188 0 : conditions.SetUncacheable();
5189 0 : text->mInitialLetterSink = parentText->mInitialLetterSink;
5190 0 : text->mInitialLetterSize = parentText->mInitialLetterSize;
5191 0 : } else if (initialLetterValue->GetUnit() == eCSSUnit_Initial ||
5192 0 : initialLetterValue->GetUnit() == eCSSUnit_Unset ||
5193 0 : initialLetterValue->GetUnit() == eCSSUnit_Normal) {
5194 : // Use invalid values in initial-letter property to mean normal. So we can
5195 : // determine whether it is normal by checking mInitialLetterSink == 0.
5196 0 : text->mInitialLetterSink = 0;
5197 0 : text->mInitialLetterSize = 0.0f;
5198 0 : } else if (initialLetterValue->GetUnit() == eCSSUnit_Array) {
5199 0 : const nsCSSValue& firstValue = initialLetterValue->GetArrayValue()->Item(0);
5200 0 : const nsCSSValue& secondValue = initialLetterValue->GetArrayValue()->Item(1);
5201 0 : MOZ_ASSERT(firstValue.GetUnit() == eCSSUnit_Number &&
5202 : secondValue.GetUnit() == eCSSUnit_Integer,
5203 : "unexpected value unit");
5204 0 : text->mInitialLetterSize = firstValue.GetFloatValue();
5205 0 : text->mInitialLetterSink = secondValue.GetIntValue();
5206 0 : } else if (initialLetterValue->GetUnit() == eCSSUnit_Number) {
5207 0 : text->mInitialLetterSize = initialLetterValue->GetFloatValue();
5208 0 : text->mInitialLetterSink = NSToCoordFloorClamped(text->mInitialLetterSize);
5209 : } else {
5210 0 : MOZ_ASSERT_UNREACHABLE("unknown unit for initial-letter");
5211 : }
5212 :
5213 242 : COMPUTE_END_RESET(TextReset, text)
5214 : }
5215 :
5216 : const void*
5217 1490 : nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
5218 : const nsRuleData* aRuleData,
5219 : GeckoStyleContext* aContext,
5220 : nsRuleNode* aHighestNode,
5221 : const RuleDetail aRuleDetail,
5222 : const RuleNodeCacheConditions aConditions)
5223 : {
5224 2980 : COMPUTE_START_INHERITED(UserInterface, ui, parentUI)
5225 :
5226 : // cursor: enum, url, inherit
5227 1490 : const nsCSSValue* cursorValue = aRuleData->ValueForCursor();
5228 1490 : nsCSSUnit cursorUnit = cursorValue->GetUnit();
5229 1490 : if (cursorUnit != eCSSUnit_Null) {
5230 228 : ui->mCursorImages.Clear();
5231 :
5232 228 : if (cursorUnit == eCSSUnit_Inherit ||
5233 : cursorUnit == eCSSUnit_Unset) {
5234 0 : conditions.SetUncacheable();
5235 0 : ui->mCursor = parentUI->mCursor;
5236 0 : ui->mCursorImages = parentUI->mCursorImages;
5237 : }
5238 228 : else if (cursorUnit == eCSSUnit_Initial) {
5239 0 : ui->mCursor = NS_STYLE_CURSOR_AUTO;
5240 : }
5241 : else {
5242 : // The parser will never create a list that is *all* URL values --
5243 : // that's invalid.
5244 228 : MOZ_ASSERT(cursorUnit == eCSSUnit_List || cursorUnit == eCSSUnit_ListDep,
5245 : "unrecognized cursor unit");
5246 228 : const nsCSSValueList* list = cursorValue->GetListValue();
5247 228 : for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext) {
5248 0 : nsCSSValue::Array* arr = list->mValue.GetArrayValue();
5249 0 : nsCursorImage* item = ui->mCursorImages.AppendElement();
5250 : item->mImage =
5251 0 : CreateStyleImageRequest(aContext->PresContext(), arr->Item(0),
5252 0 : nsStyleImageRequest::Mode::Discard);
5253 0 : if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
5254 0 : item->mHaveHotspot = true;
5255 0 : item->mHotspotX = arr->Item(1).GetFloatValue();
5256 0 : item->mHotspotY = arr->Item(2).GetFloatValue();
5257 : }
5258 : }
5259 :
5260 228 : NS_ASSERTION(list, "Must have non-array value at the end");
5261 228 : NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated,
5262 : "Unexpected fallback value at end of cursor list");
5263 228 : ui->mCursor = list->mValue.GetIntValue();
5264 : }
5265 : }
5266 :
5267 : // user-input: enum, inherit, initial
5268 1490 : SetValue(*aRuleData->ValueForUserInput(),
5269 : ui->mUserInput, conditions,
5270 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
5271 1490 : parentUI->mUserInput,
5272 1490 : StyleUserInput::Auto);
5273 :
5274 : // user-modify: enum, inherit, initial
5275 1490 : SetValue(*aRuleData->ValueForUserModify(),
5276 : ui->mUserModify, conditions,
5277 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
5278 1490 : parentUI->mUserModify,
5279 1490 : StyleUserModify::ReadOnly);
5280 :
5281 : // user-focus: enum, inherit, initial
5282 1490 : SetValue(*aRuleData->ValueForUserFocus(),
5283 : ui->mUserFocus, conditions,
5284 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
5285 1490 : parentUI->mUserFocus,
5286 1490 : StyleUserFocus::None);
5287 :
5288 : // pointer-events: enum, inherit, initial
5289 1490 : SetValue(*aRuleData->ValueForPointerEvents(), ui->mPointerEvents,
5290 : conditions,
5291 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
5292 1490 : parentUI->mPointerEvents,
5293 1490 : NS_STYLE_POINTER_EVENTS_AUTO);
5294 :
5295 : // caret-color: auto, color, inherit
5296 1490 : const nsCSSValue* caretColorValue = aRuleData->ValueForCaretColor();
5297 2980 : SetComplexColor<eUnsetInherit>(*caretColorValue,
5298 : parentUI->mCaretColor,
5299 2980 : StyleComplexColor::Auto(),
5300 1490 : mPresContext,
5301 1490 : ui->mCaretColor, conditions);
5302 :
5303 2980 : COMPUTE_END_INHERITED(UserInterface, ui)
5304 : }
5305 :
5306 : const void*
5307 9 : nsRuleNode::ComputeUIResetData(void* aStartStruct,
5308 : const nsRuleData* aRuleData,
5309 : GeckoStyleContext* aContext,
5310 : nsRuleNode* aHighestNode,
5311 : const RuleDetail aRuleDetail,
5312 : const RuleNodeCacheConditions aConditions)
5313 : {
5314 18 : COMPUTE_START_RESET(UIReset, ui, parentUI)
5315 :
5316 : // user-select: enum, inherit, initial
5317 9 : SetValue(*aRuleData->ValueForUserSelect(),
5318 : ui->mUserSelect, conditions,
5319 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
5320 9 : parentUI->mUserSelect,
5321 9 : StyleUserSelect::Auto);
5322 :
5323 : // ime-mode: enum, inherit, initial
5324 9 : SetValue(*aRuleData->ValueForImeMode(),
5325 : ui->mIMEMode, conditions,
5326 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
5327 9 : parentUI->mIMEMode,
5328 9 : NS_STYLE_IME_MODE_AUTO);
5329 :
5330 : // force-broken-image-icons: integer, inherit, initial
5331 9 : SetValue(*aRuleData->ValueForForceBrokenImageIcon(),
5332 : ui->mForceBrokenImageIcon,
5333 : conditions,
5334 : SETVAL_INTEGER | SETVAL_UNSET_INITIAL,
5335 18 : parentUI->mForceBrokenImageIcon, 0);
5336 :
5337 : // -moz-window-dragging: enum, inherit, initial
5338 9 : SetValue(*aRuleData->ValueForWindowDragging(),
5339 : ui->mWindowDragging, conditions,
5340 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
5341 9 : parentUI->mWindowDragging,
5342 9 : StyleWindowDragging::Default);
5343 :
5344 : // -moz-window-shadow: enum, inherit, initial
5345 9 : SetValue(*aRuleData->ValueForWindowShadow(),
5346 : ui->mWindowShadow, conditions,
5347 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
5348 9 : parentUI->mWindowShadow,
5349 9 : NS_STYLE_WINDOW_SHADOW_DEFAULT);
5350 :
5351 : // -moz-window-opacity: factor, inherit, initial
5352 9 : SetFactor(*aRuleData->ValueForWindowOpacity(),
5353 : ui->mWindowOpacity, conditions,
5354 9 : parentUI->mWindowOpacity, 1.0f,
5355 9 : SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
5356 :
5357 : // -moz-window-transform
5358 9 : SetTransformValue(*aRuleData->ValueForWindowTransform(),
5359 : ui->mSpecifiedWindowTransform, conditions,
5360 9 : parentUI->mSpecifiedWindowTransform);
5361 :
5362 : // -moz-window-transform-origin
5363 : const nsCSSValue* windowTransformOriginValue =
5364 9 : aRuleData->ValueForWindowTransformOrigin();
5365 9 : if (windowTransformOriginValue->GetUnit() != eCSSUnit_Null) {
5366 : mozilla::DebugOnly<bool> result =
5367 0 : SetPairCoords(*windowTransformOriginValue,
5368 : ui->mWindowTransformOrigin[0],
5369 : ui->mWindowTransformOrigin[1],
5370 : parentUI->mWindowTransformOrigin[0],
5371 : parentUI->mWindowTransformOrigin[1],
5372 : SETCOORD_LPH | SETCOORD_INITIAL_HALF |
5373 : SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
5374 : SETCOORD_UNSET_INITIAL,
5375 0 : aContext, mPresContext, conditions);
5376 0 : NS_ASSERTION(result, "Malformed -moz-window-transform-origin parse!");
5377 : }
5378 :
5379 18 : COMPUTE_END_RESET(UIReset, ui)
5380 : }
5381 :
5382 : // Information about each transition or animation property that is
5383 : // constant.
5384 : struct TransitionPropInfo {
5385 : nsCSSPropertyID property;
5386 : // Location of the count of the property's computed value.
5387 : uint32_t nsStyleDisplay::* sdCount;
5388 : };
5389 :
5390 : // Each property's index in this array must match its index in the
5391 : // mutable array |transitionPropData| below.
5392 : static const TransitionPropInfo transitionPropInfo[4] = {
5393 : { eCSSProperty_transition_delay,
5394 : &nsStyleDisplay::mTransitionDelayCount },
5395 : { eCSSProperty_transition_duration,
5396 : &nsStyleDisplay::mTransitionDurationCount },
5397 : { eCSSProperty_transition_property,
5398 : &nsStyleDisplay::mTransitionPropertyCount },
5399 : { eCSSProperty_transition_timing_function,
5400 : &nsStyleDisplay::mTransitionTimingFunctionCount },
5401 : };
5402 :
5403 : // Each property's index in this array must match its index in the
5404 : // mutable array |animationPropData| below.
5405 : static const TransitionPropInfo animationPropInfo[8] = {
5406 : { eCSSProperty_animation_delay,
5407 : &nsStyleDisplay::mAnimationDelayCount },
5408 : { eCSSProperty_animation_duration,
5409 : &nsStyleDisplay::mAnimationDurationCount },
5410 : { eCSSProperty_animation_name,
5411 : &nsStyleDisplay::mAnimationNameCount },
5412 : { eCSSProperty_animation_timing_function,
5413 : &nsStyleDisplay::mAnimationTimingFunctionCount },
5414 : { eCSSProperty_animation_direction,
5415 : &nsStyleDisplay::mAnimationDirectionCount },
5416 : { eCSSProperty_animation_fill_mode,
5417 : &nsStyleDisplay::mAnimationFillModeCount },
5418 : { eCSSProperty_animation_play_state,
5419 : &nsStyleDisplay::mAnimationPlayStateCount },
5420 : { eCSSProperty_animation_iteration_count,
5421 : &nsStyleDisplay::mAnimationIterationCountCount },
5422 : };
5423 :
5424 : // Information about each transition or animation property that changes
5425 : // during ComputeDisplayData.
5426 : struct TransitionPropData {
5427 : const nsCSSValueList *list;
5428 : nsCSSUnit unit;
5429 : uint32_t num;
5430 : };
5431 :
5432 : static uint32_t
5433 1342 : CountTransitionProps(const TransitionPropInfo* aInfo,
5434 : TransitionPropData* aData,
5435 : size_t aLength,
5436 : nsStyleDisplay* aDisplay,
5437 : const nsStyleDisplay* aParentDisplay,
5438 : const nsRuleData* aRuleData,
5439 : RuleNodeCacheConditions& aConditions)
5440 : {
5441 : // The four transition properties or eight animation properties are
5442 : // stored in nsCSSDisplay in a single array for all properties. The
5443 : // number of transitions is equal to the number of items in the
5444 : // longest property's value. Properties that have fewer values than
5445 : // the longest are filled in by repeating the list. However, this
5446 : // repetition does not extend the computed value of that particular
5447 : // property (for purposes of inheritance, or, in our code, for when
5448 : // other properties are overridden by a more specific rule).
5449 :
5450 : // But actually, since the spec isn't clear yet, we'll fully compute
5451 : // all of them (so we can switch easily later), but only care about
5452 : // the ones up to the number of items for 'transition-property', per
5453 : // http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html .
5454 :
5455 : // Transitions are difficult to handle correctly because of this. For
5456 : // example, we need to handle scenarios such as:
5457 : // * a more general rule specifies transition-property: a, b, c;
5458 : // * a more specific rule overrides as transition-property: d;
5459 : //
5460 : // If only the general rule applied, we would fill in the extra
5461 : // properties (duration, delay, etc) with initial values to create 3
5462 : // fully-specified transitions. But when the more specific rule
5463 : // applies, we should only create a single transition. In order to do
5464 : // this we need to remember which properties were explicitly specified
5465 : // and which ones were just filled in with initial values to get a
5466 : // fully-specified transition, which we do by remembering the number
5467 : // of values for each property.
5468 :
5469 1342 : uint32_t numTransitions = 0;
5470 9394 : for (size_t i = 0; i < aLength; ++i) {
5471 8052 : const TransitionPropInfo& info = aInfo[i];
5472 8052 : TransitionPropData& data = aData[i];
5473 :
5474 : // cache whether any of the properties are specified as 'inherit' so
5475 : // we can use it below
5476 :
5477 8052 : const nsCSSValue& value = *aRuleData->ValueFor(info.property);
5478 8052 : data.unit = value.GetUnit();
5479 23895 : data.list = (value.GetUnit() == eCSSUnit_List ||
5480 7791 : value.GetUnit() == eCSSUnit_ListDep)
5481 8313 : ? value.GetListValue() : nullptr;
5482 :
5483 : // General algorithm to determine how many total transitions we need
5484 : // to build. For each property:
5485 : // - if there is no value specified in for the property in
5486 : // displayData, use the values from the start struct, but only if
5487 : // they were explicitly specified
5488 : // - if there is a value specified for the property in displayData:
5489 : // - if the value is 'inherit', count the number of values for
5490 : // that property are specified by the parent, but only those
5491 : // that were explicitly specified
5492 : // - otherwise, count the number of values specified in displayData
5493 :
5494 :
5495 : // calculate number of elements
5496 8052 : if (data.unit == eCSSUnit_Inherit) {
5497 0 : data.num = aParentDisplay->*(info.sdCount);
5498 0 : aConditions.SetUncacheable();
5499 8052 : } else if (data.list) {
5500 261 : data.num = ListLength(data.list);
5501 : } else {
5502 7791 : data.num = aDisplay->*(info.sdCount);
5503 : }
5504 8052 : if (data.num > numTransitions)
5505 1353 : numTransitions = data.num;
5506 : }
5507 :
5508 1342 : return numTransitions;
5509 : }
5510 :
5511 : /* static */ void
5512 65 : nsRuleNode::ComputeTimingFunction(const nsCSSValue& aValue,
5513 : nsTimingFunction& aResult)
5514 : {
5515 65 : switch (aValue.GetUnit()) {
5516 : case eCSSUnit_Enumerated:
5517 62 : aResult = nsTimingFunction(aValue.GetIntValue());
5518 62 : break;
5519 : case eCSSUnit_Cubic_Bezier:
5520 : {
5521 0 : nsCSSValue::Array* array = aValue.GetArrayValue();
5522 0 : NS_ASSERTION(array && array->Count() == 4,
5523 : "Need 4 control points");
5524 0 : aResult = nsTimingFunction(array->Item(0).GetFloatValue(),
5525 0 : array->Item(1).GetFloatValue(),
5526 0 : array->Item(2).GetFloatValue(),
5527 0 : array->Item(3).GetFloatValue());
5528 : }
5529 0 : break;
5530 : case eCSSUnit_Steps:
5531 : {
5532 3 : nsCSSValue::Array* array = aValue.GetArrayValue();
5533 3 : NS_ASSERTION(array && array->Count() == 2,
5534 : "Need 2 items");
5535 3 : NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
5536 : "unexpected first value");
5537 3 : NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
5538 : (array->Item(1).GetIntValue() ==
5539 : NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START ||
5540 : array->Item(1).GetIntValue() ==
5541 : NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END ||
5542 : array->Item(1).GetIntValue() == -1),
5543 : "unexpected second value");
5544 : nsTimingFunction::Type type =
5545 3 : (array->Item(1).GetIntValue() ==
5546 3 : NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START) ?
5547 : nsTimingFunction::Type::StepStart :
5548 3 : nsTimingFunction::Type::StepEnd;
5549 3 : aResult = nsTimingFunction(type, array->Item(0).GetIntValue());
5550 : }
5551 3 : break;
5552 : case eCSSUnit_Function:
5553 : {
5554 0 : nsCSSValue::Array* array = aValue.GetArrayValue();
5555 0 : NS_ASSERTION(array && array->Count() == 2, "Need 2 items");
5556 0 : NS_ASSERTION(array->Item(0).GetKeywordValue() == eCSSKeyword_frames,
5557 : "should be frames function");
5558 0 : NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Integer,
5559 : "unexpected frames function value");
5560 0 : aResult = nsTimingFunction(nsTimingFunction::Type::Frames,
5561 0 : array->Item(1).GetIntValue());
5562 : }
5563 0 : break;
5564 : default:
5565 0 : NS_NOTREACHED("Invalid transition property unit");
5566 : }
5567 65 : }
5568 :
5569 : static uint8_t
5570 0 : GetWillChangeBitFieldFromPropFlags(const nsCSSPropertyID& aProp)
5571 : {
5572 0 : uint8_t willChangeBitField = 0;
5573 0 : if (nsCSSProps::PropHasFlags(aProp, CSS_PROPERTY_CREATES_STACKING_CONTEXT)) {
5574 0 : willChangeBitField |= NS_STYLE_WILL_CHANGE_STACKING_CONTEXT;
5575 : }
5576 :
5577 0 : if (nsCSSProps::PropHasFlags(aProp, CSS_PROPERTY_FIXPOS_CB)) {
5578 0 : willChangeBitField |= NS_STYLE_WILL_CHANGE_FIXPOS_CB;
5579 : }
5580 :
5581 0 : if (nsCSSProps::PropHasFlags(aProp, CSS_PROPERTY_ABSPOS_CB)) {
5582 0 : willChangeBitField |= NS_STYLE_WILL_CHANGE_ABSPOS_CB;
5583 : }
5584 :
5585 0 : return willChangeBitField;
5586 : }
5587 :
5588 : const void*
5589 671 : nsRuleNode::ComputeDisplayData(void* aStartStruct,
5590 : const nsRuleData* aRuleData,
5591 : GeckoStyleContext* aContext,
5592 : nsRuleNode* aHighestNode,
5593 : const RuleDetail aRuleDetail,
5594 : const RuleNodeCacheConditions aConditions)
5595 : {
5596 1342 : COMPUTE_START_RESET(Display, display, parentDisplay)
5597 :
5598 : // We may have ended up with aStartStruct's values of mDisplay and
5599 : // mFloat, but those may not be correct if our style data overrides
5600 : // its position or float properties. Reset to mOriginalDisplay and
5601 : // mOriginalFloat; if it turns out we still need the display/floats
5602 : // adjustments, we'll do them below.
5603 671 : display->mDisplay = display->mOriginalDisplay;
5604 671 : display->mFloat = display->mOriginalFloat;
5605 :
5606 : // Each property's index in this array must match its index in the
5607 : // const array |transitionPropInfo| above.
5608 : TransitionPropData transitionPropData[4];
5609 671 : TransitionPropData& delay = transitionPropData[0];
5610 671 : TransitionPropData& duration = transitionPropData[1];
5611 671 : TransitionPropData& property = transitionPropData[2];
5612 671 : TransitionPropData& timingFunction = transitionPropData[3];
5613 :
5614 : #define FOR_ALL_TRANSITION_PROPS(var_) \
5615 : for (uint32_t var_ = 0; var_ < 4; ++var_)
5616 :
5617 : // CSS Transitions
5618 : uint32_t numTransitions =
5619 671 : CountTransitionProps(transitionPropInfo, transitionPropData,
5620 : ArrayLength(transitionPropData),
5621 : display, parentDisplay, aRuleData,
5622 671 : conditions);
5623 :
5624 671 : display->mTransitions.SetLengthNonZero(numTransitions);
5625 :
5626 3355 : FOR_ALL_TRANSITION_PROPS(p) {
5627 2684 : const TransitionPropInfo& i = transitionPropInfo[p];
5628 2684 : TransitionPropData& d = transitionPropData[p];
5629 :
5630 2684 : display->*(i.sdCount) = d.num;
5631 : }
5632 :
5633 : // Fill in the transitions we just allocated with the appropriate values.
5634 1372 : for (uint32_t i = 0; i < numTransitions; ++i) {
5635 701 : StyleTransition *transition = &display->mTransitions[i];
5636 :
5637 701 : if (i >= delay.num) {
5638 21 : MOZ_ASSERT(delay.num, "delay.num must be greater than 0");
5639 21 : transition->SetDelay(display->mTransitions[i % delay.num].GetDelay());
5640 680 : } else if (delay.unit == eCSSUnit_Inherit) {
5641 : // FIXME (Bug 522599) (for all transition properties): write a test that
5642 : // detects when this was wrong for i >= delay.num if parent had
5643 : // count for this property not equal to length
5644 0 : MOZ_ASSERT(i < parentDisplay->mTransitionDelayCount,
5645 : "delay.num computed incorrectly");
5646 0 : MOZ_ASSERT(!conditions.Cacheable(),
5647 : "should have made conditions.Cacheable() false above");
5648 0 : transition->SetDelay(parentDisplay->mTransitions[i].GetDelay());
5649 1360 : } else if (delay.unit == eCSSUnit_Initial ||
5650 680 : delay.unit == eCSSUnit_Unset) {
5651 0 : transition->SetDelay(0.0);
5652 680 : } else if (delay.list) {
5653 58 : switch (delay.list->mValue.GetUnit()) {
5654 : case eCSSUnit_Seconds:
5655 36 : transition->SetDelay(PR_MSEC_PER_SEC *
5656 72 : delay.list->mValue.GetFloatValue());
5657 36 : break;
5658 : case eCSSUnit_Milliseconds:
5659 22 : transition->SetDelay(delay.list->mValue.GetFloatValue());
5660 22 : break;
5661 : default:
5662 0 : NS_NOTREACHED("Invalid delay unit");
5663 : }
5664 : }
5665 :
5666 701 : if (i >= duration.num) {
5667 21 : MOZ_ASSERT(duration.num, "duration.num must be greater than 0");
5668 21 : transition->SetDuration(
5669 42 : display->mTransitions[i % duration.num].GetDuration());
5670 680 : } else if (duration.unit == eCSSUnit_Inherit) {
5671 0 : MOZ_ASSERT(i < parentDisplay->mTransitionDurationCount,
5672 : "duration.num computed incorrectly");
5673 0 : MOZ_ASSERT(!conditions.Cacheable(),
5674 : "should have made conditions.Cacheable() false above");
5675 0 : transition->SetDuration(parentDisplay->mTransitions[i].GetDuration());
5676 1360 : } else if (duration.unit == eCSSUnit_Initial ||
5677 680 : duration.unit == eCSSUnit_Unset) {
5678 0 : transition->SetDuration(0.0);
5679 680 : } else if (duration.list) {
5680 69 : switch (duration.list->mValue.GetUnit()) {
5681 : case eCSSUnit_Seconds:
5682 30 : transition->SetDuration(PR_MSEC_PER_SEC *
5683 60 : duration.list->mValue.GetFloatValue());
5684 30 : break;
5685 : case eCSSUnit_Milliseconds:
5686 39 : transition->SetDuration(duration.list->mValue.GetFloatValue());
5687 39 : break;
5688 : default:
5689 0 : NS_NOTREACHED("Invalid duration unit");
5690 : }
5691 : }
5692 :
5693 701 : if (i >= property.num) {
5694 0 : MOZ_ASSERT(property.num, "property.num must be greater than 0");
5695 0 : transition->CopyPropertyFrom(display->mTransitions[i % property.num]);
5696 701 : } else if (property.unit == eCSSUnit_Inherit) {
5697 0 : MOZ_ASSERT(i < parentDisplay->mTransitionPropertyCount,
5698 : "property.num computed incorrectly");
5699 0 : MOZ_ASSERT(!conditions.Cacheable(),
5700 : "should have made conditions.Cacheable() false above");
5701 0 : transition->CopyPropertyFrom(parentDisplay->mTransitions[i]);
5702 1402 : } else if (property.unit == eCSSUnit_Initial ||
5703 701 : property.unit == eCSSUnit_Unset) {
5704 0 : transition->SetProperty(eCSSPropertyExtra_all_properties);
5705 701 : } else if (property.unit == eCSSUnit_None) {
5706 3 : transition->SetProperty(eCSSPropertyExtra_no_properties);
5707 698 : } else if (property.list) {
5708 87 : const nsCSSValue &val = property.list->mValue;
5709 :
5710 87 : if (val.GetUnit() == eCSSUnit_Ident) {
5711 : nsDependentString
5712 174 : propertyStr(property.list->mValue.GetStringBufferValue());
5713 : nsCSSPropertyID prop =
5714 : nsCSSProps::LookupProperty(propertyStr,
5715 87 : CSSEnabledState::eForAllContent);
5716 87 : if (prop == eCSSProperty_UNKNOWN ||
5717 : prop == eCSSPropertyExtra_variable) {
5718 0 : transition->SetUnknownProperty(prop, propertyStr);
5719 : } else {
5720 87 : transition->SetProperty(prop);
5721 : }
5722 : } else {
5723 0 : MOZ_ASSERT(val.GetUnit() == eCSSUnit_All,
5724 : "Invalid transition property unit");
5725 0 : transition->SetProperty(eCSSPropertyExtra_all_properties);
5726 : }
5727 : }
5728 :
5729 701 : if (i >= timingFunction.num) {
5730 21 : MOZ_ASSERT(timingFunction.num,
5731 : "timingFunction.num must be greater than 0");
5732 21 : transition->SetTimingFunction(
5733 42 : display->mTransitions[i % timingFunction.num].GetTimingFunction());
5734 680 : } else if (timingFunction.unit == eCSSUnit_Inherit) {
5735 0 : MOZ_ASSERT(i < parentDisplay->mTransitionTimingFunctionCount,
5736 : "timingFunction.num computed incorrectly");
5737 0 : MOZ_ASSERT(!conditions.Cacheable(),
5738 : "should have made conditions.Cacheable() false above");
5739 0 : transition->SetTimingFunction(
5740 0 : parentDisplay->mTransitions[i].GetTimingFunction());
5741 1360 : } else if (timingFunction.unit == eCSSUnit_Initial ||
5742 680 : timingFunction.unit == eCSSUnit_Unset) {
5743 : transition->SetTimingFunction(
5744 0 : nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
5745 680 : } else if (timingFunction.list) {
5746 58 : ComputeTimingFunction(timingFunction.list->mValue,
5747 58 : transition->TimingFunctionSlot());
5748 : }
5749 :
5750 3505 : FOR_ALL_TRANSITION_PROPS(p) {
5751 2804 : const TransitionPropInfo& info = transitionPropInfo[p];
5752 2804 : TransitionPropData& d = transitionPropData[p];
5753 :
5754 : // if we're at the end of the list, start at the beginning and repeat
5755 : // until we're out of transitions to populate
5756 2804 : if (d.list) {
5757 529 : d.list = d.list->mNext ? d.list->mNext :
5758 236 : aRuleData->ValueFor(info.property)->GetListValue();
5759 : }
5760 : }
5761 : }
5762 :
5763 : // Each property's index in this array must match its index in the
5764 : // const array |animationPropInfo| above.
5765 : TransitionPropData animationPropData[8];
5766 671 : TransitionPropData& animDelay = animationPropData[0];
5767 671 : TransitionPropData& animDuration = animationPropData[1];
5768 671 : TransitionPropData& animName = animationPropData[2];
5769 671 : TransitionPropData& animTimingFunction = animationPropData[3];
5770 671 : TransitionPropData& animDirection = animationPropData[4];
5771 671 : TransitionPropData& animFillMode = animationPropData[5];
5772 671 : TransitionPropData& animPlayState = animationPropData[6];
5773 671 : TransitionPropData& animIterationCount = animationPropData[7];
5774 :
5775 : #define FOR_ALL_ANIMATION_PROPS(var_) \
5776 : for (uint32_t var_ = 0; var_ < 8; ++var_)
5777 :
5778 : // CSS Animations.
5779 :
5780 : uint32_t numAnimations =
5781 671 : CountTransitionProps(animationPropInfo, animationPropData,
5782 : ArrayLength(animationPropData),
5783 : display, parentDisplay, aRuleData,
5784 671 : conditions);
5785 :
5786 671 : display->mAnimations.SetLengthNonZero(numAnimations);
5787 :
5788 6039 : FOR_ALL_ANIMATION_PROPS(p) {
5789 5368 : const TransitionPropInfo& i = animationPropInfo[p];
5790 5368 : TransitionPropData& d = animationPropData[p];
5791 :
5792 5368 : display->*(i.sdCount) = d.num;
5793 : }
5794 :
5795 : // Fill in the animations we just allocated with the appropriate values.
5796 1342 : for (uint32_t i = 0; i < numAnimations; ++i) {
5797 671 : StyleAnimation *animation = &display->mAnimations[i];
5798 :
5799 671 : if (i >= animDelay.num) {
5800 0 : MOZ_ASSERT(animDelay.num, "animDelay.num must be greater than 0");
5801 0 : animation->SetDelay(display->mAnimations[i % animDelay.num].GetDelay());
5802 671 : } else if (animDelay.unit == eCSSUnit_Inherit) {
5803 : // FIXME (Bug 522599) (for all animation properties): write a test that
5804 : // detects when this was wrong for i >= animDelay.num if parent had
5805 : // count for this property not equal to length
5806 0 : MOZ_ASSERT(i < parentDisplay->mAnimationDelayCount,
5807 : "animDelay.num computed incorrectly");
5808 0 : MOZ_ASSERT(!conditions.Cacheable(),
5809 : "should have made conditions.Cacheable() false above");
5810 0 : animation->SetDelay(parentDisplay->mAnimations[i].GetDelay());
5811 1342 : } else if (animDelay.unit == eCSSUnit_Initial ||
5812 671 : animDelay.unit == eCSSUnit_Unset) {
5813 0 : animation->SetDelay(0.0);
5814 671 : } else if (animDelay.list) {
5815 4 : switch (animDelay.list->mValue.GetUnit()) {
5816 : case eCSSUnit_Seconds:
5817 4 : animation->SetDelay(PR_MSEC_PER_SEC *
5818 8 : animDelay.list->mValue.GetFloatValue());
5819 4 : break;
5820 : case eCSSUnit_Milliseconds:
5821 0 : animation->SetDelay(animDelay.list->mValue.GetFloatValue());
5822 0 : break;
5823 : default:
5824 0 : NS_NOTREACHED("Invalid delay unit");
5825 : }
5826 : }
5827 :
5828 671 : if (i >= animDuration.num) {
5829 0 : MOZ_ASSERT(animDuration.num, "animDuration.num must be greater than 0");
5830 0 : animation->SetDuration(
5831 0 : display->mAnimations[i % animDuration.num].GetDuration());
5832 671 : } else if (animDuration.unit == eCSSUnit_Inherit) {
5833 0 : MOZ_ASSERT(i < parentDisplay->mAnimationDurationCount,
5834 : "animDuration.num computed incorrectly");
5835 0 : MOZ_ASSERT(!conditions.Cacheable(),
5836 : "should have made conditions.Cacheable() false above");
5837 0 : animation->SetDuration(parentDisplay->mAnimations[i].GetDuration());
5838 1342 : } else if (animDuration.unit == eCSSUnit_Initial ||
5839 671 : animDuration.unit == eCSSUnit_Unset) {
5840 0 : animation->SetDuration(0.0);
5841 671 : } else if (animDuration.list) {
5842 7 : switch (animDuration.list->mValue.GetUnit()) {
5843 : case eCSSUnit_Seconds:
5844 4 : animation->SetDuration(PR_MSEC_PER_SEC *
5845 8 : animDuration.list->mValue.GetFloatValue());
5846 4 : break;
5847 : case eCSSUnit_Milliseconds:
5848 3 : animation->SetDuration(animDuration.list->mValue.GetFloatValue());
5849 3 : break;
5850 : default:
5851 0 : NS_NOTREACHED("Invalid duration unit");
5852 : }
5853 : }
5854 :
5855 671 : if (i >= animName.num) {
5856 0 : MOZ_ASSERT(animName.num, "animName.num must be greater than 0");
5857 0 : animation->SetName(display->mAnimations[i % animName.num].GetName());
5858 671 : } else if (animName.unit == eCSSUnit_Inherit) {
5859 0 : MOZ_ASSERT(i < parentDisplay->mAnimationNameCount,
5860 : "animName.num computed incorrectly");
5861 0 : MOZ_ASSERT(!conditions.Cacheable(),
5862 : "should have made conditions.Cacheable() false above");
5863 0 : animation->SetName(parentDisplay->mAnimations[i].GetName());
5864 1342 : } else if (animName.unit == eCSSUnit_Initial ||
5865 671 : animName.unit == eCSSUnit_Unset) {
5866 0 : animation->SetName(EmptyString());
5867 671 : } else if (animName.list) {
5868 4 : switch (animName.list->mValue.GetUnit()) {
5869 : case eCSSUnit_String:
5870 : case eCSSUnit_Ident: {
5871 : nsDependentString
5872 8 : nameStr(animName.list->mValue.GetStringBufferValue());
5873 4 : animation->SetName(nameStr);
5874 4 : break;
5875 : }
5876 : case eCSSUnit_None: {
5877 0 : animation->SetName(EmptyString());
5878 0 : break;
5879 : }
5880 : default:
5881 0 : MOZ_ASSERT(false, "Invalid animation-name unit");
5882 : }
5883 : }
5884 :
5885 671 : if (i >= animTimingFunction.num) {
5886 0 : MOZ_ASSERT(animTimingFunction.num,
5887 : "animTimingFunction.num must be greater than 0");
5888 0 : animation->SetTimingFunction(
5889 0 : display->mAnimations[i % animTimingFunction.num].GetTimingFunction());
5890 671 : } else if (animTimingFunction.unit == eCSSUnit_Inherit) {
5891 0 : MOZ_ASSERT(i < parentDisplay->mAnimationTimingFunctionCount,
5892 : "animTimingFunction.num computed incorrectly");
5893 0 : MOZ_ASSERT(!conditions.Cacheable(),
5894 : "should have made conditions.Cacheable() false above");
5895 0 : animation->SetTimingFunction(
5896 0 : parentDisplay->mAnimations[i].GetTimingFunction());
5897 1342 : } else if (animTimingFunction.unit == eCSSUnit_Initial ||
5898 671 : animTimingFunction.unit == eCSSUnit_Unset) {
5899 : animation->SetTimingFunction(
5900 0 : nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
5901 671 : } else if (animTimingFunction.list) {
5902 7 : ComputeTimingFunction(animTimingFunction.list->mValue,
5903 7 : animation->TimingFunctionSlot());
5904 : }
5905 :
5906 671 : if (i >= animDirection.num) {
5907 0 : MOZ_ASSERT(animDirection.num,
5908 : "animDirection.num must be greater than 0");
5909 0 : animation->SetDirection(display->mAnimations[i % animDirection.num].GetDirection());
5910 671 : } else if (animDirection.unit == eCSSUnit_Inherit) {
5911 0 : MOZ_ASSERT(i < parentDisplay->mAnimationDirectionCount,
5912 : "animDirection.num computed incorrectly");
5913 0 : MOZ_ASSERT(!conditions.Cacheable(),
5914 : "should have made conditions.Cacheable() false above");
5915 0 : animation->SetDirection(parentDisplay->mAnimations[i].GetDirection());
5916 1342 : } else if (animDirection.unit == eCSSUnit_Initial ||
5917 671 : animDirection.unit == eCSSUnit_Unset) {
5918 0 : animation->SetDirection(dom::PlaybackDirection::Normal);
5919 671 : } else if (animDirection.list) {
5920 4 : MOZ_ASSERT(animDirection.list->mValue.GetUnit() == eCSSUnit_Enumerated,
5921 : "Invalid animation-direction unit");
5922 :
5923 4 : animation->SetDirection(
5924 8 : static_cast<dom::PlaybackDirection>(animDirection.list->mValue.GetIntValue()));
5925 : }
5926 :
5927 671 : if (i >= animFillMode.num) {
5928 0 : MOZ_ASSERT(animFillMode.num, "animFillMode.num must be greater than 0");
5929 0 : animation->SetFillMode(display->mAnimations[i % animFillMode.num].GetFillMode());
5930 671 : } else if (animFillMode.unit == eCSSUnit_Inherit) {
5931 0 : MOZ_ASSERT(i < parentDisplay->mAnimationFillModeCount,
5932 : "animFillMode.num computed incorrectly");
5933 0 : MOZ_ASSERT(!conditions.Cacheable(),
5934 : "should have made conditions.Cacheable() false above");
5935 0 : animation->SetFillMode(parentDisplay->mAnimations[i].GetFillMode());
5936 1342 : } else if (animFillMode.unit == eCSSUnit_Initial ||
5937 671 : animFillMode.unit == eCSSUnit_Unset) {
5938 0 : animation->SetFillMode(dom::FillMode::None);
5939 671 : } else if (animFillMode.list) {
5940 8 : MOZ_ASSERT(animFillMode.list->mValue.GetUnit() == eCSSUnit_Enumerated,
5941 : "Invalid animation-fill-mode unit");
5942 :
5943 8 : animation->SetFillMode(
5944 16 : static_cast<dom::FillMode>(animFillMode.list->mValue.GetIntValue()));
5945 : }
5946 :
5947 671 : if (i >= animPlayState.num) {
5948 0 : MOZ_ASSERT(animPlayState.num,
5949 : "animPlayState.num must be greater than 0");
5950 0 : animation->SetPlayState(display->mAnimations[i % animPlayState.num].GetPlayState());
5951 671 : } else if (animPlayState.unit == eCSSUnit_Inherit) {
5952 0 : MOZ_ASSERT(i < parentDisplay->mAnimationPlayStateCount,
5953 : "animPlayState.num computed incorrectly");
5954 0 : MOZ_ASSERT(!conditions.Cacheable(),
5955 : "should have made conditions.Cacheable() false above");
5956 0 : animation->SetPlayState(parentDisplay->mAnimations[i].GetPlayState());
5957 1342 : } else if (animPlayState.unit == eCSSUnit_Initial ||
5958 671 : animPlayState.unit == eCSSUnit_Unset) {
5959 0 : animation->SetPlayState(NS_STYLE_ANIMATION_PLAY_STATE_RUNNING);
5960 671 : } else if (animPlayState.list) {
5961 4 : MOZ_ASSERT(animPlayState.list->mValue.GetUnit() == eCSSUnit_Enumerated,
5962 : "Invalid animation-play-state unit");
5963 :
5964 4 : animation->SetPlayState(animPlayState.list->mValue.GetIntValue());
5965 : }
5966 :
5967 671 : if (i >= animIterationCount.num) {
5968 0 : MOZ_ASSERT(animIterationCount.num,
5969 : "animIterationCount.num must be greater than 0");
5970 0 : animation->SetIterationCount(display->mAnimations[i % animIterationCount.num].GetIterationCount());
5971 671 : } else if (animIterationCount.unit == eCSSUnit_Inherit) {
5972 0 : MOZ_ASSERT(i < parentDisplay->mAnimationIterationCountCount,
5973 : "animIterationCount.num computed incorrectly");
5974 0 : MOZ_ASSERT(!conditions.Cacheable(),
5975 : "should have made conditions.Cacheable() false above");
5976 0 : animation->SetIterationCount(parentDisplay->mAnimations[i].GetIterationCount());
5977 1342 : } else if (animIterationCount.unit == eCSSUnit_Initial ||
5978 671 : animIterationCount.unit == eCSSUnit_Unset) {
5979 0 : animation->SetIterationCount(1.0f);
5980 671 : } else if (animIterationCount.list) {
5981 8 : switch (animIterationCount.list->mValue.GetUnit()) {
5982 : case eCSSUnit_Enumerated:
5983 4 : MOZ_ASSERT(animIterationCount.list->mValue.GetIntValue() ==
5984 : NS_STYLE_ANIMATION_ITERATION_COUNT_INFINITE,
5985 : "unexpected value");
5986 4 : animation->SetIterationCount(NS_IEEEPositiveInfinity());
5987 4 : break;
5988 : case eCSSUnit_Number:
5989 4 : animation->SetIterationCount(
5990 8 : animIterationCount.list->mValue.GetFloatValue());
5991 4 : break;
5992 : default:
5993 0 : MOZ_ASSERT(false,
5994 : "unexpected animation-iteration-count unit");
5995 : }
5996 : }
5997 :
5998 6039 : FOR_ALL_ANIMATION_PROPS(p) {
5999 5368 : const TransitionPropInfo& info = animationPropInfo[p];
6000 5368 : TransitionPropData& d = animationPropData[p];
6001 :
6002 : // if we're at the end of the list, start at the beginning and repeat
6003 : // until we're out of animations to populate
6004 5368 : if (d.list) {
6005 92 : d.list = d.list->mNext ? d.list->mNext :
6006 46 : aRuleData->ValueFor(info.property)->GetListValue();
6007 : }
6008 : }
6009 : }
6010 :
6011 : // display: enum, inherit, initial
6012 671 : SetValue(*aRuleData->ValueForDisplay(), display->mDisplay, conditions,
6013 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6014 671 : parentDisplay->mDisplay,
6015 671 : StyleDisplay::Inline);
6016 :
6017 : // contain: none, enum, inherit, initial
6018 671 : SetValue(*aRuleData->ValueForContain(), display->mContain, conditions,
6019 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6020 671 : parentDisplay->mContain,
6021 : NS_STYLE_CONTAIN_NONE, Unused,
6022 671 : NS_STYLE_CONTAIN_NONE, Unused, Unused);
6023 :
6024 : // scroll-behavior: enum, inherit, initial
6025 671 : SetValue(*aRuleData->ValueForScrollBehavior(), display->mScrollBehavior,
6026 : conditions,
6027 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6028 1342 : parentDisplay->mScrollBehavior, NS_STYLE_SCROLL_BEHAVIOR_AUTO);
6029 :
6030 : // scroll-snap-type-x: none, enum, inherit, initial
6031 671 : SetValue(*aRuleData->ValueForScrollSnapTypeX(), display->mScrollSnapTypeX,
6032 : conditions,
6033 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6034 1342 : parentDisplay->mScrollSnapTypeX, NS_STYLE_SCROLL_SNAP_TYPE_NONE);
6035 :
6036 : // scroll-snap-type-y: none, enum, inherit, initial
6037 671 : SetValue(*aRuleData->ValueForScrollSnapTypeY(), display->mScrollSnapTypeY,
6038 : conditions,
6039 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6040 1342 : parentDisplay->mScrollSnapTypeY, NS_STYLE_SCROLL_SNAP_TYPE_NONE);
6041 :
6042 : // scroll-snap-points-x: none, inherit, initial
6043 671 : const nsCSSValue& scrollSnapPointsX = *aRuleData->ValueForScrollSnapPointsX();
6044 671 : switch (scrollSnapPointsX.GetUnit()) {
6045 : case eCSSUnit_Null:
6046 671 : break;
6047 : case eCSSUnit_Initial:
6048 : case eCSSUnit_Unset:
6049 : case eCSSUnit_None:
6050 0 : display->mScrollSnapPointsX.SetNoneValue();
6051 0 : break;
6052 : case eCSSUnit_Inherit:
6053 0 : display->mScrollSnapPointsX = parentDisplay->mScrollSnapPointsX;
6054 0 : conditions.SetUncacheable();
6055 0 : break;
6056 : case eCSSUnit_Function: {
6057 0 : nsCSSValue::Array* func = scrollSnapPointsX.GetArrayValue();
6058 0 : NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_repeat,
6059 : "Expected repeat(), got another function name");
6060 0 : nsStyleCoord coord;
6061 0 : if (SetCoord(func->Item(1), coord, nsStyleCoord(),
6062 : SETCOORD_LP | SETCOORD_STORE_CALC |
6063 : SETCOORD_CALC_CLAMP_NONNEGATIVE,
6064 0 : aContext, mPresContext, conditions)) {
6065 0 : NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
6066 : coord.GetUnit() == eStyleUnit_Percent ||
6067 : coord.GetUnit() == eStyleUnit_Calc,
6068 : "unexpected unit");
6069 0 : display->mScrollSnapPointsX = coord;
6070 : }
6071 0 : break;
6072 : }
6073 : default:
6074 0 : NS_NOTREACHED("unexpected unit");
6075 : }
6076 :
6077 : // scroll-snap-points-y: none, inherit, initial
6078 671 : const nsCSSValue& scrollSnapPointsY = *aRuleData->ValueForScrollSnapPointsY();
6079 671 : switch (scrollSnapPointsY.GetUnit()) {
6080 : case eCSSUnit_Null:
6081 671 : break;
6082 : case eCSSUnit_Initial:
6083 : case eCSSUnit_Unset:
6084 : case eCSSUnit_None:
6085 0 : display->mScrollSnapPointsY.SetNoneValue();
6086 0 : break;
6087 : case eCSSUnit_Inherit:
6088 0 : display->mScrollSnapPointsY = parentDisplay->mScrollSnapPointsY;
6089 0 : conditions.SetUncacheable();
6090 0 : break;
6091 : case eCSSUnit_Function: {
6092 0 : nsCSSValue::Array* func = scrollSnapPointsY.GetArrayValue();
6093 0 : NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_repeat,
6094 : "Expected repeat(), got another function name");
6095 0 : nsStyleCoord coord;
6096 0 : if (SetCoord(func->Item(1), coord, nsStyleCoord(),
6097 : SETCOORD_LP | SETCOORD_STORE_CALC |
6098 : SETCOORD_CALC_CLAMP_NONNEGATIVE,
6099 0 : aContext, mPresContext, conditions)) {
6100 0 : NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
6101 : coord.GetUnit() == eStyleUnit_Percent ||
6102 : coord.GetUnit() == eStyleUnit_Calc,
6103 : "unexpected unit");
6104 0 : display->mScrollSnapPointsY = coord;
6105 : }
6106 0 : break;
6107 : }
6108 : default:
6109 0 : NS_NOTREACHED("unexpected unit");
6110 : }
6111 :
6112 : // scroll-snap-destination: inherit, initial
6113 671 : const nsCSSValue& snapDestination = *aRuleData->ValueForScrollSnapDestination();
6114 671 : switch (snapDestination.GetUnit()) {
6115 : case eCSSUnit_Null:
6116 671 : break;
6117 : case eCSSUnit_Initial:
6118 : case eCSSUnit_Unset:
6119 0 : display->mScrollSnapDestination.SetInitialZeroValues();
6120 0 : break;
6121 : case eCSSUnit_Inherit:
6122 0 : display->mScrollSnapDestination = parentDisplay->mScrollSnapDestination;
6123 0 : conditions.SetUncacheable();
6124 0 : break;
6125 : default: {
6126 0 : ComputePositionValue(aContext, snapDestination,
6127 0 : display->mScrollSnapDestination, conditions);
6128 : }
6129 : }
6130 :
6131 : // scroll-snap-coordinate: none, inherit, initial
6132 671 : const nsCSSValue& snapCoordinate = *aRuleData->ValueForScrollSnapCoordinate();
6133 671 : switch (snapCoordinate.GetUnit()) {
6134 : case eCSSUnit_Null:
6135 671 : break;
6136 : case eCSSUnit_Initial:
6137 : case eCSSUnit_Unset:
6138 : case eCSSUnit_None:
6139 : // Unset and Initial is none, indicated by an empty array
6140 0 : display->mScrollSnapCoordinate.Clear();
6141 0 : break;
6142 : case eCSSUnit_Inherit:
6143 0 : display->mScrollSnapCoordinate = parentDisplay->mScrollSnapCoordinate;
6144 0 : conditions.SetUncacheable();
6145 0 : break;
6146 : case eCSSUnit_List: {
6147 0 : display->mScrollSnapCoordinate.Clear();
6148 0 : const nsCSSValueList* item = snapCoordinate.GetListValue();
6149 0 : do {
6150 0 : NS_ASSERTION(item->mValue.GetUnit() != eCSSUnit_Null &&
6151 : item->mValue.GetUnit() != eCSSUnit_Inherit &&
6152 : item->mValue.GetUnit() != eCSSUnit_Initial &&
6153 : item->mValue.GetUnit() != eCSSUnit_Unset,
6154 : "unexpected unit");
6155 0 : Position* pos = display->mScrollSnapCoordinate.AppendElement();
6156 0 : ComputePositionValue(aContext, item->mValue, *pos, conditions);
6157 0 : item = item->mNext;
6158 0 : } while(item);
6159 0 : break;
6160 : }
6161 : default:
6162 0 : NS_NOTREACHED("unexpected unit");
6163 : }
6164 :
6165 : // isolation: enum, inherit, initial
6166 671 : SetValue(*aRuleData->ValueForIsolation(), display->mIsolation,
6167 : conditions,
6168 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6169 1342 : parentDisplay->mIsolation, NS_STYLE_ISOLATION_AUTO);
6170 :
6171 : // -moz-top-layer: enum, inherit, initial
6172 671 : SetValue(*aRuleData->ValueForTopLayer(), display->mTopLayer,
6173 : conditions,
6174 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6175 1342 : parentDisplay->mTopLayer, NS_STYLE_TOP_LAYER_NONE);
6176 :
6177 : // Backup original display value for calculation of a hypothetical
6178 : // box (CSS2 10.6.4/10.6.5), in addition to getting our style data right later.
6179 : // See ReflowInput::CalculateHypotheticalBox
6180 671 : display->mOriginalDisplay = display->mDisplay;
6181 :
6182 : // appearance: enum, inherit, initial
6183 671 : SetValue(*aRuleData->ValueForAppearance(),
6184 : display->mAppearance, conditions,
6185 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6186 671 : parentDisplay->mAppearance,
6187 671 : NS_THEME_NONE);
6188 :
6189 : // binding: url, none, inherit
6190 671 : const nsCSSValue* bindingValue = aRuleData->ValueForBinding();
6191 671 : if (eCSSUnit_URL == bindingValue->GetUnit()) {
6192 239 : mozilla::css::URLValue* url = bindingValue->GetURLStructValue();
6193 239 : NS_ASSERTION(url, "What's going on here?");
6194 239 : display->mBinding.Set(url);
6195 : }
6196 1267 : else if (eCSSUnit_None == bindingValue->GetUnit() ||
6197 835 : eCSSUnit_Initial == bindingValue->GetUnit() ||
6198 403 : eCSSUnit_Unset == bindingValue->GetUnit()) {
6199 29 : display->mBinding.Set(nullptr);
6200 : }
6201 403 : else if (eCSSUnit_Inherit == bindingValue->GetUnit()) {
6202 0 : conditions.SetUncacheable();
6203 0 : display->mBinding.Set(parentDisplay->mBinding);
6204 : }
6205 :
6206 : // position: enum, inherit, initial
6207 671 : SetValue(*aRuleData->ValueForPosition(), display->mPosition, conditions,
6208 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6209 671 : parentDisplay->mPosition,
6210 671 : NS_STYLE_POSITION_STATIC);
6211 : // If an element is put in the top layer, while it is not absolutely
6212 : // positioned, the position value should be computed to 'absolute' per
6213 : // the Fullscreen API spec.
6214 676 : if (display->mTopLayer != NS_STYLE_TOP_LAYER_NONE &&
6215 5 : !display->IsAbsolutelyPositionedStyle()) {
6216 0 : display->mPosition = NS_STYLE_POSITION_ABSOLUTE;
6217 : // We cannot cache this struct because otherwise it may be used as
6218 : // an aStartStruct for some other elements.
6219 0 : conditions.SetUncacheable();
6220 : }
6221 :
6222 : // clear: enum, inherit, initial
6223 671 : SetValue(*aRuleData->ValueForClear(), display->mBreakType, conditions,
6224 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6225 671 : parentDisplay->mBreakType,
6226 671 : StyleClear::None);
6227 :
6228 : // temp fix for bug 24000
6229 : // Map 'auto' and 'avoid' to false, and 'always', 'left', and
6230 : // 'right' to true.
6231 : // "A conforming user agent may interpret the values 'left' and
6232 : // 'right' as 'always'." - CSS2.1, section 13.3.1
6233 671 : const nsCSSValue* breakBeforeValue = aRuleData->ValueForPageBreakBefore();
6234 671 : if (eCSSUnit_Enumerated == breakBeforeValue->GetUnit()) {
6235 0 : display->mBreakBefore =
6236 0 : (NS_STYLE_PAGE_BREAK_AVOID != breakBeforeValue->GetIntValue() &&
6237 0 : NS_STYLE_PAGE_BREAK_AUTO != breakBeforeValue->GetIntValue());
6238 : }
6239 1342 : else if (eCSSUnit_Initial == breakBeforeValue->GetUnit() ||
6240 671 : eCSSUnit_Unset == breakBeforeValue->GetUnit()) {
6241 0 : display->mBreakBefore = false;
6242 : }
6243 671 : else if (eCSSUnit_Inherit == breakBeforeValue->GetUnit()) {
6244 0 : conditions.SetUncacheable();
6245 0 : display->mBreakBefore = parentDisplay->mBreakBefore;
6246 : }
6247 :
6248 671 : const nsCSSValue* breakAfterValue = aRuleData->ValueForPageBreakAfter();
6249 671 : if (eCSSUnit_Enumerated == breakAfterValue->GetUnit()) {
6250 0 : display->mBreakAfter =
6251 0 : (NS_STYLE_PAGE_BREAK_AVOID != breakAfterValue->GetIntValue() &&
6252 0 : NS_STYLE_PAGE_BREAK_AUTO != breakAfterValue->GetIntValue());
6253 : }
6254 1342 : else if (eCSSUnit_Initial == breakAfterValue->GetUnit() ||
6255 671 : eCSSUnit_Unset == breakAfterValue->GetUnit()) {
6256 0 : display->mBreakAfter = false;
6257 : }
6258 671 : else if (eCSSUnit_Inherit == breakAfterValue->GetUnit()) {
6259 0 : conditions.SetUncacheable();
6260 0 : display->mBreakAfter = parentDisplay->mBreakAfter;
6261 : }
6262 : // end temp fix
6263 :
6264 : // page-break-inside: enum, inherit, initial
6265 671 : SetValue(*aRuleData->ValueForPageBreakInside(),
6266 : display->mBreakInside, conditions,
6267 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6268 671 : parentDisplay->mBreakInside,
6269 671 : NS_STYLE_PAGE_BREAK_AUTO);
6270 :
6271 : // touch-action: none, auto, enum, inherit, initial
6272 671 : SetValue(*aRuleData->ValueForTouchAction(), display->mTouchAction,
6273 : conditions,
6274 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6275 671 : parentDisplay->mTouchAction,
6276 : /* initial */ NS_STYLE_TOUCH_ACTION_AUTO,
6277 : /* auto */ NS_STYLE_TOUCH_ACTION_AUTO,
6278 671 : /* none */ NS_STYLE_TOUCH_ACTION_NONE, Unused, Unused);
6279 :
6280 : // float: enum, inherit, initial
6281 671 : SetValue(*aRuleData->ValueForFloat(),
6282 : display->mFloat, conditions,
6283 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6284 671 : parentDisplay->mFloat,
6285 671 : StyleFloat::None);
6286 : // Save mFloat in mOriginalFloat in case we need it later
6287 671 : display->mOriginalFloat = display->mFloat;
6288 :
6289 : // overflow-x: enum, inherit, initial
6290 671 : SetValue(*aRuleData->ValueForOverflowX(),
6291 : display->mOverflowX, conditions,
6292 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6293 671 : parentDisplay->mOverflowX,
6294 671 : NS_STYLE_OVERFLOW_VISIBLE);
6295 :
6296 : // overflow-y: enum, inherit, initial
6297 671 : SetValue(*aRuleData->ValueForOverflowY(),
6298 : display->mOverflowY, conditions,
6299 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6300 671 : parentDisplay->mOverflowY,
6301 671 : NS_STYLE_OVERFLOW_VISIBLE);
6302 :
6303 : // CSS3 overflow-x and overflow-y require some fixup as well in some
6304 : // cases. NS_STYLE_OVERFLOW_VISIBLE and NS_STYLE_OVERFLOW_CLIP are
6305 : // meaningful only when used in both dimensions.
6306 681 : if (display->mOverflowX != display->mOverflowY &&
6307 20 : (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE ||
6308 20 : display->mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
6309 20 : display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE ||
6310 10 : display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)) {
6311 : // We can't store in the rule tree since a more specific rule might
6312 : // change these conditions.
6313 0 : conditions.SetUncacheable();
6314 :
6315 : // NS_STYLE_OVERFLOW_CLIP is a deprecated value, so if it's specified
6316 : // in only one dimension, convert it to NS_STYLE_OVERFLOW_HIDDEN.
6317 0 : if (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
6318 0 : display->mOverflowX = NS_STYLE_OVERFLOW_HIDDEN;
6319 0 : if (display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)
6320 0 : display->mOverflowY = NS_STYLE_OVERFLOW_HIDDEN;
6321 :
6322 : // If 'visible' is specified but doesn't match the other dimension, it
6323 : // turns into 'auto'.
6324 0 : if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
6325 0 : display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
6326 0 : if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
6327 0 : display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
6328 : }
6329 :
6330 : // When 'contain: paint', update overflow from 'visible' to 'clip'.
6331 671 : if (display->IsContainPaint()) {
6332 : // XXX This actually sets overflow-[x|y] to -moz-hidden-unscrollable.
6333 0 : if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE) {
6334 : // This uncacheability (and the one below) could be fixed by adding
6335 : // mOriginalOverflowX and mOriginalOverflowY fields, if necessary.
6336 0 : display->mOverflowX = NS_STYLE_OVERFLOW_CLIP;
6337 0 : conditions.SetUncacheable();
6338 : }
6339 0 : if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE) {
6340 0 : display->mOverflowY = NS_STYLE_OVERFLOW_CLIP;
6341 0 : conditions.SetUncacheable();
6342 : }
6343 : }
6344 :
6345 671 : SetValue(*aRuleData->ValueForOverflowClipBox(), display->mOverflowClipBox,
6346 : conditions,
6347 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6348 671 : parentDisplay->mOverflowClipBox,
6349 671 : NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX);
6350 :
6351 671 : SetValue(*aRuleData->ValueForResize(), display->mResize, conditions,
6352 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6353 671 : parentDisplay->mResize,
6354 671 : NS_STYLE_RESIZE_NONE);
6355 :
6356 671 : if (display->mDisplay != StyleDisplay::None) {
6357 : // CSS2 9.7 specifies display type corrections dealing with 'float'
6358 : // and 'position'. Since generated content can't be floated or
6359 : // positioned, we can deal with it here.
6360 :
6361 484 : nsIAtom* pseudo = aContext->GetPseudo();
6362 484 : if (pseudo && display->mDisplay == StyleDisplay::Contents) {
6363 : // We don't want to create frames for anonymous content using a parent
6364 : // frame that is for content above the root of the anon tree.
6365 : // (XXX what we really should check here is not GetPseudo() but if there's
6366 : // a 'content' property value that implies anon content but we can't
6367 : // check that here since that's a different struct(?))
6368 : // We might get display:contents to work for CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS
6369 : // pseudos (:first-letter etc) in the future, but those have a lot of
6370 : // special handling in frame construction so they are also unsupported
6371 : // for now.
6372 0 : display->mOriginalDisplay = display->mDisplay = StyleDisplay::Inline;
6373 0 : conditions.SetUncacheable();
6374 : }
6375 :
6376 : // Inherit a <fieldset> grid/flex display type into its anon content frame.
6377 484 : if (pseudo == nsCSSAnonBoxes::fieldsetContent) {
6378 0 : MOZ_ASSERT(display->mDisplay == StyleDisplay::Block,
6379 : "forms.css should have set 'display:block'");
6380 0 : switch (parentDisplay->mDisplay) {
6381 : case StyleDisplay::Grid:
6382 : case StyleDisplay::InlineGrid:
6383 0 : display->mDisplay = StyleDisplay::Grid;
6384 0 : conditions.SetUncacheable();
6385 0 : break;
6386 : case StyleDisplay::Flex:
6387 : case StyleDisplay::InlineFlex:
6388 0 : display->mDisplay = StyleDisplay::Flex;
6389 0 : conditions.SetUncacheable();
6390 0 : break;
6391 : default:
6392 0 : break; // Do nothing
6393 : }
6394 : }
6395 :
6396 484 : if (nsCSSPseudoElements::firstLetter == pseudo) {
6397 : // a non-floating first-letter must be inline
6398 : // XXX this fix can go away once bug 103189 is fixed correctly
6399 : // Note that we reset mOriginalDisplay to enforce the invariant that it equals mDisplay if we're not positioned or floating.
6400 0 : display->mOriginalDisplay = display->mDisplay = StyleDisplay::Inline;
6401 :
6402 : // We can't cache the data in the rule tree since if a more specific
6403 : // rule has 'float: left' we'll end up with the wrong 'display'
6404 : // property.
6405 0 : conditions.SetUncacheable();
6406 : }
6407 :
6408 484 : if (display->IsAbsolutelyPositionedStyle()) {
6409 : // 1) if position is 'absolute' or 'fixed' then display must be
6410 : // block-level and float must be 'none'
6411 8 : EnsureBlockDisplay(display->mDisplay);
6412 8 : display->mFloat = StyleFloat::None;
6413 :
6414 : // Note that it's OK to cache this struct in the ruletree
6415 : // because it's fine as-is for any style context that points to
6416 : // it directly, and any use of it as aStartStruct (e.g. if a
6417 : // more specific rule sets "position: static") will use
6418 : // mOriginalDisplay and mOriginalFloat, which we have carefully
6419 : // not changed.
6420 476 : } else if (display->mFloat != StyleFloat::None) {
6421 : // 2) if float is not none, and display is not none, then we must
6422 : // set a block-level 'display' type per CSS2.1 section 9.7.
6423 0 : EnsureBlockDisplay(display->mDisplay);
6424 :
6425 : // Note that it's OK to cache this struct in the ruletree
6426 : // because it's fine as-is for any style context that points to
6427 : // it directly, and any use of it as aStartStruct (e.g. if a
6428 : // more specific rule sets "float: none") will use
6429 : // mOriginalDisplay, which we have carefully not changed.
6430 : }
6431 :
6432 484 : if (display->IsContainPaint()) {
6433 : // An element with contain:paint or contain:layout needs to "be a
6434 : // formatting context". For the purposes of the "display" property, that
6435 : // just means we need to promote "display:inline" to "inline-block".
6436 : // XXX We may also need to promote ruby display vals; see bug 1179349.
6437 :
6438 : // It's okay to cache this change in the rule tree for the same
6439 : // reasons as floats in the previous condition.
6440 0 : if (display->mDisplay == StyleDisplay::Inline) {
6441 0 : display->mDisplay = StyleDisplay::InlineBlock;
6442 : }
6443 : }
6444 : }
6445 :
6446 671 : SetTransformValue(*aRuleData->ValueForTransform(),
6447 : display->mSpecifiedTransform, conditions,
6448 671 : parentDisplay->mSpecifiedTransform);
6449 :
6450 : /* Convert the nsCSSValueList into a will-change bitfield for fast lookup */
6451 671 : const nsCSSValue* willChangeValue = aRuleData->ValueForWillChange();
6452 671 : switch (willChangeValue->GetUnit()) {
6453 : case eCSSUnit_Null:
6454 671 : break;
6455 :
6456 : case eCSSUnit_List:
6457 : case eCSSUnit_ListDep: {
6458 0 : display->mWillChange.Clear();
6459 0 : display->mWillChangeBitField = 0;
6460 0 : for (const nsCSSValueList* item = willChangeValue->GetListValue();
6461 0 : item; item = item->mNext)
6462 : {
6463 0 : nsIAtom* atom = item->mValue.GetAtomValue();
6464 0 : display->mWillChange.AppendElement(atom);
6465 0 : if (atom == nsGkAtoms::transform) {
6466 0 : display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_TRANSFORM;
6467 0 : } else if (atom == nsGkAtoms::opacity) {
6468 0 : display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_OPACITY;
6469 0 : } else if (atom == nsGkAtoms::scrollPosition) {
6470 0 : display->mWillChangeBitField |= NS_STYLE_WILL_CHANGE_SCROLL;
6471 : }
6472 :
6473 0 : nsDependentAtomString buffer(atom);
6474 : nsCSSPropertyID prop =
6475 0 : nsCSSProps::LookupProperty(buffer, CSSEnabledState::eForAllContent);
6476 0 : if (prop != eCSSProperty_UNKNOWN &&
6477 0 : prop != eCSSPropertyExtra_variable) {
6478 : // If the property given is a shorthand, it indicates the expectation
6479 : // for all the longhands the shorthand expands to.
6480 0 : if (nsCSSProps::IsShorthand(prop)) {
6481 0 : for (const nsCSSPropertyID* shorthands =
6482 0 : nsCSSProps::SubpropertyEntryFor(prop);
6483 0 : *shorthands != eCSSProperty_UNKNOWN; ++shorthands) {
6484 0 : display->mWillChangeBitField |= GetWillChangeBitFieldFromPropFlags(*shorthands);
6485 : }
6486 : } else {
6487 0 : display->mWillChangeBitField |= GetWillChangeBitFieldFromPropFlags(prop);
6488 : }
6489 : }
6490 : }
6491 0 : break;
6492 : }
6493 :
6494 : case eCSSUnit_Inherit:
6495 0 : display->mWillChange.Clear();
6496 0 : display->mWillChange.AppendElements(parentDisplay->mWillChange);
6497 0 : display->mWillChangeBitField = parentDisplay->mWillChangeBitField;
6498 0 : conditions.SetUncacheable();
6499 0 : break;
6500 :
6501 : case eCSSUnit_Initial:
6502 : case eCSSUnit_Unset:
6503 : case eCSSUnit_Auto:
6504 0 : display->mWillChange.Clear();
6505 0 : display->mWillChangeBitField = 0;
6506 0 : break;
6507 :
6508 : default:
6509 0 : MOZ_ASSERT(false, "unrecognized will-change unit");
6510 : }
6511 :
6512 : // vertical-align: enum, length, percent, calc, inherit
6513 671 : const nsCSSValue* verticalAlignValue = aRuleData->ValueForVerticalAlign();
6514 671 : if (!SetCoord(*verticalAlignValue, display->mVerticalAlign,
6515 : parentDisplay->mVerticalAlign,
6516 : SETCOORD_LPH | SETCOORD_ENUMERATED | SETCOORD_STORE_CALC,
6517 671 : aContext, mPresContext, conditions)) {
6518 1338 : if (eCSSUnit_Initial == verticalAlignValue->GetUnit() ||
6519 669 : eCSSUnit_Unset == verticalAlignValue->GetUnit()) {
6520 0 : display->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE,
6521 0 : eStyleUnit_Enumerated);
6522 : }
6523 : }
6524 :
6525 : /* Convert -moz-transform-origin. */
6526 : const nsCSSValue* transformOriginValue =
6527 671 : aRuleData->ValueForTransformOrigin();
6528 671 : if (transformOriginValue->GetUnit() != eCSSUnit_Null) {
6529 : const nsCSSValue& valX =
6530 30 : transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
6531 30 : transformOriginValue->GetTripletValue().mXValue : *transformOriginValue;
6532 : const nsCSSValue& valY =
6533 30 : transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
6534 30 : transformOriginValue->GetTripletValue().mYValue : *transformOriginValue;
6535 : const nsCSSValue& valZ =
6536 30 : transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
6537 30 : transformOriginValue->GetTripletValue().mZValue : *transformOriginValue;
6538 :
6539 : mozilla::DebugOnly<bool> cX =
6540 60 : SetCoord(valX, display->mTransformOrigin[0],
6541 : parentDisplay->mTransformOrigin[0],
6542 : SETCOORD_LPH | SETCOORD_INITIAL_HALF |
6543 : SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
6544 : SETCOORD_UNSET_INITIAL,
6545 90 : aContext, mPresContext, conditions);
6546 :
6547 : mozilla::DebugOnly<bool> cY =
6548 60 : SetCoord(valY, display->mTransformOrigin[1],
6549 : parentDisplay->mTransformOrigin[1],
6550 : SETCOORD_LPH | SETCOORD_INITIAL_HALF |
6551 : SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
6552 : SETCOORD_UNSET_INITIAL,
6553 90 : aContext, mPresContext, conditions);
6554 :
6555 30 : if (valZ.GetUnit() == eCSSUnit_Null) {
6556 : // Null for the z component means a 0 translation, not
6557 : // unspecified, as we have already checked the triplet
6558 : // value for Null.
6559 0 : display->mTransformOrigin[2].SetCoordValue(0);
6560 : } else {
6561 : mozilla::DebugOnly<bool> cZ =
6562 60 : SetCoord(valZ, display->mTransformOrigin[2],
6563 : parentDisplay->mTransformOrigin[2],
6564 : SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
6565 : SETCOORD_UNSET_INITIAL,
6566 90 : aContext, mPresContext, conditions);
6567 30 : MOZ_ASSERT(cY == cZ, "changed one but not the other");
6568 : }
6569 30 : MOZ_ASSERT(cX == cY, "changed one but not the other");
6570 30 : NS_ASSERTION(cX, "Malformed -moz-transform-origin parse!");
6571 : }
6572 :
6573 : const nsCSSValue* perspectiveOriginValue =
6574 671 : aRuleData->ValueForPerspectiveOrigin();
6575 671 : if (perspectiveOriginValue->GetUnit() != eCSSUnit_Null) {
6576 : mozilla::DebugOnly<bool> result =
6577 0 : SetPairCoords(*perspectiveOriginValue,
6578 : display->mPerspectiveOrigin[0],
6579 : display->mPerspectiveOrigin[1],
6580 : parentDisplay->mPerspectiveOrigin[0],
6581 : parentDisplay->mPerspectiveOrigin[1],
6582 : SETCOORD_LPH | SETCOORD_INITIAL_HALF |
6583 : SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC |
6584 : SETCOORD_UNSET_INITIAL,
6585 0 : aContext, mPresContext, conditions);
6586 0 : NS_ASSERTION(result, "Malformed -moz-perspective-origin parse!");
6587 : }
6588 :
6589 671 : SetCoord(*aRuleData->ValueForPerspective(),
6590 : display->mChildPerspective, parentDisplay->mChildPerspective,
6591 : SETCOORD_LAH | SETCOORD_INITIAL_NONE | SETCOORD_NONE |
6592 : SETCOORD_UNSET_INITIAL,
6593 1342 : aContext, mPresContext, conditions);
6594 :
6595 671 : SetValue(*aRuleData->ValueForBackfaceVisibility(),
6596 : display->mBackfaceVisibility, conditions,
6597 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6598 671 : parentDisplay->mBackfaceVisibility,
6599 671 : NS_STYLE_BACKFACE_VISIBILITY_VISIBLE);
6600 :
6601 : // transform-style: enum, inherit, initial
6602 671 : SetValue(*aRuleData->ValueForTransformStyle(),
6603 : display->mTransformStyle, conditions,
6604 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6605 671 : parentDisplay->mTransformStyle,
6606 671 : NS_STYLE_TRANSFORM_STYLE_FLAT);
6607 :
6608 : // transform-box: enum, inherit, initial
6609 671 : SetValue(*aRuleData->ValueForTransformBox(),
6610 : display->mTransformBox, conditions,
6611 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6612 671 : parentDisplay->mTransformBox,
6613 671 : StyleGeometryBox::BorderBox);
6614 :
6615 : // orient: enum, inherit, initial
6616 671 : SetValue(*aRuleData->ValueForOrient(),
6617 : display->mOrient, conditions,
6618 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
6619 671 : parentDisplay->mOrient,
6620 671 : StyleOrient::Inline);
6621 :
6622 : // shape-outside: none | [ <basic-shape> || <shape-box> ] | <image>
6623 671 : const nsCSSValue* shapeOutsideValue = aRuleData->ValueForShapeOutside();
6624 671 : switch (shapeOutsideValue->GetUnit()) {
6625 : case eCSSUnit_Null:
6626 671 : break;
6627 : case eCSSUnit_None:
6628 : case eCSSUnit_Initial:
6629 : case eCSSUnit_Unset:
6630 0 : display->mShapeOutside = StyleShapeSource();
6631 0 : break;
6632 : case eCSSUnit_Inherit:
6633 0 : conditions.SetUncacheable();
6634 0 : display->mShapeOutside = parentDisplay->mShapeOutside;
6635 0 : break;
6636 : case eCSSUnit_URL: {
6637 0 : display->mShapeOutside = StyleShapeSource();
6638 0 : display->mShapeOutside.SetURL(shapeOutsideValue->GetURLStructValue());
6639 0 : break;
6640 : }
6641 : case eCSSUnit_Array: {
6642 0 : display->mShapeOutside = StyleShapeSource();
6643 0 : SetStyleShapeSourceToCSSValue(&display->mShapeOutside, shapeOutsideValue,
6644 0 : aContext, mPresContext, conditions);
6645 0 : break;
6646 : }
6647 : default:
6648 0 : MOZ_ASSERT_UNREACHABLE("Unrecognized shape-outside unit!");
6649 : }
6650 :
6651 1342 : COMPUTE_END_RESET(Display, display)
6652 : }
6653 :
6654 : const void*
6655 142 : nsRuleNode::ComputeVisibilityData(void* aStartStruct,
6656 : const nsRuleData* aRuleData,
6657 : GeckoStyleContext* aContext,
6658 : nsRuleNode* aHighestNode,
6659 : const RuleDetail aRuleDetail,
6660 : const RuleNodeCacheConditions aConditions)
6661 : {
6662 284 : COMPUTE_START_INHERITED(Visibility, visibility, parentVisibility)
6663 :
6664 : // IMPORTANT: No properties in this struct have lengths in them. We
6665 : // depend on this since CalcLengthWith can call StyleVisibility()
6666 : // to get the language for resolving fonts!
6667 :
6668 : // direction: enum, inherit, initial
6669 284 : SetValue(*aRuleData->ValueForDirection(), visibility->mDirection,
6670 : conditions,
6671 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
6672 142 : parentVisibility->mDirection,
6673 142 : (GET_BIDI_OPTION_DIRECTION(mPresContext->GetBidi())
6674 : == IBMBIDI_TEXTDIRECTION_RTL)
6675 142 : ? NS_STYLE_DIRECTION_RTL : NS_STYLE_DIRECTION_LTR);
6676 :
6677 : // visibility: enum, inherit, initial
6678 142 : SetValue(*aRuleData->ValueForVisibility(), visibility->mVisible,
6679 : conditions,
6680 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
6681 142 : parentVisibility->mVisible,
6682 142 : NS_STYLE_VISIBILITY_VISIBLE);
6683 :
6684 : // image-rendering: enum, inherit
6685 142 : SetValue(*aRuleData->ValueForImageRendering(),
6686 : visibility->mImageRendering, conditions,
6687 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
6688 142 : parentVisibility->mImageRendering,
6689 142 : NS_STYLE_IMAGE_RENDERING_AUTO);
6690 :
6691 : // writing-mode: enum, inherit, initial
6692 142 : SetValue(*aRuleData->ValueForWritingMode(), visibility->mWritingMode,
6693 : conditions,
6694 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
6695 142 : parentVisibility->mWritingMode,
6696 142 : NS_STYLE_WRITING_MODE_HORIZONTAL_TB);
6697 :
6698 : // text-orientation: enum, inherit, initial
6699 142 : SetValue(*aRuleData->ValueForTextOrientation(), visibility->mTextOrientation,
6700 : conditions,
6701 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
6702 142 : parentVisibility->mTextOrientation,
6703 142 : NS_STYLE_TEXT_ORIENTATION_MIXED);
6704 :
6705 : // image-orientation: enum, inherit, initial
6706 142 : const nsCSSValue* orientation = aRuleData->ValueForImageOrientation();
6707 284 : if (orientation->GetUnit() == eCSSUnit_Inherit ||
6708 142 : orientation->GetUnit() == eCSSUnit_Unset) {
6709 0 : conditions.SetUncacheable();
6710 0 : visibility->mImageOrientation = parentVisibility->mImageOrientation;
6711 142 : } else if (orientation->GetUnit() == eCSSUnit_Initial) {
6712 0 : visibility->mImageOrientation = nsStyleImageOrientation();
6713 142 : } else if (orientation->IsAngularUnit()) {
6714 0 : double angle = orientation->GetAngleValueInRadians();
6715 : visibility->mImageOrientation =
6716 0 : nsStyleImageOrientation::CreateAsAngleAndFlip(angle, false);
6717 142 : } else if (orientation->GetUnit() == eCSSUnit_Array) {
6718 0 : const nsCSSValue::Array* array = orientation->GetArrayValue();
6719 0 : MOZ_ASSERT(array->Item(0).IsAngularUnit(),
6720 : "First image-orientation value is not an angle");
6721 0 : MOZ_ASSERT(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
6722 : array->Item(1).GetIntValue() == NS_STYLE_IMAGE_ORIENTATION_FLIP,
6723 : "Second image-orientation value is not 'flip'");
6724 0 : double angle = array->Item(0).GetAngleValueInRadians();
6725 : visibility->mImageOrientation =
6726 0 : nsStyleImageOrientation::CreateAsAngleAndFlip(angle, true);
6727 :
6728 142 : } else if (orientation->GetUnit() == eCSSUnit_Enumerated) {
6729 0 : switch (orientation->GetIntValue()) {
6730 : case NS_STYLE_IMAGE_ORIENTATION_FLIP:
6731 0 : visibility->mImageOrientation = nsStyleImageOrientation::CreateAsFlip();
6732 0 : break;
6733 : case NS_STYLE_IMAGE_ORIENTATION_FROM_IMAGE:
6734 0 : visibility->mImageOrientation = nsStyleImageOrientation::CreateAsFromImage();
6735 0 : break;
6736 : default:
6737 0 : NS_NOTREACHED("Invalid image-orientation enumerated value");
6738 : }
6739 : } else {
6740 142 : MOZ_ASSERT(orientation->GetUnit() == eCSSUnit_Null, "Should be null unit");
6741 : }
6742 :
6743 142 : SetValue(*aRuleData->ValueForColorAdjust(), visibility->mColorAdjust,
6744 : conditions,
6745 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
6746 142 : parentVisibility->mColorAdjust,
6747 142 : NS_STYLE_COLOR_ADJUST_ECONOMY);
6748 :
6749 284 : COMPUTE_END_INHERITED(Visibility, visibility)
6750 : }
6751 :
6752 : const void*
6753 10 : nsRuleNode::ComputeColorData(void* aStartStruct,
6754 : const nsRuleData* aRuleData,
6755 : GeckoStyleContext* aContext,
6756 : nsRuleNode* aHighestNode,
6757 : const RuleDetail aRuleDetail,
6758 : const RuleNodeCacheConditions aConditions)
6759 : {
6760 20 : COMPUTE_START_INHERITED(Color, color, parentColor)
6761 :
6762 : // color: color, string, inherit
6763 : // Special case for currentColor. According to CSS3, setting color to 'currentColor'
6764 : // should behave as if it is inherited
6765 10 : const nsCSSValue* colorValue = aRuleData->ValueForColor();
6766 30 : if ((colorValue->GetUnit() == eCSSUnit_EnumColor &&
6767 20 : colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) ||
6768 10 : colorValue->GetUnit() == eCSSUnit_Unset) {
6769 0 : color->mColor = parentColor->mColor;
6770 0 : conditions.SetUncacheable();
6771 : }
6772 10 : else if (colorValue->GetUnit() == eCSSUnit_Initial) {
6773 0 : color->mColor = mPresContext->DefaultColor();
6774 : }
6775 : else {
6776 10 : SetColor(*colorValue, parentColor->mColor, mPresContext, aContext,
6777 10 : color->mColor, conditions);
6778 : }
6779 :
6780 20 : COMPUTE_END_INHERITED(Color, color)
6781 : }
6782 :
6783 : // information about how to compute values for background-* properties
6784 : template <class SpecifiedValueItem, class ComputedValueItem>
6785 : struct BackgroundItemComputer {
6786 : };
6787 :
6788 : template <>
6789 : struct BackgroundItemComputer<nsCSSValueList, uint8_t>
6790 : {
6791 6 : static void ComputeValue(GeckoStyleContext* aStyleContext,
6792 : const nsCSSValueList* aSpecifiedValue,
6793 : uint8_t& aComputedValue,
6794 : RuleNodeCacheConditions& aConditions)
6795 : {
6796 6 : SetValue(aSpecifiedValue->mValue, aComputedValue, aConditions,
6797 6 : SETVAL_ENUMERATED, uint8_t(0), 0);
6798 6 : }
6799 : };
6800 :
6801 : template <>
6802 : struct BackgroundItemComputer<nsCSSValuePairList, nsStyleImageLayers::Repeat>
6803 : {
6804 18 : static void ComputeValue(GeckoStyleContext* aStyleContext,
6805 : const nsCSSValuePairList* aSpecifiedValue,
6806 : nsStyleImageLayers::Repeat& aComputedValue,
6807 : RuleNodeCacheConditions& aConditions)
6808 : {
6809 18 : NS_ASSERTION(aSpecifiedValue->mXValue.GetUnit() == eCSSUnit_Enumerated &&
6810 : (aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Enumerated ||
6811 : aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null),
6812 : "Invalid unit");
6813 :
6814 18 : bool hasContraction = true;
6815 : StyleImageLayerRepeat value =
6816 18 : static_cast<StyleImageLayerRepeat>(aSpecifiedValue->mXValue.GetIntValue());
6817 18 : switch (value) {
6818 : case StyleImageLayerRepeat::RepeatX:
6819 5 : aComputedValue.mXRepeat = StyleImageLayerRepeat::Repeat;
6820 5 : aComputedValue.mYRepeat = StyleImageLayerRepeat::NoRepeat;
6821 5 : break;
6822 : case StyleImageLayerRepeat::RepeatY:
6823 0 : aComputedValue.mXRepeat = StyleImageLayerRepeat::NoRepeat;
6824 0 : aComputedValue.mYRepeat = StyleImageLayerRepeat::Repeat;
6825 0 : break;
6826 : default:
6827 13 : NS_ASSERTION(value == StyleImageLayerRepeat::NoRepeat ||
6828 : value == StyleImageLayerRepeat::Repeat ||
6829 : value == StyleImageLayerRepeat::Space ||
6830 : value == StyleImageLayerRepeat::Round, "Unexpected value");
6831 13 : aComputedValue.mXRepeat = value;
6832 13 : hasContraction = false;
6833 13 : break;
6834 : }
6835 :
6836 18 : if (hasContraction) {
6837 5 : NS_ASSERTION(aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null,
6838 : "Invalid unit.");
6839 5 : return;
6840 : }
6841 :
6842 13 : switch (aSpecifiedValue->mYValue.GetUnit()) {
6843 : case eCSSUnit_Null:
6844 13 : aComputedValue.mYRepeat = aComputedValue.mXRepeat;
6845 13 : break;
6846 : case eCSSUnit_Enumerated:
6847 0 : value =
6848 0 : static_cast<StyleImageLayerRepeat>(aSpecifiedValue->mYValue.GetIntValue());
6849 0 : NS_ASSERTION(value == StyleImageLayerRepeat::NoRepeat ||
6850 : value == StyleImageLayerRepeat::Repeat ||
6851 : value == StyleImageLayerRepeat::Space ||
6852 : value == StyleImageLayerRepeat::Round, "Unexpected value");
6853 0 : aComputedValue.mYRepeat = value;
6854 0 : break;
6855 : default:
6856 0 : NS_NOTREACHED("Unexpected CSS value");
6857 0 : break;
6858 : }
6859 : }
6860 : };
6861 :
6862 : template <>
6863 : struct BackgroundItemComputer<nsCSSValueList, nsStyleImage>
6864 : {
6865 47 : static void ComputeValue(GeckoStyleContext* aStyleContext,
6866 : const nsCSSValueList* aSpecifiedValue,
6867 : nsStyleImage& aComputedValue,
6868 : RuleNodeCacheConditions& aConditions)
6869 : {
6870 47 : SetStyleImage(aStyleContext, aSpecifiedValue->mValue, aComputedValue,
6871 47 : aConditions);
6872 47 : }
6873 : };
6874 :
6875 : template <typename T>
6876 : struct BackgroundItemComputer<nsCSSValueList, T>
6877 : {
6878 : typedef typename EnableIf<IsEnum<T>::value, T>::Type ComputedType;
6879 :
6880 39 : static void ComputeValue(GeckoStyleContext* aStyleContext,
6881 : const nsCSSValueList* aSpecifiedValue,
6882 : ComputedType& aComputedValue,
6883 : RuleNodeCacheConditions& aConditions)
6884 : {
6885 39 : aComputedValue =
6886 39 : static_cast<T>(aSpecifiedValue->mValue.GetIntValue());
6887 39 : }
6888 : };
6889 :
6890 : /* Helper function for ComputePositionValue.
6891 : * This function computes a single PositionCoord from two nsCSSValue objects,
6892 : * which represent an edge and an offset from that edge.
6893 : */
6894 : static void
6895 26 : ComputePositionCoord(GeckoStyleContext* aStyleContext,
6896 : const nsCSSValue& aEdge,
6897 : const nsCSSValue& aOffset,
6898 : Position::Coord* aResult,
6899 : RuleNodeCacheConditions& aConditions)
6900 : {
6901 26 : if (eCSSUnit_Percent == aOffset.GetUnit()) {
6902 10 : aResult->mLength = 0;
6903 10 : aResult->mPercent = aOffset.GetPercentValue();
6904 10 : aResult->mHasPercent = true;
6905 16 : } else if (aOffset.IsLengthUnit()) {
6906 0 : aResult->mLength = CalcLength(aOffset, aStyleContext,
6907 : aStyleContext->PresContext(),
6908 : aConditions);
6909 0 : aResult->mPercent = 0.0f;
6910 0 : aResult->mHasPercent = false;
6911 16 : } else if (aOffset.IsCalcUnit()) {
6912 : LengthPercentPairCalcOps ops(aStyleContext,
6913 : aStyleContext->PresContext(),
6914 0 : aConditions);
6915 0 : nsRuleNode::ComputedCalc vals = ComputeCalc(aOffset, ops);
6916 0 : aResult->mLength = vals.mLength;
6917 0 : aResult->mPercent = vals.mPercent;
6918 0 : aResult->mHasPercent = ops.mHasPercent;
6919 : } else {
6920 16 : aResult->mLength = 0;
6921 16 : aResult->mPercent = 0.0f;
6922 16 : aResult->mHasPercent = false;
6923 16 : NS_ASSERTION(aOffset.GetUnit() == eCSSUnit_Null, "unexpected unit");
6924 : }
6925 :
6926 26 : if (eCSSUnit_Enumerated == aEdge.GetUnit()) {
6927 : int sign;
6928 16 : if (aEdge.GetIntValue() & (NS_STYLE_IMAGELAYER_POSITION_BOTTOM |
6929 : NS_STYLE_IMAGELAYER_POSITION_RIGHT)) {
6930 2 : sign = -1;
6931 : } else {
6932 14 : sign = 1;
6933 : }
6934 32 : aResult->mPercent = GetFloatFromBoxPosition(aEdge.GetIntValue()) +
6935 16 : sign * aResult->mPercent;
6936 16 : aResult->mLength = sign * aResult->mLength;
6937 16 : aResult->mHasPercent = true;
6938 : } else {
6939 10 : NS_ASSERTION(eCSSUnit_Null == aEdge.GetUnit(), "unexpected unit");
6940 : }
6941 26 : }
6942 :
6943 : /* Helper function to convert a CSS <position> specified value into its
6944 : * computed-style form. */
6945 : static void
6946 0 : ComputePositionValue(GeckoStyleContext* aStyleContext,
6947 : const nsCSSValue& aValue,
6948 : Position& aComputedValue,
6949 : RuleNodeCacheConditions& aConditions)
6950 : {
6951 0 : NS_ASSERTION(aValue.GetUnit() == eCSSUnit_Array,
6952 : "unexpected unit for CSS <position> value");
6953 :
6954 0 : RefPtr<nsCSSValue::Array> positionArray = aValue.GetArrayValue();
6955 0 : NS_ASSERTION(positionArray->Count() == 4,
6956 : "unexpected number of values in CSS <position> value");
6957 :
6958 0 : const nsCSSValue &xEdge = positionArray->Item(0);
6959 0 : const nsCSSValue &xOffset = positionArray->Item(1);
6960 0 : const nsCSSValue &yEdge = positionArray->Item(2);
6961 0 : const nsCSSValue &yOffset = positionArray->Item(3);
6962 :
6963 0 : NS_ASSERTION((eCSSUnit_Enumerated == xEdge.GetUnit() ||
6964 : eCSSUnit_Null == xEdge.GetUnit()) &&
6965 : (eCSSUnit_Enumerated == yEdge.GetUnit() ||
6966 : eCSSUnit_Null == yEdge.GetUnit()) &&
6967 : eCSSUnit_Enumerated != xOffset.GetUnit() &&
6968 : eCSSUnit_Enumerated != yOffset.GetUnit(),
6969 : "Invalid background position");
6970 :
6971 0 : ComputePositionCoord(aStyleContext, xEdge, xOffset,
6972 : &aComputedValue.mXPosition,
6973 0 : aConditions);
6974 :
6975 0 : ComputePositionCoord(aStyleContext, yEdge, yOffset,
6976 : &aComputedValue.mYPosition,
6977 0 : aConditions);
6978 0 : }
6979 :
6980 : /* Helper function to convert the -x or -y part of a CSS <position> specified
6981 : * value into its computed-style form. */
6982 : static void
6983 26 : ComputePositionCoordValue(GeckoStyleContext* aStyleContext,
6984 : const nsCSSValue& aValue,
6985 : Position::Coord& aComputedValue,
6986 : RuleNodeCacheConditions& aConditions)
6987 : {
6988 26 : NS_ASSERTION(aValue.GetUnit() == eCSSUnit_Array,
6989 : "unexpected unit for position coord value");
6990 :
6991 52 : RefPtr<nsCSSValue::Array> positionArray = aValue.GetArrayValue();
6992 26 : NS_ASSERTION(positionArray->Count() == 2,
6993 : "unexpected number of values, expecting one edge and one offset");
6994 :
6995 26 : const nsCSSValue &edge = positionArray->Item(0);
6996 26 : const nsCSSValue &offset = positionArray->Item(1);
6997 :
6998 26 : NS_ASSERTION((eCSSUnit_Enumerated == edge.GetUnit() ||
6999 : eCSSUnit_Null == edge.GetUnit()) &&
7000 : eCSSUnit_Enumerated != offset.GetUnit(),
7001 : "Invalid background position");
7002 :
7003 : ComputePositionCoord(aStyleContext, edge, offset,
7004 : &aComputedValue,
7005 26 : aConditions);
7006 26 : }
7007 :
7008 : struct BackgroundSizeAxis {
7009 : nsCSSValue nsCSSValuePairList::* specified;
7010 : nsStyleImageLayers::Size::Dimension nsStyleImageLayers::Size::* result;
7011 : uint8_t nsStyleImageLayers::Size::* type;
7012 : };
7013 :
7014 : static const BackgroundSizeAxis gBGSizeAxes[] = {
7015 : { &nsCSSValuePairList::mXValue,
7016 : &nsStyleImageLayers::Size::mWidth,
7017 : &nsStyleImageLayers::Size::mWidthType },
7018 : { &nsCSSValuePairList::mYValue,
7019 : &nsStyleImageLayers::Size::mHeight,
7020 : &nsStyleImageLayers::Size::mHeightType }
7021 : };
7022 :
7023 : template <>
7024 : struct BackgroundItemComputer<nsCSSValuePairList, nsStyleImageLayers::Size>
7025 : {
7026 28 : static void ComputeValue(GeckoStyleContext* aStyleContext,
7027 : const nsCSSValuePairList* aSpecifiedValue,
7028 : nsStyleImageLayers::Size& aComputedValue,
7029 : RuleNodeCacheConditions& aConditions)
7030 : {
7031 28 : nsStyleImageLayers::Size &size = aComputedValue;
7032 84 : for (const BackgroundSizeAxis *axis = gBGSizeAxes,
7033 28 : *axis_end = ArrayEnd(gBGSizeAxes);
7034 84 : axis < axis_end; ++axis) {
7035 56 : const nsCSSValue &specified = aSpecifiedValue->*(axis->specified);
7036 56 : if (eCSSUnit_Auto == specified.GetUnit()) {
7037 24 : size.*(axis->type) = nsStyleImageLayers::Size::eAuto;
7038 : }
7039 32 : else if (eCSSUnit_Enumerated == specified.GetUnit()) {
7040 : static_assert(nsStyleImageLayers::Size::eContain ==
7041 : NS_STYLE_IMAGELAYER_SIZE_CONTAIN &&
7042 : nsStyleImageLayers::Size::eCover ==
7043 : NS_STYLE_IMAGELAYER_SIZE_COVER,
7044 : "background size constants out of sync");
7045 0 : MOZ_ASSERT(specified.GetIntValue() == NS_STYLE_IMAGELAYER_SIZE_CONTAIN ||
7046 : specified.GetIntValue() == NS_STYLE_IMAGELAYER_SIZE_COVER,
7047 : "invalid enumerated value for size coordinate");
7048 0 : size.*(axis->type) = specified.GetIntValue();
7049 : }
7050 32 : else if (eCSSUnit_Null == specified.GetUnit()) {
7051 0 : MOZ_ASSERT(axis == gBGSizeAxes + 1,
7052 : "null allowed only as height value, and only "
7053 : "for contain/cover/initial/inherit");
7054 : #ifdef DEBUG
7055 : {
7056 0 : const nsCSSValue &widthValue = aSpecifiedValue->mXValue;
7057 0 : MOZ_ASSERT(widthValue.GetUnit() != eCSSUnit_Inherit &&
7058 : widthValue.GetUnit() != eCSSUnit_Initial &&
7059 : widthValue.GetUnit() != eCSSUnit_Unset,
7060 : "initial/inherit/unset should already have been handled");
7061 0 : MOZ_ASSERT(widthValue.GetUnit() == eCSSUnit_Enumerated &&
7062 : (widthValue.GetIntValue() == NS_STYLE_IMAGELAYER_SIZE_CONTAIN ||
7063 : widthValue.GetIntValue() == NS_STYLE_IMAGELAYER_SIZE_COVER),
7064 : "null height value not corresponding to allowable "
7065 : "non-null width value");
7066 : }
7067 : #endif
7068 0 : size.*(axis->type) = size.mWidthType;
7069 : }
7070 32 : else if (eCSSUnit_Percent == specified.GetUnit()) {
7071 28 : (size.*(axis->result)).mLength = 0;
7072 28 : (size.*(axis->result)).mPercent = specified.GetPercentValue();
7073 28 : (size.*(axis->result)).mHasPercent = true;
7074 28 : size.*(axis->type) = nsStyleImageLayers::Size::eLengthPercentage;
7075 : }
7076 4 : else if (specified.IsLengthUnit()) {
7077 8 : (size.*(axis->result)).mLength =
7078 4 : CalcLength(specified, aStyleContext, aStyleContext->PresContext(),
7079 : aConditions);
7080 4 : (size.*(axis->result)).mPercent = 0.0f;
7081 4 : (size.*(axis->result)).mHasPercent = false;
7082 4 : size.*(axis->type) = nsStyleImageLayers::Size::eLengthPercentage;
7083 : } else {
7084 0 : MOZ_ASSERT(specified.IsCalcUnit(), "unexpected unit");
7085 : LengthPercentPairCalcOps ops(aStyleContext,
7086 : aStyleContext->PresContext(),
7087 0 : aConditions);
7088 0 : nsRuleNode::ComputedCalc vals = ComputeCalc(specified, ops);
7089 0 : (size.*(axis->result)).mLength = vals.mLength;
7090 0 : (size.*(axis->result)).mPercent = vals.mPercent;
7091 0 : (size.*(axis->result)).mHasPercent = ops.mHasPercent;
7092 0 : size.*(axis->type) = nsStyleImageLayers::Size::eLengthPercentage;
7093 : }
7094 : }
7095 :
7096 28 : MOZ_ASSERT(size.mWidthType < nsStyleImageLayers::Size::eDimensionType_COUNT,
7097 : "bad width type");
7098 28 : MOZ_ASSERT(size.mHeightType < nsStyleImageLayers::Size::eDimensionType_COUNT,
7099 : "bad height type");
7100 28 : MOZ_ASSERT((size.mWidthType != nsStyleImageLayers::Size::eContain &&
7101 : size.mWidthType != nsStyleImageLayers::Size::eCover) ||
7102 : size.mWidthType == size.mHeightType,
7103 : "contain/cover apply to both dimensions or to neither");
7104 28 : }
7105 : };
7106 :
7107 : template <class ComputedValueItem>
7108 : static void
7109 1140 : SetImageLayerList(GeckoStyleContext* aStyleContext,
7110 : const nsCSSValue& aValue,
7111 : nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
7112 : const nsStyleAutoArray<nsStyleImageLayers::Layer>& aParentLayers,
7113 : ComputedValueItem nsStyleImageLayers::Layer::* aResultLocation,
7114 : ComputedValueItem aInitialValue,
7115 : uint32_t aParentItemCount,
7116 : uint32_t& aItemCount,
7117 : uint32_t& aMaxItemCount,
7118 : bool& aRebuild,
7119 : RuleNodeCacheConditions& aConditions)
7120 : {
7121 1140 : switch (aValue.GetUnit()) {
7122 : case eCSSUnit_Null:
7123 1072 : break;
7124 :
7125 : case eCSSUnit_Inherit:
7126 0 : aRebuild = true;
7127 0 : aConditions.SetUncacheable();
7128 0 : aLayers.EnsureLengthAtLeast(aParentItemCount);
7129 0 : aItemCount = aParentItemCount;
7130 0 : for (uint32_t i = 0; i < aParentItemCount; ++i) {
7131 0 : aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
7132 : }
7133 0 : break;
7134 :
7135 : case eCSSUnit_Initial:
7136 : case eCSSUnit_Unset:
7137 0 : aRebuild = true;
7138 0 : aItemCount = 1;
7139 0 : aLayers[0].*aResultLocation = aInitialValue;
7140 0 : break;
7141 :
7142 : case eCSSUnit_List:
7143 : case eCSSUnit_ListDep: {
7144 68 : aRebuild = true;
7145 68 : aItemCount = 0;
7146 68 : const nsCSSValueList* item = aValue.GetListValue();
7147 92 : do {
7148 92 : NS_ASSERTION(item->mValue.GetUnit() != eCSSUnit_Null &&
7149 : item->mValue.GetUnit() != eCSSUnit_Inherit &&
7150 : item->mValue.GetUnit() != eCSSUnit_Initial &&
7151 : item->mValue.GetUnit() != eCSSUnit_Unset,
7152 : "unexpected unit");
7153 92 : ++aItemCount;
7154 92 : aLayers.EnsureLengthAtLeast(aItemCount);
7155 92 : BackgroundItemComputer<nsCSSValueList, ComputedValueItem>
7156 92 : ::ComputeValue(aStyleContext, item,
7157 92 : aLayers[aItemCount-1].*aResultLocation,
7158 : aConditions);
7159 92 : item = item->mNext;
7160 : } while (item);
7161 68 : break;
7162 : }
7163 :
7164 : default:
7165 0 : MOZ_ASSERT(false, "unexpected unit");
7166 : }
7167 :
7168 1140 : if (aItemCount > aMaxItemCount)
7169 7 : aMaxItemCount = aItemCount;
7170 1140 : }
7171 :
7172 : // The same as SetImageLayerList, but for values stored in
7173 : // layer.mPosition.*aResultLocation instead of layer.*aResultLocation.
7174 : // This code is duplicated because it would be annoying to make
7175 : // SetImageLayerList generic enough to handle both cases.
7176 : static void
7177 456 : SetImageLayerPositionCoordList(
7178 : GeckoStyleContext* aStyleContext,
7179 : const nsCSSValue& aValue,
7180 : nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
7181 : const nsStyleAutoArray<nsStyleImageLayers::Layer>& aParentLayers,
7182 : Position::Coord
7183 : Position::* aResultLocation,
7184 : Position::Coord aInitialValue,
7185 : uint32_t aParentItemCount,
7186 : uint32_t& aItemCount,
7187 : uint32_t& aMaxItemCount,
7188 : bool& aRebuild,
7189 : RuleNodeCacheConditions& aConditions)
7190 : {
7191 456 : switch (aValue.GetUnit()) {
7192 : case eCSSUnit_Null:
7193 430 : break;
7194 :
7195 : case eCSSUnit_Inherit:
7196 0 : aRebuild = true;
7197 0 : aConditions.SetUncacheable();
7198 0 : aLayers.EnsureLengthAtLeast(aParentItemCount);
7199 0 : aItemCount = aParentItemCount;
7200 0 : for (uint32_t i = 0; i < aParentItemCount; ++i) {
7201 0 : aLayers[i].mPosition.*aResultLocation = aParentLayers[i].mPosition.*aResultLocation;
7202 : }
7203 0 : break;
7204 :
7205 : case eCSSUnit_Initial:
7206 : case eCSSUnit_Unset:
7207 0 : aRebuild = true;
7208 0 : aItemCount = 1;
7209 0 : aLayers[0].mPosition.*aResultLocation = aInitialValue;
7210 0 : break;
7211 :
7212 : case eCSSUnit_List:
7213 : case eCSSUnit_ListDep: {
7214 26 : aRebuild = true;
7215 26 : aItemCount = 0;
7216 26 : const nsCSSValueList* item = aValue.GetListValue();
7217 0 : do {
7218 26 : NS_ASSERTION(item->mValue.GetUnit() != eCSSUnit_Null &&
7219 : item->mValue.GetUnit() != eCSSUnit_Inherit &&
7220 : item->mValue.GetUnit() != eCSSUnit_Initial &&
7221 : item->mValue.GetUnit() != eCSSUnit_Unset,
7222 : "unexpected unit");
7223 26 : ++aItemCount;
7224 26 : aLayers.EnsureLengthAtLeast(aItemCount);
7225 :
7226 26 : ComputePositionCoordValue(aStyleContext, item->mValue,
7227 26 : aLayers[aItemCount-1].mPosition.*aResultLocation,
7228 26 : aConditions);
7229 26 : item = item->mNext;
7230 26 : } while (item);
7231 26 : break;
7232 : }
7233 :
7234 : default:
7235 0 : MOZ_ASSERT(false, "unexpected unit");
7236 : }
7237 :
7238 456 : if (aItemCount > aMaxItemCount)
7239 0 : aMaxItemCount = aItemCount;
7240 456 : }
7241 :
7242 : template <class ComputedValueItem>
7243 : static void
7244 456 : SetImageLayerPairList(GeckoStyleContext* aStyleContext,
7245 : const nsCSSValue& aValue,
7246 : nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
7247 : const nsStyleAutoArray<nsStyleImageLayers::Layer>& aParentLayers,
7248 : ComputedValueItem nsStyleImageLayers::Layer::*
7249 : aResultLocation,
7250 : ComputedValueItem aInitialValue,
7251 : uint32_t aParentItemCount,
7252 : uint32_t& aItemCount,
7253 : uint32_t& aMaxItemCount,
7254 : bool& aRebuild,
7255 : RuleNodeCacheConditions& aConditions)
7256 : {
7257 456 : switch (aValue.GetUnit()) {
7258 : case eCSSUnit_Null:
7259 415 : break;
7260 :
7261 : case eCSSUnit_Inherit:
7262 0 : aRebuild = true;
7263 0 : aConditions.SetUncacheable();
7264 0 : aLayers.EnsureLengthAtLeast(aParentItemCount);
7265 0 : aItemCount = aParentItemCount;
7266 0 : for (uint32_t i = 0; i < aParentItemCount; ++i) {
7267 0 : aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
7268 : }
7269 0 : break;
7270 :
7271 : case eCSSUnit_Initial:
7272 : case eCSSUnit_Unset:
7273 0 : aRebuild = true;
7274 0 : aItemCount = 1;
7275 0 : aLayers[0].*aResultLocation = aInitialValue;
7276 0 : break;
7277 :
7278 : case eCSSUnit_PairList:
7279 : case eCSSUnit_PairListDep: {
7280 41 : aRebuild = true;
7281 41 : aItemCount = 0;
7282 41 : const nsCSSValuePairList* item = aValue.GetPairListValue();
7283 46 : do {
7284 46 : NS_ASSERTION(item->mXValue.GetUnit() != eCSSUnit_Inherit &&
7285 : item->mXValue.GetUnit() != eCSSUnit_Initial &&
7286 : item->mXValue.GetUnit() != eCSSUnit_Unset &&
7287 : item->mYValue.GetUnit() != eCSSUnit_Inherit &&
7288 : item->mYValue.GetUnit() != eCSSUnit_Initial &&
7289 : item->mYValue.GetUnit() != eCSSUnit_Unset,
7290 : "unexpected unit");
7291 46 : ++aItemCount;
7292 46 : aLayers.EnsureLengthAtLeast(aItemCount);
7293 46 : BackgroundItemComputer<nsCSSValuePairList, ComputedValueItem>
7294 46 : ::ComputeValue(aStyleContext, item,
7295 46 : aLayers[aItemCount-1].*aResultLocation,
7296 : aConditions);
7297 46 : item = item->mNext;
7298 : } while (item);
7299 41 : break;
7300 : }
7301 :
7302 : default:
7303 0 : MOZ_ASSERT(false, "unexpected unit");
7304 : }
7305 :
7306 456 : if (aItemCount > aMaxItemCount)
7307 0 : aMaxItemCount = aItemCount;
7308 456 : }
7309 :
7310 : template <class ComputedValueItem>
7311 : static void
7312 405 : FillImageLayerList(
7313 : nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
7314 : ComputedValueItem nsStyleImageLayers::Layer::* aResultLocation,
7315 : uint32_t aItemCount, uint32_t aFillCount)
7316 : {
7317 405 : NS_PRECONDITION(aFillCount <= aLayers.Length(), "unexpected array length");
7318 502 : for (uint32_t sourceLayer = 0, destLayer = aItemCount;
7319 502 : destLayer < aFillCount;
7320 : ++sourceLayer, ++destLayer) {
7321 194 : aLayers[destLayer].*aResultLocation =
7322 97 : aLayers[sourceLayer].*aResultLocation;
7323 : }
7324 405 : }
7325 :
7326 : // The same as FillImageLayerList, but for values stored in
7327 : // layer.mPosition.*aResultLocation instead of layer.*aResultLocation.
7328 : static void
7329 90 : FillImageLayerPositionCoordList(
7330 : nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
7331 : Position::Coord
7332 : Position::* aResultLocation,
7333 : uint32_t aItemCount, uint32_t aFillCount)
7334 : {
7335 90 : NS_PRECONDITION(aFillCount <= aLayers.Length(), "unexpected array length");
7336 118 : for (uint32_t sourceLayer = 0, destLayer = aItemCount;
7337 118 : destLayer < aFillCount;
7338 : ++sourceLayer, ++destLayer) {
7339 56 : aLayers[destLayer].mPosition.*aResultLocation =
7340 28 : aLayers[sourceLayer].mPosition.*aResultLocation;
7341 : }
7342 90 : }
7343 :
7344 : /* static */
7345 : void
7346 45 : nsRuleNode::FillAllBackgroundLists(nsStyleImageLayers& aImage,
7347 : uint32_t aMaxItemCount)
7348 : {
7349 : // Delete any extra items. We need to keep layers in which any
7350 : // property was specified.
7351 45 : aImage.mLayers.TruncateLengthNonZero(aMaxItemCount);
7352 :
7353 45 : uint32_t fillCount = aImage.mImageCount;
7354 45 : FillImageLayerList(aImage.mLayers,
7355 : &nsStyleImageLayers::Layer::mImage,
7356 45 : aImage.mImageCount, fillCount);
7357 45 : FillImageLayerList(aImage.mLayers,
7358 : &nsStyleImageLayers::Layer::mRepeat,
7359 45 : aImage.mRepeatCount, fillCount);
7360 45 : FillImageLayerList(aImage.mLayers,
7361 : &nsStyleImageLayers::Layer::mAttachment,
7362 45 : aImage.mAttachmentCount, fillCount);
7363 45 : FillImageLayerList(aImage.mLayers,
7364 : &nsStyleImageLayers::Layer::mClip,
7365 45 : aImage.mClipCount, fillCount);
7366 45 : FillImageLayerList(aImage.mLayers,
7367 : &nsStyleImageLayers::Layer::mBlendMode,
7368 45 : aImage.mBlendModeCount, fillCount);
7369 45 : FillImageLayerList(aImage.mLayers,
7370 : &nsStyleImageLayers::Layer::mOrigin,
7371 45 : aImage.mOriginCount, fillCount);
7372 45 : FillImageLayerPositionCoordList(aImage.mLayers,
7373 : &Position::mXPosition,
7374 45 : aImage.mPositionXCount, fillCount);
7375 45 : FillImageLayerPositionCoordList(aImage.mLayers,
7376 : &Position::mYPosition,
7377 45 : aImage.mPositionYCount, fillCount);
7378 45 : FillImageLayerList(aImage.mLayers,
7379 : &nsStyleImageLayers::Layer::mSize,
7380 45 : aImage.mSizeCount, fillCount);
7381 45 : FillImageLayerList(aImage.mLayers,
7382 : &nsStyleImageLayers::Layer::mMaskMode,
7383 45 : aImage.mMaskModeCount, fillCount);
7384 45 : FillImageLayerList(aImage.mLayers,
7385 : &nsStyleImageLayers::Layer::mComposite,
7386 45 : aImage.mCompositeCount, fillCount);
7387 45 : }
7388 :
7389 : const void*
7390 198 : nsRuleNode::ComputeBackgroundData(void* aStartStruct,
7391 : const nsRuleData* aRuleData,
7392 : GeckoStyleContext* aContext,
7393 : nsRuleNode* aHighestNode,
7394 : const RuleDetail aRuleDetail,
7395 : const RuleNodeCacheConditions aConditions)
7396 : {
7397 396 : COMPUTE_START_RESET(Background, bg, parentBG)
7398 :
7399 : // background-color: color, inherit
7400 396 : SetComplexColor<eUnsetInitial>(*aRuleData->ValueForBackgroundColor(),
7401 : parentBG->mBackgroundColor,
7402 396 : StyleComplexColor::FromColor(
7403 : NS_RGBA(0, 0, 0, 0)),
7404 198 : mPresContext,
7405 198 : bg->mBackgroundColor, conditions);
7406 :
7407 198 : uint32_t maxItemCount = 1;
7408 198 : bool rebuild = false;
7409 :
7410 : // background-image: url (stored as image), none, inherit [list]
7411 396 : nsStyleImage initialImage;
7412 594 : SetImageLayerList(aContext, *aRuleData->ValueForBackgroundImage(),
7413 : bg->mImage.mLayers,
7414 : parentBG->mImage.mLayers,
7415 : &nsStyleImageLayers::Layer::mImage,
7416 198 : initialImage, parentBG->mImage.mImageCount,
7417 : bg->mImage.mImageCount,
7418 198 : maxItemCount, rebuild, conditions);
7419 :
7420 : // background-repeat: enum, inherit, initial [pair list]
7421 198 : nsStyleImageLayers::Repeat initialRepeat;
7422 198 : initialRepeat.SetInitialValues();
7423 396 : SetImageLayerPairList(aContext, *aRuleData->ValueForBackgroundRepeat(),
7424 : bg->mImage.mLayers,
7425 : parentBG->mImage.mLayers,
7426 : &nsStyleImageLayers::Layer::mRepeat,
7427 198 : initialRepeat, parentBG->mImage.mRepeatCount,
7428 : bg->mImage.mRepeatCount, maxItemCount, rebuild,
7429 198 : conditions);
7430 :
7431 : // background-attachment: enum, inherit, initial [list]
7432 396 : SetImageLayerList(aContext, *aRuleData->ValueForBackgroundAttachment(),
7433 : bg->mImage.mLayers, parentBG->mImage.mLayers,
7434 : &nsStyleImageLayers::Layer::mAttachment,
7435 : uint8_t(NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL),
7436 198 : parentBG->mImage.mAttachmentCount,
7437 : bg->mImage.mAttachmentCount, maxItemCount, rebuild,
7438 198 : conditions);
7439 :
7440 : // background-clip: enum, inherit, initial [list]
7441 396 : SetImageLayerList(aContext, *aRuleData->ValueForBackgroundClip(),
7442 : bg->mImage.mLayers,
7443 : parentBG->mImage.mLayers,
7444 : &nsStyleImageLayers::Layer::mClip,
7445 : StyleGeometryBox::BorderBox,
7446 198 : parentBG->mImage.mClipCount,
7447 198 : bg->mImage.mClipCount, maxItemCount, rebuild, conditions);
7448 :
7449 : // background-blend-mode: enum, inherit, initial [list]
7450 396 : SetImageLayerList(aContext, *aRuleData->ValueForBackgroundBlendMode(),
7451 : bg->mImage.mLayers,
7452 : parentBG->mImage.mLayers,
7453 : &nsStyleImageLayers::Layer::mBlendMode,
7454 : uint8_t(NS_STYLE_BLEND_NORMAL),
7455 198 : parentBG->mImage.mBlendModeCount,
7456 : bg->mImage.mBlendModeCount, maxItemCount, rebuild,
7457 198 : conditions);
7458 :
7459 : // background-origin: enum, inherit, initial [list]
7460 396 : SetImageLayerList(aContext, *aRuleData->ValueForBackgroundOrigin(),
7461 : bg->mImage.mLayers,
7462 : parentBG->mImage.mLayers,
7463 : &nsStyleImageLayers::Layer::mOrigin,
7464 : StyleGeometryBox::PaddingBox,
7465 198 : parentBG->mImage.mOriginCount,
7466 : bg->mImage.mOriginCount, maxItemCount, rebuild,
7467 198 : conditions);
7468 :
7469 : // background-position-x/y: enum, length, percent (flags), inherit [list]
7470 : Position::Coord initialPositionCoord;
7471 198 : initialPositionCoord.mPercent = 0.0f;
7472 198 : initialPositionCoord.mLength = 0;
7473 198 : initialPositionCoord.mHasPercent = true;
7474 :
7475 396 : SetImageLayerPositionCoordList(
7476 198 : aContext, *aRuleData->ValueForBackgroundPositionX(),
7477 : bg->mImage.mLayers,
7478 : parentBG->mImage.mLayers,
7479 : &Position::mXPosition,
7480 198 : initialPositionCoord, parentBG->mImage.mPositionXCount,
7481 : bg->mImage.mPositionXCount, maxItemCount, rebuild,
7482 198 : conditions);
7483 396 : SetImageLayerPositionCoordList(
7484 198 : aContext, *aRuleData->ValueForBackgroundPositionY(),
7485 : bg->mImage.mLayers,
7486 : parentBG->mImage.mLayers,
7487 : &Position::mYPosition,
7488 198 : initialPositionCoord, parentBG->mImage.mPositionYCount,
7489 : bg->mImage.mPositionYCount, maxItemCount, rebuild,
7490 198 : conditions);
7491 :
7492 : // background-size: enum, length, auto, inherit, initial [pair list]
7493 198 : nsStyleImageLayers::Size initialSize;
7494 198 : initialSize.SetInitialValues();
7495 396 : SetImageLayerPairList(aContext, *aRuleData->ValueForBackgroundSize(),
7496 : bg->mImage.mLayers,
7497 : parentBG->mImage.mLayers,
7498 : &nsStyleImageLayers::Layer::mSize,
7499 198 : initialSize, parentBG->mImage.mSizeCount,
7500 : bg->mImage.mSizeCount, maxItemCount, rebuild,
7501 198 : conditions);
7502 :
7503 198 : if (rebuild) {
7504 43 : FillAllBackgroundLists(bg->mImage, maxItemCount);
7505 : }
7506 :
7507 396 : COMPUTE_END_RESET(Background, bg)
7508 : }
7509 :
7510 : const void*
7511 214 : nsRuleNode::ComputeMarginData(void* aStartStruct,
7512 : const nsRuleData* aRuleData,
7513 : GeckoStyleContext* aContext,
7514 : nsRuleNode* aHighestNode,
7515 : const RuleDetail aRuleDetail,
7516 : const RuleNodeCacheConditions aConditions)
7517 : {
7518 428 : COMPUTE_START_RESET(Margin, margin, parentMargin)
7519 :
7520 : // margin: length, percent, calc, inherit
7521 : const nsCSSPropertyID* subprops =
7522 214 : nsCSSProps::SubpropertyEntryFor(eCSSProperty_margin);
7523 428 : nsStyleCoord coord;
7524 1070 : NS_FOR_CSS_SIDES(side) {
7525 1712 : nsStyleCoord parentCoord = parentMargin->mMargin.Get(side);
7526 856 : if (SetCoord(*aRuleData->ValueFor(subprops[side]),
7527 : coord, parentCoord,
7528 : SETCOORD_LPAH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
7529 : SETCOORD_UNSET_INITIAL,
7530 856 : aContext, mPresContext, conditions)) {
7531 510 : margin->mMargin.Set(side, coord);
7532 : }
7533 : }
7534 :
7535 428 : COMPUTE_END_RESET(Margin, margin)
7536 : }
7537 :
7538 : static void
7539 483 : SetBorderImageRect(const nsCSSValue& aValue,
7540 : /** outparam */ nsCSSRect& aRect)
7541 : {
7542 483 : switch (aValue.GetUnit()) {
7543 : case eCSSUnit_Null:
7544 300 : aRect.Reset();
7545 300 : break;
7546 : case eCSSUnit_Rect:
7547 183 : aRect = aValue.GetRectValue();
7548 183 : break;
7549 : case eCSSUnit_Inherit:
7550 : case eCSSUnit_Initial:
7551 : case eCSSUnit_Unset:
7552 0 : aRect.SetAllSidesTo(aValue);
7553 0 : break;
7554 : default:
7555 0 : NS_ASSERTION(false, "Unexpected border image value for rect.");
7556 : }
7557 483 : }
7558 :
7559 : static void
7560 161 : SetBorderImagePair(const nsCSSValue& aValue,
7561 : /** outparam */ nsCSSValuePair& aPair)
7562 : {
7563 161 : switch (aValue.GetUnit()) {
7564 : case eCSSUnit_Null:
7565 100 : aPair.Reset();
7566 100 : break;
7567 : case eCSSUnit_Pair:
7568 61 : aPair = aValue.GetPairValue();
7569 61 : break;
7570 : case eCSSUnit_Inherit:
7571 : case eCSSUnit_Initial:
7572 : case eCSSUnit_Unset:
7573 0 : aPair.SetBothValuesTo(aValue);
7574 0 : break;
7575 : default:
7576 0 : NS_ASSERTION(false, "Unexpected border image value for pair.");
7577 : }
7578 161 : }
7579 :
7580 : static void
7581 161 : SetBorderImageSlice(const nsCSSValue& aValue,
7582 : /** outparam */ nsCSSValue& aSlice,
7583 : /** outparam */ nsCSSValue& aFill)
7584 : {
7585 : const nsCSSValueList* valueList;
7586 161 : switch (aValue.GetUnit()) {
7587 : case eCSSUnit_Null:
7588 100 : aSlice.Reset();
7589 100 : aFill.Reset();
7590 100 : break;
7591 : case eCSSUnit_List:
7592 : // Get slice dimensions.
7593 61 : valueList = aValue.GetListValue();
7594 61 : aSlice = valueList->mValue;
7595 :
7596 : // Get "fill" keyword.
7597 61 : valueList = valueList->mNext;
7598 61 : if (valueList) {
7599 0 : aFill = valueList->mValue;
7600 : } else {
7601 61 : aFill.SetInitialValue();
7602 : }
7603 61 : break;
7604 : case eCSSUnit_Inherit:
7605 : case eCSSUnit_Initial:
7606 : case eCSSUnit_Unset:
7607 0 : aSlice = aValue;
7608 0 : aFill = aValue;
7609 0 : break;
7610 : default:
7611 0 : NS_ASSERTION(false, "Unexpected border image value for pair.");
7612 : }
7613 161 : }
7614 :
7615 : const void*
7616 161 : nsRuleNode::ComputeBorderData(void* aStartStruct,
7617 : const nsRuleData* aRuleData,
7618 : GeckoStyleContext* aContext,
7619 : nsRuleNode* aHighestNode,
7620 : const RuleDetail aRuleDetail,
7621 : const RuleNodeCacheConditions aConditions)
7622 : {
7623 322 : COMPUTE_START_RESET(Border, border, parentBorder)
7624 :
7625 : // box-decoration-break: enum, inherit, initial
7626 161 : SetValue(*aRuleData->ValueForBoxDecorationBreak(),
7627 : border->mBoxDecorationBreak, conditions,
7628 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
7629 161 : parentBorder->mBoxDecorationBreak,
7630 161 : StyleBoxDecorationBreak::Slice);
7631 :
7632 : // border-width, border-*-width: length, enum, inherit
7633 322 : nsStyleCoord coord;
7634 : {
7635 : const nsCSSPropertyID* subprops =
7636 161 : nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_width);
7637 805 : NS_FOR_CSS_SIDES(side) {
7638 644 : const nsCSSValue& value = *aRuleData->ValueFor(subprops[side]);
7639 644 : NS_ASSERTION(eCSSUnit_Percent != value.GetUnit(),
7640 : "Percentage borders not implemented yet "
7641 : "If implementing, make sure to fix all consumers of "
7642 : "nsStyleBorder, the IsPercentageAwareChild method, "
7643 : "the nsAbsoluteContainingBlock::FrameDependsOnContainer "
7644 : "method, the "
7645 : "nsLineLayout::IsPercentageAwareReplacedElement method "
7646 : "and probably some other places");
7647 : Maybe<nscoord> coord =
7648 : ComputeLineWidthValue<eUnsetInitial>(
7649 644 : value, parentBorder->GetComputedBorder().Side(side),
7650 : nsPresContext::GetBorderWidthForKeyword(NS_STYLE_BORDER_WIDTH_MEDIUM),
7651 1932 : aContext, mPresContext, conditions);
7652 644 : if (coord.isSome()) {
7653 282 : border->SetBorderWidth(side, *coord);
7654 : }
7655 : }
7656 : }
7657 :
7658 : // border-style, border-*-style: enum, inherit
7659 : {
7660 : const nsCSSPropertyID* subprops =
7661 161 : nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_style);
7662 805 : NS_FOR_CSS_SIDES(side) {
7663 644 : const nsCSSValue& value = *aRuleData->ValueFor(subprops[side]);
7664 644 : nsCSSUnit unit = value.GetUnit();
7665 644 : MOZ_ASSERT(eCSSUnit_None != unit,
7666 : "'none' should be handled as enumerated value");
7667 644 : if (eCSSUnit_Enumerated == unit) {
7668 292 : border->SetBorderStyle(side, value.GetIntValue());
7669 : }
7670 352 : else if (eCSSUnit_Initial == unit ||
7671 : eCSSUnit_Unset == unit) {
7672 0 : border->SetBorderStyle(side, NS_STYLE_BORDER_STYLE_NONE);
7673 : }
7674 352 : else if (eCSSUnit_Inherit == unit) {
7675 0 : conditions.SetUncacheable();
7676 0 : border->SetBorderStyle(side, parentBorder->GetBorderStyle(side));
7677 : }
7678 : }
7679 : }
7680 :
7681 : // -moz-border-*-colors: color, string, enum, none, inherit/initial
7682 : nscolor borderColor;
7683 161 : nscolor unused = NS_RGB(0,0,0);
7684 :
7685 : static const nsCSSPropertyID borderColorsProps[] = {
7686 : eCSSProperty__moz_border_top_colors,
7687 : eCSSProperty__moz_border_right_colors,
7688 : eCSSProperty__moz_border_bottom_colors,
7689 : eCSSProperty__moz_border_left_colors
7690 : };
7691 :
7692 805 : NS_FOR_CSS_SIDES(side) {
7693 644 : const nsCSSValue& value = *aRuleData->ValueFor(borderColorsProps[side]);
7694 644 : switch (value.GetUnit()) {
7695 : case eCSSUnit_Null:
7696 408 : break;
7697 :
7698 : case eCSSUnit_Initial:
7699 : case eCSSUnit_Unset:
7700 : case eCSSUnit_None:
7701 236 : border->ClearBorderColors(side);
7702 236 : break;
7703 :
7704 : case eCSSUnit_Inherit: {
7705 0 : conditions.SetUncacheable();
7706 0 : border->ClearBorderColors(side);
7707 0 : if (parentContext) {
7708 : nsBorderColors *parentColors;
7709 0 : parentBorder->GetCompositeColors(side, &parentColors);
7710 0 : if (parentColors) {
7711 0 : border->EnsureBorderColors();
7712 0 : border->mBorderColors[side] = parentColors->Clone();
7713 : }
7714 : }
7715 0 : break;
7716 : }
7717 :
7718 : case eCSSUnit_List:
7719 : case eCSSUnit_ListDep: {
7720 : // Some composite border color information has been specified for this
7721 : // border side.
7722 0 : border->EnsureBorderColors();
7723 0 : border->ClearBorderColors(side);
7724 0 : const nsCSSValueList* list = value.GetListValue();
7725 0 : while (list) {
7726 0 : if (SetColor(list->mValue, unused, mPresContext,
7727 : aContext, borderColor, conditions))
7728 0 : border->AppendBorderColor(side, borderColor);
7729 : else {
7730 0 : NS_NOTREACHED("unexpected item in -moz-border-*-colors list");
7731 : }
7732 0 : list = list->mNext;
7733 : }
7734 0 : break;
7735 : }
7736 :
7737 : default:
7738 0 : MOZ_ASSERT(false, "unrecognized border color unit");
7739 : }
7740 : }
7741 :
7742 : // border-color, border-*-color: color, string, enum, inherit
7743 : {
7744 : const nsCSSPropertyID* subprops =
7745 161 : nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color);
7746 805 : NS_FOR_CSS_SIDES(side) {
7747 1288 : SetComplexColor<eUnsetInitial>(*aRuleData->ValueFor(subprops[side]),
7748 644 : parentBorder->mBorderColor[side],
7749 1288 : StyleComplexColor::CurrentColor(),
7750 644 : mPresContext,
7751 1288 : border->mBorderColor[side], conditions);
7752 : }
7753 : }
7754 :
7755 : // border-radius: length, percent, inherit
7756 : {
7757 : const nsCSSPropertyID* subprops =
7758 161 : nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius);
7759 805 : NS_FOR_CSS_FULL_CORNERS(corner) {
7760 644 : int cx = FullToHalfCorner(corner, false);
7761 644 : int cy = FullToHalfCorner(corner, true);
7762 644 : const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
7763 1288 : nsStyleCoord parentX = parentBorder->mBorderRadius.Get(cx);
7764 1288 : nsStyleCoord parentY = parentBorder->mBorderRadius.Get(cy);
7765 1288 : nsStyleCoord coordX, coordY;
7766 :
7767 644 : if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
7768 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
7769 : SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
7770 644 : aContext, mPresContext, conditions)) {
7771 357 : border->mBorderRadius.Set(cx, coordX);
7772 357 : border->mBorderRadius.Set(cy, coordY);
7773 : }
7774 : }
7775 : }
7776 :
7777 : // float-edge: enum, inherit, initial
7778 161 : SetValue(*aRuleData->ValueForFloatEdge(),
7779 : border->mFloatEdge, conditions,
7780 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
7781 161 : parentBorder->mFloatEdge,
7782 161 : StyleFloatEdge::ContentBox);
7783 :
7784 : // border-image-source
7785 161 : const nsCSSValue* borderImageSource = aRuleData->ValueForBorderImageSource();
7786 161 : if (borderImageSource->GetUnit() == eCSSUnit_Inherit) {
7787 0 : conditions.SetUncacheable();
7788 0 : border->mBorderImageSource = parentBorder->mBorderImageSource;
7789 : } else {
7790 161 : SetStyleImage(aContext,
7791 : *borderImageSource,
7792 : border->mBorderImageSource,
7793 161 : conditions);
7794 : }
7795 :
7796 322 : nsCSSValue borderImageSliceValue;
7797 322 : nsCSSValue borderImageSliceFill;
7798 161 : SetBorderImageSlice(*aRuleData->ValueForBorderImageSlice(),
7799 161 : borderImageSliceValue, borderImageSliceFill);
7800 :
7801 : // border-image-slice: fill
7802 161 : SetValue(borderImageSliceFill,
7803 : border->mBorderImageFill,
7804 : conditions,
7805 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
7806 161 : parentBorder->mBorderImageFill,
7807 161 : NS_STYLE_BORDER_IMAGE_SLICE_NOFILL);
7808 :
7809 322 : nsCSSRect borderImageSlice;
7810 161 : SetBorderImageRect(borderImageSliceValue, borderImageSlice);
7811 :
7812 322 : nsCSSRect borderImageWidth;
7813 161 : SetBorderImageRect(*aRuleData->ValueForBorderImageWidth(),
7814 161 : borderImageWidth);
7815 :
7816 322 : nsCSSRect borderImageOutset;
7817 161 : SetBorderImageRect(*aRuleData->ValueForBorderImageOutset(),
7818 161 : borderImageOutset);
7819 :
7820 805 : NS_FOR_CSS_SIDES (side) {
7821 : // border-image-slice
7822 1288 : if (SetCoord(borderImageSlice.*(nsCSSRect::sides[side]), coord,
7823 1288 : parentBorder->mBorderImageSlice.Get(side),
7824 : SETCOORD_FACTOR | SETCOORD_PERCENT |
7825 : SETCOORD_INHERIT | SETCOORD_INITIAL_HUNDRED_PCT |
7826 : SETCOORD_UNSET_INITIAL,
7827 644 : aContext, mPresContext, conditions)) {
7828 244 : border->mBorderImageSlice.Set(side, coord);
7829 : }
7830 :
7831 : // border-image-width
7832 : // 'auto' here means "same as slice"
7833 1288 : if (SetCoord(borderImageWidth.*(nsCSSRect::sides[side]), coord,
7834 1288 : parentBorder->mBorderImageWidth.Get(side),
7835 : SETCOORD_LPAH | SETCOORD_FACTOR | SETCOORD_INITIAL_FACTOR_ONE |
7836 : SETCOORD_UNSET_INITIAL,
7837 644 : aContext, mPresContext, conditions)) {
7838 244 : border->mBorderImageWidth.Set(side, coord);
7839 : }
7840 :
7841 : // border-image-outset
7842 1288 : if (SetCoord(borderImageOutset.*(nsCSSRect::sides[side]), coord,
7843 1288 : parentBorder->mBorderImageOutset.Get(side),
7844 : SETCOORD_LENGTH | SETCOORD_FACTOR |
7845 : SETCOORD_INHERIT | SETCOORD_INITIAL_FACTOR_ZERO |
7846 : SETCOORD_UNSET_INITIAL,
7847 644 : aContext, mPresContext, conditions)) {
7848 244 : border->mBorderImageOutset.Set(side, coord);
7849 : }
7850 : }
7851 :
7852 : // border-image-repeat
7853 322 : nsCSSValuePair borderImageRepeat;
7854 161 : SetBorderImagePair(*aRuleData->ValueForBorderImageRepeat(),
7855 161 : borderImageRepeat);
7856 :
7857 161 : SetValue(borderImageRepeat.mXValue,
7858 : border->mBorderImageRepeatH,
7859 : conditions,
7860 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
7861 161 : parentBorder->mBorderImageRepeatH,
7862 161 : NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH);
7863 :
7864 161 : SetValue(borderImageRepeat.mYValue,
7865 : border->mBorderImageRepeatV,
7866 : conditions,
7867 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
7868 161 : parentBorder->mBorderImageRepeatV,
7869 161 : NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH);
7870 :
7871 322 : COMPUTE_END_RESET(Border, border)
7872 : }
7873 :
7874 : const void*
7875 145 : nsRuleNode::ComputePaddingData(void* aStartStruct,
7876 : const nsRuleData* aRuleData,
7877 : GeckoStyleContext* aContext,
7878 : nsRuleNode* aHighestNode,
7879 : const RuleDetail aRuleDetail,
7880 : const RuleNodeCacheConditions aConditions)
7881 : {
7882 290 : COMPUTE_START_RESET(Padding, padding, parentPadding)
7883 :
7884 : // padding: length, percent, calc, inherit
7885 : const nsCSSPropertyID* subprops =
7886 145 : nsCSSProps::SubpropertyEntryFor(eCSSProperty_padding);
7887 290 : nsStyleCoord coord;
7888 725 : NS_FOR_CSS_SIDES(side) {
7889 1160 : nsStyleCoord parentCoord = parentPadding->mPadding.Get(side);
7890 580 : if (SetCoord(*aRuleData->ValueFor(subprops[side]),
7891 : coord, parentCoord,
7892 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
7893 : SETCOORD_UNSET_INITIAL,
7894 580 : aContext, mPresContext, conditions)) {
7895 455 : padding->mPadding.Set(side, coord);
7896 : }
7897 : }
7898 :
7899 290 : COMPUTE_END_RESET(Padding, padding)
7900 : }
7901 :
7902 : const void*
7903 26 : nsRuleNode::ComputeOutlineData(void* aStartStruct,
7904 : const nsRuleData* aRuleData,
7905 : GeckoStyleContext* aContext,
7906 : nsRuleNode* aHighestNode,
7907 : const RuleDetail aRuleDetail,
7908 : const RuleNodeCacheConditions aConditions)
7909 : {
7910 52 : COMPUTE_START_RESET(Outline, outline, parentOutline)
7911 :
7912 : // outline-width: length, enum, inherit
7913 : Maybe<nscoord> coord =
7914 : ComputeLineWidthValue<eUnsetInitial>(
7915 26 : *aRuleData->ValueForOutlineWidth(), parentOutline->mOutlineWidth,
7916 : nsPresContext::GetBorderWidthForKeyword(NS_STYLE_BORDER_WIDTH_MEDIUM),
7917 78 : aContext, mPresContext, conditions);
7918 26 : if (coord.isSome()) {
7919 0 : outline->mOutlineWidth = *coord;
7920 : }
7921 :
7922 : // outline-offset: length, inherit
7923 52 : nsStyleCoord tempCoord;
7924 26 : const nsCSSValue* outlineOffsetValue = aRuleData->ValueForOutlineOffset();
7925 52 : if (SetCoord(*outlineOffsetValue, tempCoord,
7926 52 : nsStyleCoord(parentOutline->mOutlineOffset,
7927 : nsStyleCoord::CoordConstructor),
7928 : SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
7929 : SETCOORD_UNSET_INITIAL,
7930 26 : aContext, mPresContext, conditions)) {
7931 0 : outline->mOutlineOffset = tempCoord.GetCoordValue();
7932 : } else {
7933 26 : NS_ASSERTION(outlineOffsetValue->GetUnit() == eCSSUnit_Null,
7934 : "unexpected unit");
7935 : }
7936 :
7937 : // outline-color: color, string, enum, inherit
7938 52 : SetComplexColor<eUnsetInitial>(*aRuleData->ValueForOutlineColor(),
7939 : parentOutline->mOutlineColor,
7940 52 : StyleComplexColor::CurrentColor(),
7941 26 : mPresContext,
7942 26 : outline->mOutlineColor, conditions);
7943 :
7944 : // -moz-outline-radius: length, percent, inherit
7945 : {
7946 : const nsCSSPropertyID* subprops =
7947 26 : nsCSSProps::SubpropertyEntryFor(eCSSProperty__moz_outline_radius);
7948 130 : NS_FOR_CSS_FULL_CORNERS(corner) {
7949 104 : int cx = FullToHalfCorner(corner, false);
7950 104 : int cy = FullToHalfCorner(corner, true);
7951 104 : const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
7952 208 : nsStyleCoord parentX = parentOutline->mOutlineRadius.Get(cx);
7953 208 : nsStyleCoord parentY = parentOutline->mOutlineRadius.Get(cy);
7954 208 : nsStyleCoord coordX, coordY;
7955 :
7956 104 : if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
7957 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
7958 : SETCOORD_STORE_CALC | SETCOORD_UNSET_INITIAL,
7959 104 : aContext, mPresContext, conditions)) {
7960 0 : outline->mOutlineRadius.Set(cx, coordX);
7961 0 : outline->mOutlineRadius.Set(cy, coordY);
7962 : }
7963 : }
7964 : }
7965 :
7966 : // outline-style: enum, inherit, initial
7967 : // cannot use SetValue because of SetOutlineStyle
7968 26 : const nsCSSValue* outlineStyleValue = aRuleData->ValueForOutlineStyle();
7969 26 : nsCSSUnit unit = outlineStyleValue->GetUnit();
7970 26 : MOZ_ASSERT(eCSSUnit_None != unit && eCSSUnit_Auto != unit,
7971 : "'none' and 'auto' should be handled as enumerated values");
7972 26 : if (eCSSUnit_Enumerated == unit) {
7973 0 : outline->mOutlineStyle = outlineStyleValue->GetIntValue();
7974 26 : } else if (eCSSUnit_Initial == unit ||
7975 : eCSSUnit_Unset == unit) {
7976 0 : outline->mOutlineStyle = NS_STYLE_BORDER_STYLE_NONE;
7977 26 : } else if (eCSSUnit_Inherit == unit) {
7978 0 : conditions.SetUncacheable();
7979 0 : outline->mOutlineStyle = parentOutline->mOutlineStyle;
7980 : }
7981 :
7982 26 : outline->RecalcData();
7983 52 : COMPUTE_END_RESET(Outline, outline)
7984 : }
7985 :
7986 : const void*
7987 130 : nsRuleNode::ComputeListData(void* aStartStruct,
7988 : const nsRuleData* aRuleData,
7989 : GeckoStyleContext* aContext,
7990 : nsRuleNode* aHighestNode,
7991 : const RuleDetail aRuleDetail,
7992 : const RuleNodeCacheConditions aConditions)
7993 : {
7994 260 : COMPUTE_START_INHERITED(List, list, parentList)
7995 :
7996 : // quotes: inherit, initial, none, [string string]+
7997 130 : const nsCSSValue* quotesValue = aRuleData->ValueForQuotes();
7998 130 : switch (quotesValue->GetUnit()) {
7999 : case eCSSUnit_Null:
8000 130 : break;
8001 : case eCSSUnit_Inherit:
8002 : case eCSSUnit_Unset:
8003 0 : conditions.SetUncacheable();
8004 0 : list->SetQuotesInherit(parentList);
8005 0 : break;
8006 : case eCSSUnit_Initial:
8007 0 : list->SetQuotesInitial();
8008 0 : break;
8009 : case eCSSUnit_None:
8010 0 : list->SetQuotesNone();
8011 0 : break;
8012 : case eCSSUnit_PairList:
8013 : case eCSSUnit_PairListDep: {
8014 0 : const nsCSSValuePairList* ourQuotes = quotesValue->GetPairListValue();
8015 :
8016 0 : nsStyleQuoteValues::QuotePairArray quotePairs;
8017 0 : quotePairs.SetLength(ListLength(ourQuotes));
8018 :
8019 0 : size_t index = 0;
8020 0 : nsAutoString buffer;
8021 0 : while (ourQuotes) {
8022 0 : MOZ_ASSERT(ourQuotes->mXValue.GetUnit() == eCSSUnit_String &&
8023 : ourQuotes->mYValue.GetUnit() == eCSSUnit_String,
8024 : "improper list contents for quotes");
8025 0 : quotePairs[index].first = ourQuotes->mXValue.GetStringValue(buffer);
8026 0 : quotePairs[index].second = ourQuotes->mYValue.GetStringValue(buffer);
8027 0 : ++index;
8028 0 : ourQuotes = ourQuotes->mNext;
8029 : }
8030 0 : list->SetQuotes(Move(quotePairs));
8031 0 : break;
8032 : }
8033 : default:
8034 0 : MOZ_ASSERT(false, "unexpected value unit");
8035 : }
8036 :
8037 : // list-style-type: string, none, inherit, initial
8038 130 : const nsCSSValue* typeValue = aRuleData->ValueForListStyleType();
8039 0 : auto setListStyleType = [this, list](nsIAtom* type) {
8040 0 : list->mCounterStyle = mPresContext->
8041 0 : CounterStyleManager()->BuildCounterStyle(type);
8042 130 : };
8043 130 : switch (typeValue->GetUnit()) {
8044 : case eCSSUnit_Unset:
8045 : case eCSSUnit_Inherit: {
8046 0 : conditions.SetUncacheable();
8047 0 : list->mCounterStyle = parentList->mCounterStyle;
8048 0 : break;
8049 : }
8050 : case eCSSUnit_Initial:
8051 0 : setListStyleType(nsGkAtoms::disc);
8052 0 : break;
8053 : case eCSSUnit_AtomIdent: {
8054 0 : setListStyleType(typeValue->GetAtomValue());
8055 0 : break;
8056 : }
8057 : case eCSSUnit_String: {
8058 0 : nsString str;
8059 0 : typeValue->GetStringValue(str);
8060 0 : list->mCounterStyle = new AnonymousCounterStyle(str);
8061 0 : break;
8062 : }
8063 : case eCSSUnit_Enumerated: {
8064 : // For compatibility with html attribute map.
8065 : // This branch should never be called for value from CSS.
8066 0 : int32_t intValue = typeValue->GetIntValue();
8067 0 : nsCOMPtr<nsIAtom> name;
8068 0 : switch (intValue) {
8069 : case NS_STYLE_LIST_STYLE_LOWER_ROMAN:
8070 0 : name = nsGkAtoms::lowerRoman;
8071 0 : break;
8072 : case NS_STYLE_LIST_STYLE_UPPER_ROMAN:
8073 0 : name = nsGkAtoms::upperRoman;
8074 0 : break;
8075 : case NS_STYLE_LIST_STYLE_LOWER_ALPHA:
8076 0 : name = nsGkAtoms::lowerAlpha;
8077 0 : break;
8078 : case NS_STYLE_LIST_STYLE_UPPER_ALPHA:
8079 0 : name = nsGkAtoms::upperAlpha;
8080 0 : break;
8081 : default:
8082 0 : name = NS_Atomize(nsCSSProps::ValueToKeyword(
8083 0 : intValue, nsCSSProps::kListStyleKTable));
8084 0 : break;
8085 : }
8086 0 : setListStyleType(name);
8087 0 : break;
8088 : }
8089 : case eCSSUnit_Symbols:
8090 : list->mCounterStyle =
8091 0 : new AnonymousCounterStyle(typeValue->GetArrayValue());
8092 0 : break;
8093 : case eCSSUnit_Null:
8094 130 : break;
8095 : default:
8096 0 : NS_NOTREACHED("Unexpected value unit");
8097 : }
8098 :
8099 : // list-style-image: url, none, inherit
8100 130 : const nsCSSValue* imageValue = aRuleData->ValueForListStyleImage();
8101 130 : if (eCSSUnit_Image == imageValue->GetUnit()) {
8102 234 : list->mListStyleImage = CreateStyleImageRequest(
8103 234 : mPresContext, *imageValue, nsStyleImageRequest::Mode(0));
8104 : }
8105 13 : else if (eCSSUnit_None == imageValue->GetUnit() ||
8106 0 : eCSSUnit_Initial == imageValue->GetUnit()) {
8107 13 : list->mListStyleImage = nullptr;
8108 : }
8109 0 : else if (eCSSUnit_Inherit == imageValue->GetUnit() ||
8110 0 : eCSSUnit_Unset == imageValue->GetUnit()) {
8111 0 : conditions.SetUncacheable();
8112 0 : list->mListStyleImage = parentList->mListStyleImage;
8113 : }
8114 :
8115 : // list-style-position: enum, inherit, initial
8116 130 : SetValue(*aRuleData->ValueForListStylePosition(),
8117 : list->mListStylePosition, conditions,
8118 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
8119 130 : parentList->mListStylePosition,
8120 130 : NS_STYLE_LIST_STYLE_POSITION_OUTSIDE);
8121 :
8122 : // image region property: length, auto, inherit
8123 130 : const nsCSSValue* imageRegionValue = aRuleData->ValueForImageRegion();
8124 130 : switch (imageRegionValue->GetUnit()) {
8125 : case eCSSUnit_Inherit:
8126 : case eCSSUnit_Unset:
8127 0 : conditions.SetUncacheable();
8128 0 : list->mImageRegion = parentList->mImageRegion;
8129 0 : break;
8130 :
8131 : case eCSSUnit_Initial:
8132 : case eCSSUnit_Auto:
8133 14 : list->mImageRegion.SetRect(0,0,0,0);
8134 14 : break;
8135 :
8136 : case eCSSUnit_Null:
8137 109 : break;
8138 :
8139 : case eCSSUnit_Rect: {
8140 7 : const nsCSSRect& rgnRect = imageRegionValue->GetRectValue();
8141 :
8142 7 : if (rgnRect.mTop.GetUnit() == eCSSUnit_Auto)
8143 0 : list->mImageRegion.y = 0;
8144 7 : else if (rgnRect.mTop.IsLengthUnit())
8145 7 : list->mImageRegion.y =
8146 7 : CalcLength(rgnRect.mTop, aContext, mPresContext, conditions);
8147 :
8148 7 : if (rgnRect.mBottom.GetUnit() == eCSSUnit_Auto)
8149 0 : list->mImageRegion.height = 0;
8150 7 : else if (rgnRect.mBottom.IsLengthUnit())
8151 7 : list->mImageRegion.height =
8152 7 : CalcLength(rgnRect.mBottom, aContext, mPresContext,
8153 7 : conditions) - list->mImageRegion.y;
8154 :
8155 7 : if (rgnRect.mLeft.GetUnit() == eCSSUnit_Auto)
8156 0 : list->mImageRegion.x = 0;
8157 7 : else if (rgnRect.mLeft.IsLengthUnit())
8158 7 : list->mImageRegion.x =
8159 7 : CalcLength(rgnRect.mLeft, aContext, mPresContext, conditions);
8160 :
8161 7 : if (rgnRect.mRight.GetUnit() == eCSSUnit_Auto)
8162 0 : list->mImageRegion.width = 0;
8163 7 : else if (rgnRect.mRight.IsLengthUnit())
8164 7 : list->mImageRegion.width =
8165 7 : CalcLength(rgnRect.mRight, aContext, mPresContext,
8166 7 : conditions) - list->mImageRegion.x;
8167 7 : break;
8168 : }
8169 :
8170 : default:
8171 0 : MOZ_ASSERT(false, "unrecognized image-region unit");
8172 : }
8173 :
8174 260 : COMPUTE_END_INHERITED(List, list)
8175 : }
8176 :
8177 : static void
8178 0 : SetGridTrackBreadth(const nsCSSValue& aValue,
8179 : nsStyleCoord& aResult,
8180 : GeckoStyleContext* aStyleContext,
8181 : nsPresContext* aPresContext,
8182 : RuleNodeCacheConditions& aConditions)
8183 : {
8184 0 : nsCSSUnit unit = aValue.GetUnit();
8185 0 : if (unit == eCSSUnit_FlexFraction) {
8186 0 : aResult.SetFlexFractionValue(aValue.GetFloatValue());
8187 0 : } else if (unit == eCSSUnit_Auto) {
8188 0 : aResult.SetAutoValue();
8189 0 : } else if (unit == eCSSUnit_None) {
8190 : // For fit-content().
8191 0 : aResult.SetNoneValue();
8192 : } else {
8193 0 : MOZ_ASSERT(unit != eCSSUnit_Inherit && unit != eCSSUnit_Unset,
8194 : "Unexpected value that would use dummyParentCoord");
8195 0 : const nsStyleCoord dummyParentCoord;
8196 : DebugOnly<bool> stored =
8197 0 : SetCoord(aValue, aResult, dummyParentCoord,
8198 : SETCOORD_LPE | SETCOORD_STORE_CALC,
8199 0 : aStyleContext, aPresContext, aConditions);
8200 0 : MOZ_ASSERT(stored, "invalid <track-size> value");
8201 : }
8202 0 : }
8203 :
8204 : static void
8205 0 : SetGridTrackSize(const nsCSSValue& aValue,
8206 : nsStyleCoord& aResultMin,
8207 : nsStyleCoord& aResultMax,
8208 : GeckoStyleContext* aStyleContext,
8209 : nsPresContext* aPresContext,
8210 : RuleNodeCacheConditions& aConditions)
8211 : {
8212 0 : if (aValue.GetUnit() == eCSSUnit_Function) {
8213 0 : nsCSSValue::Array* func = aValue.GetArrayValue();
8214 0 : auto funcName = func->Item(0).GetKeywordValue();
8215 0 : if (funcName == eCSSKeyword_minmax) {
8216 0 : SetGridTrackBreadth(func->Item(1), aResultMin,
8217 0 : aStyleContext, aPresContext, aConditions);
8218 0 : SetGridTrackBreadth(func->Item(2), aResultMax,
8219 0 : aStyleContext, aPresContext, aConditions);
8220 0 : } else if (funcName == eCSSKeyword_fit_content) {
8221 : // We represent fit-content(L) as 'none' min-sizing and L max-sizing.
8222 0 : SetGridTrackBreadth(nsCSSValue(eCSSUnit_None), aResultMin,
8223 0 : aStyleContext, aPresContext, aConditions);
8224 0 : SetGridTrackBreadth(func->Item(1), aResultMax,
8225 0 : aStyleContext, aPresContext, aConditions);
8226 : } else {
8227 0 : NS_ERROR("Expected minmax() or fit-content(), got another function name");
8228 : }
8229 : } else {
8230 : // A single <track-breadth>,
8231 : // specifies identical min and max sizing functions.
8232 : SetGridTrackBreadth(aValue, aResultMin,
8233 0 : aStyleContext, aPresContext, aConditions);
8234 0 : aResultMax = aResultMin;
8235 : }
8236 0 : }
8237 :
8238 : static void
8239 562 : SetGridAutoColumnsRows(const nsCSSValue& aValue,
8240 : nsStyleCoord& aResultMin,
8241 : nsStyleCoord& aResultMax,
8242 : const nsStyleCoord& aParentValueMin,
8243 : const nsStyleCoord& aParentValueMax,
8244 : GeckoStyleContext* aStyleContext,
8245 : nsPresContext* aPresContext,
8246 : RuleNodeCacheConditions& aConditions)
8247 :
8248 : {
8249 562 : switch (aValue.GetUnit()) {
8250 : case eCSSUnit_Null:
8251 464 : break;
8252 :
8253 : case eCSSUnit_Inherit:
8254 98 : aConditions.SetUncacheable();
8255 98 : aResultMin = aParentValueMin;
8256 98 : aResultMax = aParentValueMax;
8257 98 : break;
8258 :
8259 : case eCSSUnit_Initial:
8260 : case eCSSUnit_Unset:
8261 : // The initial value is 'auto',
8262 : // which computes to 'minmax(auto, auto)'.
8263 : // (Explicitly-specified 'auto' values are handled in SetGridTrackSize.)
8264 0 : aResultMin.SetAutoValue();
8265 0 : aResultMax.SetAutoValue();
8266 0 : break;
8267 :
8268 : default:
8269 : SetGridTrackSize(aValue, aResultMin, aResultMax,
8270 0 : aStyleContext, aPresContext, aConditions);
8271 : }
8272 562 : }
8273 :
8274 : static void
8275 0 : AppendGridLineNames(const nsCSSValue& aValue,
8276 : nsTArray<nsString>& aNameList)
8277 : {
8278 : // Compute a <line-names> value
8279 : // Null unit means empty list, nothing more to do.
8280 0 : if (aValue.GetUnit() != eCSSUnit_Null) {
8281 0 : const nsCSSValueList* item = aValue.GetListValue();
8282 0 : do {
8283 0 : nsString* name = aNameList.AppendElement();
8284 0 : item->mValue.GetStringValue(*name);
8285 0 : item = item->mNext;
8286 0 : } while (item);
8287 : }
8288 0 : }
8289 :
8290 : static void
8291 562 : SetGridTrackList(const nsCSSValue& aValue,
8292 : nsStyleGridTemplate& aResult,
8293 : const nsStyleGridTemplate& aParentValue,
8294 : GeckoStyleContext* aStyleContext,
8295 : nsPresContext* aPresContext,
8296 : RuleNodeCacheConditions& aConditions)
8297 :
8298 : {
8299 562 : switch (aValue.GetUnit()) {
8300 : case eCSSUnit_Null:
8301 464 : break;
8302 :
8303 : case eCSSUnit_Inherit:
8304 98 : aConditions.SetUncacheable();
8305 98 : aResult = aParentValue;
8306 98 : break;
8307 :
8308 : case eCSSUnit_Initial:
8309 : case eCSSUnit_Unset:
8310 : case eCSSUnit_None:
8311 0 : aResult.mIsSubgrid = false;
8312 0 : aResult.mLineNameLists.Clear();
8313 0 : aResult.mMinTrackSizingFunctions.Clear();
8314 0 : aResult.mMaxTrackSizingFunctions.Clear();
8315 0 : aResult.mRepeatAutoLineNameListBefore.Clear();
8316 0 : aResult.mRepeatAutoLineNameListAfter.Clear();
8317 0 : aResult.mRepeatAutoIndex = -1;
8318 0 : aResult.mIsAutoFill = false;
8319 0 : break;
8320 :
8321 : default:
8322 0 : aResult.mLineNameLists.Clear();
8323 0 : aResult.mMinTrackSizingFunctions.Clear();
8324 0 : aResult.mMaxTrackSizingFunctions.Clear();
8325 0 : aResult.mRepeatAutoLineNameListBefore.Clear();
8326 0 : aResult.mRepeatAutoLineNameListAfter.Clear();
8327 0 : aResult.mRepeatAutoIndex = -1;
8328 0 : aResult.mIsAutoFill = false;
8329 0 : const nsCSSValueList* item = aValue.GetListValue();
8330 0 : if (item->mValue.GetUnit() == eCSSUnit_Enumerated &&
8331 0 : item->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) {
8332 : // subgrid <line-name-list>?
8333 0 : aResult.mIsSubgrid = true;
8334 0 : item = item->mNext;
8335 0 : for (int32_t i = 0; item && i < nsStyleGridLine::kMaxLine; ++i) {
8336 0 : if (item->mValue.GetUnit() == eCSSUnit_Pair) {
8337 : // This is a 'auto-fill' <name-repeat> expression.
8338 0 : const nsCSSValuePair& pair = item->mValue.GetPairValue();
8339 0 : MOZ_ASSERT(aResult.mRepeatAutoIndex == -1,
8340 : "can only have one <name-repeat> with auto-fill");
8341 0 : aResult.mRepeatAutoIndex = i;
8342 0 : aResult.mIsAutoFill = true;
8343 0 : MOZ_ASSERT(pair.mXValue.GetIntValue() == NS_STYLE_GRID_REPEAT_AUTO_FILL,
8344 : "unexpected repeat() enum value for subgrid");
8345 0 : const nsCSSValueList* list = pair.mYValue.GetListValue();
8346 0 : AppendGridLineNames(list->mValue, aResult.mRepeatAutoLineNameListBefore);
8347 : } else {
8348 0 : AppendGridLineNames(item->mValue,
8349 0 : *aResult.mLineNameLists.AppendElement());
8350 : }
8351 0 : item = item->mNext;
8352 : }
8353 : } else {
8354 : // <track-list>
8355 : // The list is expected to have odd number of items, at least 3
8356 : // starting with a <line-names> (sub list of identifiers),
8357 : // and alternating between that and <track-size>.
8358 0 : aResult.mIsSubgrid = false;
8359 0 : for (int32_t line = 1; ; ++line) {
8360 0 : AppendGridLineNames(item->mValue,
8361 0 : *aResult.mLineNameLists.AppendElement());
8362 0 : item = item->mNext;
8363 :
8364 0 : if (!item || line == nsStyleGridLine::kMaxLine) {
8365 : break;
8366 : }
8367 :
8368 0 : if (item->mValue.GetUnit() == eCSSUnit_Pair) {
8369 : // This is a 'auto-fill' / 'auto-fit' <auto-repeat> expression.
8370 0 : const nsCSSValuePair& pair = item->mValue.GetPairValue();
8371 0 : MOZ_ASSERT(aResult.mRepeatAutoIndex == -1,
8372 : "can only have one <auto-repeat>");
8373 0 : aResult.mRepeatAutoIndex = line - 1;
8374 0 : switch (pair.mXValue.GetIntValue()) {
8375 : case NS_STYLE_GRID_REPEAT_AUTO_FILL:
8376 0 : aResult.mIsAutoFill = true;
8377 0 : break;
8378 : case NS_STYLE_GRID_REPEAT_AUTO_FIT:
8379 0 : aResult.mIsAutoFill = false;
8380 0 : break;
8381 : default:
8382 0 : MOZ_ASSERT_UNREACHABLE("unexpected repeat() enum value");
8383 : }
8384 0 : const nsCSSValueList* list = pair.mYValue.GetListValue();
8385 0 : AppendGridLineNames(list->mValue, aResult.mRepeatAutoLineNameListBefore);
8386 0 : list = list->mNext;
8387 0 : nsStyleCoord& min = *aResult.mMinTrackSizingFunctions.AppendElement();
8388 0 : nsStyleCoord& max = *aResult.mMaxTrackSizingFunctions.AppendElement();
8389 0 : SetGridTrackSize(list->mValue, min, max,
8390 0 : aStyleContext, aPresContext, aConditions);
8391 0 : list = list->mNext;
8392 0 : AppendGridLineNames(list->mValue, aResult.mRepeatAutoLineNameListAfter);
8393 : } else {
8394 0 : nsStyleCoord& min = *aResult.mMinTrackSizingFunctions.AppendElement();
8395 0 : nsStyleCoord& max = *aResult.mMaxTrackSizingFunctions.AppendElement();
8396 0 : SetGridTrackSize(item->mValue, min, max,
8397 0 : aStyleContext, aPresContext, aConditions);
8398 : }
8399 :
8400 0 : item = item->mNext;
8401 0 : MOZ_ASSERT(item, "Expected a eCSSUnit_List of odd length");
8402 0 : }
8403 0 : MOZ_ASSERT(!aResult.mMinTrackSizingFunctions.IsEmpty() &&
8404 : aResult.mMinTrackSizingFunctions.Length() ==
8405 : aResult.mMaxTrackSizingFunctions.Length() &&
8406 : aResult.mMinTrackSizingFunctions.Length() + 1 ==
8407 : aResult.mLineNameLists.Length(),
8408 : "Inconstistent array lengths for nsStyleGridTemplate");
8409 : }
8410 : }
8411 562 : }
8412 :
8413 : static void
8414 281 : SetGridTemplateAreas(const nsCSSValue& aValue,
8415 : RefPtr<css::GridTemplateAreasValue>* aResult,
8416 : css::GridTemplateAreasValue* aParentValue,
8417 : RuleNodeCacheConditions& aConditions)
8418 : {
8419 281 : switch (aValue.GetUnit()) {
8420 : case eCSSUnit_Null:
8421 232 : break;
8422 :
8423 : case eCSSUnit_Inherit:
8424 49 : aConditions.SetUncacheable();
8425 49 : *aResult = aParentValue;
8426 49 : break;
8427 :
8428 : case eCSSUnit_Initial:
8429 : case eCSSUnit_Unset:
8430 : case eCSSUnit_None:
8431 0 : *aResult = nullptr;
8432 0 : break;
8433 :
8434 : default:
8435 0 : *aResult = aValue.GetGridTemplateAreas();
8436 : }
8437 281 : }
8438 :
8439 : static void
8440 1124 : SetGridLine(const nsCSSValue& aValue,
8441 : nsStyleGridLine& aResult,
8442 : const nsStyleGridLine& aParentValue,
8443 : RuleNodeCacheConditions& aConditions)
8444 :
8445 : {
8446 1124 : switch (aValue.GetUnit()) {
8447 : case eCSSUnit_Null:
8448 1124 : break;
8449 :
8450 : case eCSSUnit_Inherit:
8451 0 : aConditions.SetUncacheable();
8452 0 : aResult = aParentValue;
8453 0 : break;
8454 :
8455 : case eCSSUnit_Initial:
8456 : case eCSSUnit_Unset:
8457 : case eCSSUnit_Auto:
8458 0 : aResult.SetAuto();
8459 0 : break;
8460 :
8461 : default:
8462 0 : aResult.SetAuto(); // Reset any existing value.
8463 0 : const nsCSSValueList* item = aValue.GetListValue();
8464 0 : do {
8465 0 : if (item->mValue.GetUnit() == eCSSUnit_Enumerated) {
8466 0 : aResult.mHasSpan = true;
8467 0 : } else if (item->mValue.GetUnit() == eCSSUnit_Integer) {
8468 0 : aResult.mInteger = clamped(item->mValue.GetIntValue(),
8469 : nsStyleGridLine::kMinLine,
8470 0 : nsStyleGridLine::kMaxLine);
8471 0 : } else if (item->mValue.GetUnit() == eCSSUnit_Ident) {
8472 0 : item->mValue.GetStringValue(aResult.mLineName);
8473 : } else {
8474 0 : NS_ASSERTION(false, "Unexpected unit");
8475 : }
8476 0 : item = item->mNext;
8477 0 : } while (item);
8478 0 : MOZ_ASSERT(!aResult.IsAuto(),
8479 : "should have set something away from default value");
8480 : }
8481 1124 : }
8482 :
8483 : const void*
8484 281 : nsRuleNode::ComputePositionData(void* aStartStruct,
8485 : const nsRuleData* aRuleData,
8486 : GeckoStyleContext* aContext,
8487 : nsRuleNode* aHighestNode,
8488 : const RuleDetail aRuleDetail,
8489 : const RuleNodeCacheConditions aConditions)
8490 : {
8491 562 : COMPUTE_START_RESET(Position, pos, parentPos)
8492 :
8493 : // box offsets: length, percent, calc, auto, inherit
8494 : static const nsCSSPropertyID offsetProps[] = {
8495 : eCSSProperty_top,
8496 : eCSSProperty_right,
8497 : eCSSProperty_bottom,
8498 : eCSSProperty_left
8499 : };
8500 562 : nsStyleCoord coord;
8501 1405 : NS_FOR_CSS_SIDES(side) {
8502 2248 : nsStyleCoord parentCoord = parentPos->mOffset.Get(side);
8503 1124 : if (SetCoord(*aRuleData->ValueFor(offsetProps[side]),
8504 : coord, parentCoord,
8505 : SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
8506 : SETCOORD_UNSET_INITIAL,
8507 1124 : aContext, mPresContext, conditions)) {
8508 2 : pos->mOffset.Set(side, coord);
8509 : }
8510 : }
8511 :
8512 : // We allow the enumerated box size property values -moz-min-content, etc. to
8513 : // be specified on both the {,min-,max-}width properties and the
8514 : // {,min-,max-}height properties, regardless of the writing mode. This is
8515 : // because the writing mode is not determined until here, at computed value
8516 : // time. Since we do not support layout behavior of these keywords on the
8517 : // block-axis properties, we turn them into unset if we find them in
8518 : // that case.
8519 :
8520 281 : WritingMode wm(aContext);
8521 281 : bool vertical = wm.IsVertical();
8522 :
8523 281 : const nsCSSValue* width = aRuleData->ValueForWidth();
8524 281 : if (width->GetUnit() == eCSSUnit_Enumerated) {
8525 0 : conditions.SetWritingModeDependency(wm.GetBits());
8526 : }
8527 562 : SetCoord(width->GetUnit() == eCSSUnit_Enumerated && vertical ?
8528 : nsCSSValue(eCSSUnit_Unset) : *width,
8529 : pos->mWidth, parentPos->mWidth,
8530 : SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
8531 : SETCOORD_UNSET_INITIAL,
8532 562 : aContext, mPresContext, conditions);
8533 :
8534 281 : const nsCSSValue* minWidth = aRuleData->ValueForMinWidth();
8535 281 : if (minWidth->GetUnit() == eCSSUnit_Enumerated) {
8536 0 : conditions.SetWritingModeDependency(wm.GetBits());
8537 : }
8538 562 : SetCoord(minWidth->GetUnit() == eCSSUnit_Enumerated && vertical ?
8539 : nsCSSValue(eCSSUnit_Unset) : *minWidth,
8540 : pos->mMinWidth, parentPos->mMinWidth,
8541 : SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
8542 : SETCOORD_UNSET_INITIAL,
8543 562 : aContext, mPresContext, conditions);
8544 :
8545 281 : const nsCSSValue* maxWidth = aRuleData->ValueForMaxWidth();
8546 281 : if (maxWidth->GetUnit() == eCSSUnit_Enumerated) {
8547 0 : conditions.SetWritingModeDependency(wm.GetBits());
8548 : }
8549 562 : SetCoord(maxWidth->GetUnit() == eCSSUnit_Enumerated && vertical ?
8550 : nsCSSValue(eCSSUnit_Unset) : *maxWidth,
8551 : pos->mMaxWidth, parentPos->mMaxWidth,
8552 : SETCOORD_LPOEH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
8553 : SETCOORD_UNSET_INITIAL,
8554 562 : aContext, mPresContext, conditions);
8555 :
8556 281 : const nsCSSValue* height = aRuleData->ValueForHeight();
8557 281 : if (height->GetUnit() == eCSSUnit_Enumerated) {
8558 0 : conditions.SetWritingModeDependency(wm.GetBits());
8559 : }
8560 562 : SetCoord(height->GetUnit() == eCSSUnit_Enumerated && !vertical ?
8561 : nsCSSValue(eCSSUnit_Unset) : *height,
8562 : pos->mHeight, parentPos->mHeight,
8563 : SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
8564 : SETCOORD_UNSET_INITIAL,
8565 562 : aContext, mPresContext, conditions);
8566 :
8567 281 : const nsCSSValue* minHeight = aRuleData->ValueForMinHeight();
8568 281 : if (minHeight->GetUnit() == eCSSUnit_Enumerated) {
8569 0 : conditions.SetWritingModeDependency(wm.GetBits());
8570 : }
8571 562 : SetCoord(minHeight->GetUnit() == eCSSUnit_Enumerated && !vertical ?
8572 : nsCSSValue(eCSSUnit_Unset) : *minHeight,
8573 : pos->mMinHeight, parentPos->mMinHeight,
8574 : SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
8575 : SETCOORD_UNSET_INITIAL,
8576 562 : aContext, mPresContext, conditions);
8577 :
8578 281 : const nsCSSValue* maxHeight = aRuleData->ValueForMaxHeight();
8579 281 : if (maxHeight->GetUnit() == eCSSUnit_Enumerated) {
8580 0 : conditions.SetWritingModeDependency(wm.GetBits());
8581 : }
8582 562 : SetCoord(maxHeight->GetUnit() == eCSSUnit_Enumerated && !vertical ?
8583 : nsCSSValue(eCSSUnit_Unset) : *maxHeight,
8584 : pos->mMaxHeight, parentPos->mMaxHeight,
8585 : SETCOORD_LPOEH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC |
8586 : SETCOORD_UNSET_INITIAL,
8587 562 : aContext, mPresContext, conditions);
8588 :
8589 : // box-sizing: enum, inherit, initial
8590 281 : SetValue(*aRuleData->ValueForBoxSizing(),
8591 : pos->mBoxSizing, conditions,
8592 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
8593 281 : parentPos->mBoxSizing,
8594 281 : StyleBoxSizing::Content);
8595 :
8596 : // align-content: enum, inherit, initial
8597 281 : SetValue(*aRuleData->ValueForAlignContent(),
8598 : pos->mAlignContent, conditions,
8599 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
8600 281 : parentPos->mAlignContent,
8601 281 : NS_STYLE_ALIGN_NORMAL);
8602 :
8603 : // align-items: enum, inherit, initial
8604 281 : SetValue(*aRuleData->ValueForAlignItems(),
8605 : pos->mAlignItems, conditions,
8606 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
8607 281 : parentPos->mAlignItems,
8608 281 : NS_STYLE_ALIGN_NORMAL);
8609 :
8610 : // align-self: enum, inherit, initial
8611 281 : SetValue(*aRuleData->ValueForAlignSelf(),
8612 : pos->mAlignSelf, conditions,
8613 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
8614 281 : parentPos->mAlignSelf,
8615 281 : NS_STYLE_ALIGN_AUTO);
8616 :
8617 : // justify-content: enum, inherit, initial
8618 281 : SetValue(*aRuleData->ValueForJustifyContent(),
8619 : pos->mJustifyContent, conditions,
8620 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
8621 281 : parentPos->mJustifyContent,
8622 281 : NS_STYLE_JUSTIFY_NORMAL);
8623 :
8624 : // justify-items: enum, inherit, initial
8625 281 : const auto& justifyItemsValue = *aRuleData->ValueForJustifyItems();
8626 281 : if (MOZ_UNLIKELY(justifyItemsValue.GetUnit() == eCSSUnit_Inherit)) {
8627 49 : if (MOZ_LIKELY(parentContext)) {
8628 49 : pos->mJustifyItems =
8629 49 : parentPos->ComputedJustifyItems(parentContext->GetParentAllowServo());
8630 : } else {
8631 0 : pos->mJustifyItems = NS_STYLE_JUSTIFY_NORMAL;
8632 : }
8633 49 : conditions.SetUncacheable();
8634 : } else {
8635 232 : SetValue(justifyItemsValue,
8636 : pos->mJustifyItems, conditions,
8637 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
8638 232 : parentPos->mJustifyItems, // unused, we handle 'inherit' above
8639 232 : NS_STYLE_JUSTIFY_AUTO);
8640 : }
8641 :
8642 : // justify-self: enum, inherit, initial
8643 281 : SetValue(*aRuleData->ValueForJustifySelf(),
8644 : pos->mJustifySelf, conditions,
8645 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
8646 281 : parentPos->mJustifySelf,
8647 281 : NS_STYLE_JUSTIFY_AUTO);
8648 :
8649 : // flex-basis: auto, length, percent, enum, calc, inherit, initial
8650 : // (Note: The flags here should match those used for 'width' property above.)
8651 281 : SetCoord(*aRuleData->ValueForFlexBasis(), pos->mFlexBasis, parentPos->mFlexBasis,
8652 : SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC |
8653 : SETCOORD_UNSET_INITIAL,
8654 562 : aContext, mPresContext, conditions);
8655 :
8656 : // flex-direction: enum, inherit, initial
8657 281 : SetValue(*aRuleData->ValueForFlexDirection(),
8658 : pos->mFlexDirection, conditions,
8659 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
8660 281 : parentPos->mFlexDirection,
8661 281 : NS_STYLE_FLEX_DIRECTION_ROW);
8662 :
8663 : // flex-grow: float, inherit, initial
8664 281 : SetFactor(*aRuleData->ValueForFlexGrow(),
8665 : pos->mFlexGrow, conditions,
8666 281 : parentPos->mFlexGrow, 0.0f,
8667 281 : SETFCT_UNSET_INITIAL);
8668 :
8669 : // flex-shrink: float, inherit, initial
8670 281 : SetFactor(*aRuleData->ValueForFlexShrink(),
8671 : pos->mFlexShrink, conditions,
8672 281 : parentPos->mFlexShrink, 1.0f,
8673 281 : SETFCT_UNSET_INITIAL);
8674 :
8675 : // flex-wrap: enum, inherit, initial
8676 281 : SetValue(*aRuleData->ValueForFlexWrap(),
8677 : pos->mFlexWrap, conditions,
8678 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
8679 281 : parentPos->mFlexWrap,
8680 281 : NS_STYLE_FLEX_WRAP_NOWRAP);
8681 :
8682 : // order: integer, inherit, initial
8683 281 : SetValue(*aRuleData->ValueForOrder(),
8684 : pos->mOrder, conditions,
8685 : SETVAL_INTEGER | SETVAL_UNSET_INITIAL,
8686 281 : parentPos->mOrder,
8687 281 : NS_STYLE_ORDER_INITIAL);
8688 :
8689 : // object-fit: enum, inherit, initial
8690 281 : SetValue(*aRuleData->ValueForObjectFit(),
8691 : pos->mObjectFit, conditions,
8692 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
8693 281 : parentPos->mObjectFit,
8694 281 : NS_STYLE_OBJECT_FIT_FILL);
8695 :
8696 : // object-position
8697 281 : const nsCSSValue& objectPosition = *aRuleData->ValueForObjectPosition();
8698 281 : switch (objectPosition.GetUnit()) {
8699 : case eCSSUnit_Null:
8700 281 : break;
8701 : case eCSSUnit_Inherit:
8702 0 : conditions.SetUncacheable();
8703 0 : pos->mObjectPosition = parentPos->mObjectPosition;
8704 0 : break;
8705 : case eCSSUnit_Initial:
8706 : case eCSSUnit_Unset:
8707 0 : pos->mObjectPosition.SetInitialPercentValues(0.5f);
8708 0 : break;
8709 : default:
8710 0 : ComputePositionValue(aContext, objectPosition,
8711 0 : pos->mObjectPosition, conditions);
8712 : }
8713 :
8714 : // grid-auto-flow
8715 281 : const nsCSSValue& gridAutoFlow = *aRuleData->ValueForGridAutoFlow();
8716 281 : switch (gridAutoFlow.GetUnit()) {
8717 : case eCSSUnit_Null:
8718 232 : break;
8719 : case eCSSUnit_Inherit:
8720 49 : conditions.SetUncacheable();
8721 49 : pos->mGridAutoFlow = parentPos->mGridAutoFlow;
8722 49 : break;
8723 : case eCSSUnit_Initial:
8724 : case eCSSUnit_Unset:
8725 0 : pos->mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_ROW;
8726 0 : break;
8727 : default:
8728 0 : NS_ASSERTION(gridAutoFlow.GetUnit() == eCSSUnit_Enumerated,
8729 : "Unexpected unit");
8730 0 : pos->mGridAutoFlow = gridAutoFlow.GetIntValue();
8731 : }
8732 :
8733 : // grid-auto-columns
8734 281 : SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoColumns(),
8735 : pos->mGridAutoColumnsMin,
8736 : pos->mGridAutoColumnsMax,
8737 : parentPos->mGridAutoColumnsMin,
8738 : parentPos->mGridAutoColumnsMax,
8739 562 : aContext, mPresContext, conditions);
8740 :
8741 : // grid-auto-rows
8742 281 : SetGridAutoColumnsRows(*aRuleData->ValueForGridAutoRows(),
8743 : pos->mGridAutoRowsMin,
8744 : pos->mGridAutoRowsMax,
8745 : parentPos->mGridAutoRowsMin,
8746 : parentPos->mGridAutoRowsMax,
8747 562 : aContext, mPresContext, conditions);
8748 :
8749 : // grid-template-columns
8750 281 : SetGridTrackList(*aRuleData->ValueForGridTemplateColumns(),
8751 : pos->mGridTemplateColumns, parentPos->mGridTemplateColumns,
8752 562 : aContext, mPresContext, conditions);
8753 :
8754 : // grid-template-rows
8755 281 : SetGridTrackList(*aRuleData->ValueForGridTemplateRows(),
8756 : pos->mGridTemplateRows, parentPos->mGridTemplateRows,
8757 562 : aContext, mPresContext, conditions);
8758 :
8759 : // grid-tempate-areas
8760 281 : SetGridTemplateAreas(*aRuleData->ValueForGridTemplateAreas(),
8761 : &pos->mGridTemplateAreas,
8762 : parentPos->mGridTemplateAreas,
8763 281 : conditions);
8764 :
8765 : // grid-column-start
8766 281 : SetGridLine(*aRuleData->ValueForGridColumnStart(),
8767 : pos->mGridColumnStart,
8768 : parentPos->mGridColumnStart,
8769 281 : conditions);
8770 :
8771 : // grid-column-end
8772 281 : SetGridLine(*aRuleData->ValueForGridColumnEnd(),
8773 : pos->mGridColumnEnd,
8774 : parentPos->mGridColumnEnd,
8775 281 : conditions);
8776 :
8777 : // grid-row-start
8778 281 : SetGridLine(*aRuleData->ValueForGridRowStart(),
8779 : pos->mGridRowStart,
8780 : parentPos->mGridRowStart,
8781 281 : conditions);
8782 :
8783 : // grid-row-end
8784 281 : SetGridLine(*aRuleData->ValueForGridRowEnd(),
8785 : pos->mGridRowEnd,
8786 : parentPos->mGridRowEnd,
8787 281 : conditions);
8788 :
8789 : // grid-column-gap
8790 281 : if (SetCoord(*aRuleData->ValueForGridColumnGap(),
8791 : pos->mGridColumnGap, parentPos->mGridColumnGap,
8792 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
8793 : SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INITIAL,
8794 281 : aContext, mPresContext, conditions)) {
8795 : } else {
8796 232 : MOZ_ASSERT(aRuleData->ValueForGridColumnGap()->GetUnit() == eCSSUnit_Null,
8797 : "unexpected unit");
8798 : }
8799 :
8800 : // grid-row-gap
8801 281 : if (SetCoord(*aRuleData->ValueForGridRowGap(),
8802 : pos->mGridRowGap, parentPos->mGridRowGap,
8803 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC |
8804 : SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INITIAL,
8805 281 : aContext, mPresContext, conditions)) {
8806 : } else {
8807 232 : MOZ_ASSERT(aRuleData->ValueForGridRowGap()->GetUnit() == eCSSUnit_Null,
8808 : "unexpected unit");
8809 : }
8810 :
8811 : // z-index
8812 281 : const nsCSSValue* zIndexValue = aRuleData->ValueForZIndex();
8813 281 : if (! SetCoord(*zIndexValue, pos->mZIndex, parentPos->mZIndex,
8814 : SETCOORD_IA | SETCOORD_INITIAL_AUTO | SETCOORD_UNSET_INITIAL,
8815 : aContext, nullptr, conditions)) {
8816 261 : if (eCSSUnit_Inherit == zIndexValue->GetUnit()) {
8817 : // handle inherit, because it's ok to inherit 'auto' here
8818 0 : conditions.SetUncacheable();
8819 0 : pos->mZIndex = parentPos->mZIndex;
8820 : }
8821 : }
8822 :
8823 562 : COMPUTE_END_RESET(Position, pos)
8824 : }
8825 :
8826 : const void*
8827 0 : nsRuleNode::ComputeTableData(void* aStartStruct,
8828 : const nsRuleData* aRuleData,
8829 : GeckoStyleContext* aContext,
8830 : nsRuleNode* aHighestNode,
8831 : const RuleDetail aRuleDetail,
8832 : const RuleNodeCacheConditions aConditions)
8833 : {
8834 0 : COMPUTE_START_RESET(Table, table, parentTable)
8835 :
8836 : // table-layout: enum, inherit, initial
8837 0 : SetValue(*aRuleData->ValueForTableLayout(),
8838 : table->mLayoutStrategy, conditions,
8839 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
8840 0 : parentTable->mLayoutStrategy,
8841 0 : NS_STYLE_TABLE_LAYOUT_AUTO);
8842 :
8843 : // span: pixels (not a real CSS prop)
8844 0 : const nsCSSValue* spanValue = aRuleData->ValueForSpan();
8845 0 : if (eCSSUnit_Enumerated == spanValue->GetUnit() ||
8846 0 : eCSSUnit_Integer == spanValue->GetUnit())
8847 0 : table->mSpan = spanValue->GetIntValue();
8848 :
8849 0 : COMPUTE_END_RESET(Table, table)
8850 : }
8851 :
8852 : const void*
8853 0 : nsRuleNode::ComputeTableBorderData(void* aStartStruct,
8854 : const nsRuleData* aRuleData,
8855 : GeckoStyleContext* aContext,
8856 : nsRuleNode* aHighestNode,
8857 : const RuleDetail aRuleDetail,
8858 : const RuleNodeCacheConditions aConditions)
8859 : {
8860 0 : COMPUTE_START_INHERITED(TableBorder, table, parentTable)
8861 :
8862 : // border-collapse: enum, inherit, initial
8863 0 : SetValue(*aRuleData->ValueForBorderCollapse(), table->mBorderCollapse,
8864 : conditions,
8865 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
8866 0 : parentTable->mBorderCollapse,
8867 0 : NS_STYLE_BORDER_SEPARATE);
8868 :
8869 0 : const nsCSSValue* borderSpacingValue = aRuleData->ValueForBorderSpacing();
8870 : // border-spacing: pair(length), inherit
8871 0 : if (borderSpacingValue->GetUnit() != eCSSUnit_Null) {
8872 0 : nsStyleCoord parentCol(parentTable->mBorderSpacingCol,
8873 0 : nsStyleCoord::CoordConstructor);
8874 0 : nsStyleCoord parentRow(parentTable->mBorderSpacingRow,
8875 0 : nsStyleCoord::CoordConstructor);
8876 0 : nsStyleCoord coordCol, coordRow;
8877 :
8878 : #ifdef DEBUG
8879 : bool result =
8880 : #endif
8881 : SetPairCoords(*borderSpacingValue,
8882 : coordCol, coordRow, parentCol, parentRow,
8883 : SETCOORD_LH | SETCOORD_INITIAL_ZERO |
8884 : SETCOORD_CALC_LENGTH_ONLY |
8885 : SETCOORD_CALC_CLAMP_NONNEGATIVE | SETCOORD_UNSET_INHERIT,
8886 0 : aContext, mPresContext, conditions);
8887 0 : NS_ASSERTION(result, "malformed table border value");
8888 0 : table->mBorderSpacingCol = coordCol.GetCoordValue();
8889 0 : table->mBorderSpacingRow = coordRow.GetCoordValue();
8890 : }
8891 :
8892 : // caption-side: enum, inherit, initial
8893 0 : SetValue(*aRuleData->ValueForCaptionSide(),
8894 : table->mCaptionSide, conditions,
8895 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
8896 0 : parentTable->mCaptionSide,
8897 0 : NS_STYLE_CAPTION_SIDE_TOP);
8898 :
8899 : // empty-cells: enum, inherit, initial
8900 0 : SetValue(*aRuleData->ValueForEmptyCells(),
8901 : table->mEmptyCells, conditions,
8902 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
8903 0 : parentTable->mEmptyCells,
8904 0 : NS_STYLE_TABLE_EMPTY_CELLS_SHOW);
8905 :
8906 0 : COMPUTE_END_INHERITED(TableBorder, table)
8907 : }
8908 :
8909 : const void*
8910 34 : nsRuleNode::ComputeContentData(void* aStartStruct,
8911 : const nsRuleData* aRuleData,
8912 : GeckoStyleContext* aContext,
8913 : nsRuleNode* aHighestNode,
8914 : const RuleDetail aRuleDetail,
8915 : const RuleNodeCacheConditions aConditions)
8916 : {
8917 : uint32_t count;
8918 68 : nsAutoString buffer;
8919 :
8920 68 : COMPUTE_START_RESET(Content, content, parentContent)
8921 :
8922 : // content: [string, url, counter, attr, enum]+, normal, none, inherit
8923 34 : const nsCSSValue* contentValue = aRuleData->ValueForContent();
8924 34 : switch (contentValue->GetUnit()) {
8925 : case eCSSUnit_Null:
8926 26 : break;
8927 :
8928 : case eCSSUnit_Normal:
8929 : case eCSSUnit_None:
8930 : case eCSSUnit_Initial:
8931 : case eCSSUnit_Unset:
8932 : // "normal", "none", "initial" and "unset" all mean no content
8933 0 : content->AllocateContents(0);
8934 0 : break;
8935 :
8936 : case eCSSUnit_Inherit:
8937 0 : conditions.SetUncacheable();
8938 0 : count = parentContent->ContentCount();
8939 0 : content->AllocateContents(count);
8940 0 : while (0 < count--) {
8941 0 : content->ContentAt(count) = parentContent->ContentAt(count);
8942 : }
8943 0 : break;
8944 :
8945 : case eCSSUnit_Enumerated: {
8946 0 : MOZ_ASSERT(contentValue->GetIntValue() == NS_STYLE_CONTENT_ALT_CONTENT,
8947 : "unrecognized solitary content keyword");
8948 0 : content->AllocateContents(1);
8949 0 : content->ContentAt(0).SetKeyword(eStyleContentType_AltContent);
8950 0 : break;
8951 : }
8952 :
8953 : case eCSSUnit_List:
8954 : case eCSSUnit_ListDep: {
8955 8 : const nsCSSValueList* contentValueList = contentValue->GetListValue();
8956 8 : count = 0;
8957 24 : while (contentValueList) {
8958 8 : count++;
8959 8 : contentValueList = contentValueList->mNext;
8960 : }
8961 8 : content->AllocateContents(count);
8962 16 : const nsAutoString nullStr;
8963 8 : count = 0;
8964 8 : contentValueList = contentValue->GetListValue();
8965 24 : while (contentValueList) {
8966 8 : const nsCSSValue& value = contentValueList->mValue;
8967 8 : nsCSSUnit unit = value.GetUnit();
8968 8 : nsStyleContentData& data = content->ContentAt(count++);
8969 8 : switch (unit) {
8970 : case eCSSUnit_Image:
8971 0 : data.SetImageRequest(CreateStyleImageRequest(mPresContext, value));
8972 0 : break;
8973 : case eCSSUnit_String:
8974 : case eCSSUnit_Attr: {
8975 : nsStyleContentType type =
8976 8 : unit == eCSSUnit_String ? eStyleContentType_String
8977 8 : : eStyleContentType_Attr;
8978 8 : value.GetStringValue(buffer);
8979 8 : data.SetString(type, buffer.get());
8980 8 : break;
8981 : }
8982 : case eCSSUnit_Counter:
8983 : case eCSSUnit_Counters: {
8984 : nsStyleContentType type =
8985 0 : unit == eCSSUnit_Counter ? eStyleContentType_Counter
8986 0 : : eStyleContentType_Counters;
8987 : RefPtr<nsStyleContentData::CounterFunction>
8988 0 : counterFunc = new nsStyleContentData::CounterFunction();
8989 0 : nsCSSValue::Array* arrayValue = value.GetArrayValue();
8990 0 : arrayValue->Item(0).GetStringValue(counterFunc->mIdent);
8991 0 : if (unit == eCSSUnit_Counters) {
8992 0 : arrayValue->Item(1).GetStringValue(counterFunc->mSeparator);
8993 : }
8994 : const nsCSSValue& style =
8995 0 : value.GetArrayValue()->Item(unit == eCSSUnit_Counters ? 2 : 1);
8996 0 : if (style.GetUnit() == eCSSUnit_AtomIdent) {
8997 0 : counterFunc->mCounterStyle = mPresContext->
8998 0 : CounterStyleManager()->BuildCounterStyle(style.GetAtomValue());
8999 0 : } else if (style.GetUnit() == eCSSUnit_Symbols) {
9000 0 : counterFunc->mCounterStyle =
9001 0 : new AnonymousCounterStyle(style.GetArrayValue());
9002 : } else {
9003 0 : MOZ_ASSERT_UNREACHABLE("Unknown counter style");
9004 : counterFunc->mCounterStyle = CounterStyleManager::GetDecimalStyle();
9005 : }
9006 0 : data.SetCounters(type, counterFunc.forget());
9007 0 : break;
9008 : }
9009 : case eCSSUnit_Enumerated:
9010 0 : switch (value.GetIntValue()) {
9011 : case NS_STYLE_CONTENT_OPEN_QUOTE:
9012 0 : data.SetKeyword(eStyleContentType_OpenQuote);
9013 0 : break;
9014 : case NS_STYLE_CONTENT_CLOSE_QUOTE:
9015 0 : data.SetKeyword(eStyleContentType_CloseQuote);
9016 0 : break;
9017 : case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
9018 0 : data.SetKeyword(eStyleContentType_NoOpenQuote);
9019 0 : break;
9020 : case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
9021 0 : data.SetKeyword(eStyleContentType_NoCloseQuote);
9022 0 : break;
9023 : default:
9024 0 : NS_ERROR("bad content value");
9025 0 : break;
9026 : }
9027 0 : break;
9028 : default:
9029 0 : NS_ERROR("bad content type");
9030 0 : break;
9031 : }
9032 8 : contentValueList = contentValueList->mNext;
9033 : }
9034 8 : break;
9035 : }
9036 :
9037 : default:
9038 0 : MOZ_ASSERT(false, "unrecognized content unit");
9039 : }
9040 :
9041 : // counter-increment: [string [int]]+, none, inherit
9042 : const nsCSSValue* counterIncrementValue =
9043 34 : aRuleData->ValueForCounterIncrement();
9044 34 : switch (counterIncrementValue->GetUnit()) {
9045 : case eCSSUnit_Null:
9046 34 : break;
9047 :
9048 : case eCSSUnit_None:
9049 : case eCSSUnit_Initial:
9050 : case eCSSUnit_Unset:
9051 0 : content->AllocateCounterIncrements(0);
9052 0 : break;
9053 :
9054 : case eCSSUnit_Inherit:
9055 0 : conditions.SetUncacheable();
9056 0 : count = parentContent->CounterIncrementCount();
9057 0 : content->AllocateCounterIncrements(count);
9058 0 : while (count--) {
9059 0 : const nsStyleCounterData& data = parentContent->CounterIncrementAt(count);
9060 0 : content->SetCounterIncrementAt(count, data.mCounter, data.mValue);
9061 : }
9062 0 : break;
9063 :
9064 : case eCSSUnit_PairList:
9065 : case eCSSUnit_PairListDep: {
9066 : const nsCSSValuePairList* ourIncrement =
9067 0 : counterIncrementValue->GetPairListValue();
9068 0 : MOZ_ASSERT(ourIncrement->mXValue.GetUnit() == eCSSUnit_Ident,
9069 : "unexpected value unit");
9070 0 : count = ListLength(ourIncrement);
9071 0 : content->AllocateCounterIncrements(count);
9072 :
9073 0 : count = 0;
9074 0 : for (const nsCSSValuePairList* p = ourIncrement; p; p = p->mNext, count++) {
9075 0 : MOZ_ASSERT(p->mYValue.GetUnit() == eCSSUnit_Integer);
9076 0 : p->mXValue.GetStringValue(buffer);
9077 0 : content->SetCounterIncrementAt(count, buffer, p->mYValue.GetIntValue());
9078 : }
9079 0 : break;
9080 : }
9081 :
9082 : default:
9083 0 : MOZ_ASSERT(false, "unexpected value unit");
9084 : }
9085 :
9086 : // counter-reset: [string [int]]+, none, inherit
9087 34 : const nsCSSValue* counterResetValue = aRuleData->ValueForCounterReset();
9088 34 : switch (counterResetValue->GetUnit()) {
9089 : case eCSSUnit_Null:
9090 34 : break;
9091 :
9092 : case eCSSUnit_None:
9093 : case eCSSUnit_Initial:
9094 : case eCSSUnit_Unset:
9095 0 : content->AllocateCounterResets(0);
9096 0 : break;
9097 :
9098 : case eCSSUnit_Inherit:
9099 0 : conditions.SetUncacheable();
9100 0 : count = parentContent->CounterResetCount();
9101 0 : content->AllocateCounterResets(count);
9102 0 : while (0 < count--) {
9103 0 : const nsStyleCounterData& data = parentContent->CounterResetAt(count);
9104 0 : content->SetCounterResetAt(count, data.mCounter, data.mValue);
9105 : }
9106 0 : break;
9107 :
9108 : case eCSSUnit_PairList:
9109 : case eCSSUnit_PairListDep: {
9110 : const nsCSSValuePairList* ourReset =
9111 0 : counterResetValue->GetPairListValue();
9112 0 : MOZ_ASSERT(ourReset->mXValue.GetUnit() == eCSSUnit_Ident,
9113 : "unexpected value unit");
9114 0 : count = ListLength(ourReset);
9115 0 : content->AllocateCounterResets(count);
9116 0 : count = 0;
9117 0 : for (const nsCSSValuePairList* p = ourReset; p; p = p->mNext, count++) {
9118 0 : MOZ_ASSERT(p->mYValue.GetUnit() == eCSSUnit_Integer);
9119 0 : p->mXValue.GetStringValue(buffer);
9120 0 : content->SetCounterResetAt(count, buffer, p->mYValue.GetIntValue());
9121 : }
9122 0 : break;
9123 : }
9124 :
9125 : default:
9126 0 : MOZ_ASSERT(false, "unexpected value unit");
9127 : }
9128 :
9129 68 : COMPUTE_END_RESET(Content, content)
9130 : }
9131 :
9132 : const void*
9133 158 : nsRuleNode::ComputeXULData(void* aStartStruct,
9134 : const nsRuleData* aRuleData,
9135 : GeckoStyleContext* aContext,
9136 : nsRuleNode* aHighestNode,
9137 : const RuleDetail aRuleDetail,
9138 : const RuleNodeCacheConditions aConditions)
9139 : {
9140 316 : COMPUTE_START_RESET(XUL, xul, parentXUL)
9141 :
9142 : // box-align: enum, inherit, initial
9143 158 : SetValue(*aRuleData->ValueForBoxAlign(),
9144 : xul->mBoxAlign, conditions,
9145 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
9146 158 : parentXUL->mBoxAlign,
9147 158 : StyleBoxAlign::Stretch);
9148 :
9149 : // box-direction: enum, inherit, initial
9150 158 : SetValue(*aRuleData->ValueForBoxDirection(),
9151 : xul->mBoxDirection, conditions,
9152 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
9153 158 : parentXUL->mBoxDirection,
9154 158 : StyleBoxDirection::Normal);
9155 :
9156 : // box-flex: factor, inherit
9157 158 : SetFactor(*aRuleData->ValueForBoxFlex(),
9158 : xul->mBoxFlex, conditions,
9159 158 : parentXUL->mBoxFlex, 0.0f,
9160 158 : SETFCT_UNSET_INITIAL);
9161 :
9162 : // box-orient: enum, inherit, initial
9163 158 : SetValue(*aRuleData->ValueForBoxOrient(),
9164 : xul->mBoxOrient, conditions,
9165 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
9166 158 : parentXUL->mBoxOrient,
9167 158 : StyleBoxOrient::Horizontal);
9168 :
9169 : // box-pack: enum, inherit, initial
9170 158 : SetValue(*aRuleData->ValueForBoxPack(),
9171 : xul->mBoxPack, conditions,
9172 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
9173 158 : parentXUL->mBoxPack,
9174 158 : StyleBoxPack::Start);
9175 :
9176 : // box-ordinal-group: integer, inherit, initial
9177 158 : SetValue(*aRuleData->ValueForBoxOrdinalGroup(),
9178 : xul->mBoxOrdinal, conditions,
9179 : SETVAL_INTEGER | SETVAL_UNSET_INITIAL,
9180 316 : parentXUL->mBoxOrdinal, 1);
9181 :
9182 158 : SetValue(*aRuleData->ValueForStackSizing(),
9183 : xul->mStackSizing, conditions,
9184 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
9185 158 : parentXUL->mStackSizing,
9186 158 : StyleStackSizing::StretchToFit);
9187 :
9188 316 : COMPUTE_END_RESET(XUL, xul)
9189 : }
9190 :
9191 : const void*
9192 32 : nsRuleNode::ComputeColumnData(void* aStartStruct,
9193 : const nsRuleData* aRuleData,
9194 : GeckoStyleContext* aContext,
9195 : nsRuleNode* aHighestNode,
9196 : const RuleDetail aRuleDetail,
9197 : const RuleNodeCacheConditions aConditions)
9198 : {
9199 64 : COMPUTE_START_RESET(Column, column, parent)
9200 :
9201 : // column-width: length, auto, inherit
9202 32 : SetCoord(*aRuleData->ValueForColumnWidth(),
9203 : column->mColumnWidth, parent->mColumnWidth,
9204 : SETCOORD_LAH | SETCOORD_INITIAL_AUTO |
9205 : SETCOORD_CALC_LENGTH_ONLY | SETCOORD_CALC_CLAMP_NONNEGATIVE |
9206 : SETCOORD_UNSET_INITIAL,
9207 64 : aContext, mPresContext, conditions);
9208 :
9209 : // column-gap: length, inherit, normal
9210 32 : SetCoord(*aRuleData->ValueForColumnGap(),
9211 : column->mColumnGap, parent->mColumnGap,
9212 : SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
9213 : SETCOORD_CALC_LENGTH_ONLY | SETCOORD_UNSET_INITIAL,
9214 64 : aContext, mPresContext, conditions);
9215 : // clamp negative calc() to 0
9216 32 : if (column->mColumnGap.GetUnit() == eStyleUnit_Coord) {
9217 0 : column->mColumnGap.SetCoordValue(
9218 0 : std::max(column->mColumnGap.GetCoordValue(), 0));
9219 : }
9220 :
9221 : // column-count: auto, integer, inherit
9222 32 : const nsCSSValue* columnCountValue = aRuleData->ValueForColumnCount();
9223 96 : if (eCSSUnit_Auto == columnCountValue->GetUnit() ||
9224 64 : eCSSUnit_Initial == columnCountValue->GetUnit() ||
9225 32 : eCSSUnit_Unset == columnCountValue->GetUnit()) {
9226 0 : column->mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
9227 32 : } else if (eCSSUnit_Integer == columnCountValue->GetUnit()) {
9228 0 : column->mColumnCount = columnCountValue->GetIntValue();
9229 : // Max kMaxColumnCount columns - wallpaper for bug 345583.
9230 0 : column->mColumnCount = std::min(column->mColumnCount,
9231 0 : nsStyleColumn::kMaxColumnCount);
9232 32 : } else if (eCSSUnit_Inherit == columnCountValue->GetUnit()) {
9233 25 : conditions.SetUncacheable();
9234 25 : column->mColumnCount = parent->mColumnCount;
9235 : }
9236 :
9237 : // column-rule-width: length, enum, inherit
9238 : Maybe<nscoord> coord =
9239 : ComputeLineWidthValue<eUnsetInitial>(
9240 32 : *aRuleData->ValueForColumnRuleWidth(),
9241 : parent->GetComputedColumnRuleWidth(),
9242 : nsPresContext::GetBorderWidthForKeyword(NS_STYLE_BORDER_WIDTH_MEDIUM),
9243 96 : aContext, mPresContext, conditions);
9244 32 : if (coord.isSome()) {
9245 25 : column->SetColumnRuleWidth(*coord);
9246 : }
9247 :
9248 : // column-rule-style: enum, inherit
9249 32 : const nsCSSValue& styleValue = *aRuleData->ValueForColumnRuleStyle();
9250 32 : MOZ_ASSERT(eCSSUnit_None != styleValue.GetUnit(),
9251 : "'none' should be handled as enumerated value");
9252 32 : if (eCSSUnit_Enumerated == styleValue.GetUnit()) {
9253 0 : column->mColumnRuleStyle = styleValue.GetIntValue();
9254 : }
9255 64 : else if (eCSSUnit_Initial == styleValue.GetUnit() ||
9256 32 : eCSSUnit_Unset == styleValue.GetUnit()) {
9257 0 : column->mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
9258 : }
9259 32 : else if (eCSSUnit_Inherit == styleValue.GetUnit()) {
9260 25 : conditions.SetUncacheable();
9261 25 : column->mColumnRuleStyle = parent->mColumnRuleStyle;
9262 : }
9263 :
9264 : // column-rule-color: color, inherit
9265 64 : SetComplexColor<eUnsetInitial>(*aRuleData->ValueForColumnRuleColor(),
9266 : parent->mColumnRuleColor,
9267 64 : StyleComplexColor::CurrentColor(),
9268 32 : mPresContext,
9269 32 : column->mColumnRuleColor, conditions);
9270 :
9271 : // column-fill: enum
9272 32 : SetValue(*aRuleData->ValueForColumnFill(),
9273 : column->mColumnFill, conditions,
9274 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
9275 32 : parent->mColumnFill,
9276 32 : NS_STYLE_COLUMN_FILL_BALANCE);
9277 :
9278 : // column-span: enum
9279 32 : SetValue(*aRuleData->ValueForColumnSpan(),
9280 : column->mColumnSpan, conditions,
9281 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
9282 32 : parent->mColumnSpan,
9283 32 : NS_STYLE_COLUMN_SPAN_NONE);
9284 :
9285 64 : COMPUTE_END_RESET(Column, column)
9286 : }
9287 :
9288 : static void
9289 132 : SetSVGPaint(const nsCSSValue& aValue, const nsStyleSVGPaint& parentPaint,
9290 : nsPresContext* aPresContext, GeckoStyleContext *aContext,
9291 : nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
9292 : RuleNodeCacheConditions& aConditions)
9293 : {
9294 132 : MOZ_ASSERT(aInitialPaintType == eStyleSVGPaintType_None ||
9295 : aInitialPaintType == eStyleSVGPaintType_Color,
9296 : "SetSVGPaint only supports initial values being either 'black' "
9297 : "(represented by eStyleSVGPaintType_Color) or none (by "
9298 : "eStyleSVGPaintType_None)");
9299 :
9300 : nscolor color;
9301 :
9302 264 : if (aValue.GetUnit() == eCSSUnit_Inherit ||
9303 132 : aValue.GetUnit() == eCSSUnit_Unset) {
9304 0 : aResult = parentPaint;
9305 0 : aConditions.SetUncacheable();
9306 132 : } else if (aValue.GetUnit() == eCSSUnit_None) {
9307 1 : aResult.SetNone();
9308 131 : } else if (aValue.GetUnit() == eCSSUnit_Initial) {
9309 0 : if (aInitialPaintType == eStyleSVGPaintType_None) {
9310 0 : aResult.SetNone();
9311 : } else {
9312 0 : aResult.SetColor(NS_RGB(0, 0, 0));
9313 : }
9314 131 : } else if (aValue.GetUnit() == eCSSUnit_URL) {
9315 0 : aResult.SetPaintServer(aValue.GetURLStructValue());
9316 131 : } else if (aValue.GetUnit() == eCSSUnit_Enumerated) {
9317 22 : switch (aValue.GetIntValue()) {
9318 : case NS_COLOR_CONTEXT_FILL:
9319 22 : aResult.SetContextValue(eStyleSVGPaintType_ContextFill);
9320 22 : break;
9321 : case NS_COLOR_CONTEXT_STROKE:
9322 0 : aResult.SetContextValue(eStyleSVGPaintType_ContextStroke);
9323 0 : break;
9324 : default:
9325 0 : NS_NOTREACHED("unknown keyword as paint server value");
9326 : }
9327 109 : } else if (SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aContext,
9328 : color, aConditions)) {
9329 44 : aResult.SetColor(color);
9330 65 : } else if (aValue.GetUnit() == eCSSUnit_Pair) {
9331 0 : const nsCSSValuePair& pair = aValue.GetPairValue();
9332 :
9333 : nsStyleSVGFallbackType fallbackType;
9334 : nscolor fallback;
9335 0 : if (pair.mYValue.GetUnit() == eCSSUnit_None) {
9336 0 : fallbackType = eStyleSVGFallbackType_None;
9337 0 : fallback = NS_RGBA(0, 0, 0, 0);
9338 : } else {
9339 0 : MOZ_ASSERT(pair.mYValue.GetUnit() != eCSSUnit_Inherit,
9340 : "cannot inherit fallback colour");
9341 0 : fallbackType = eStyleSVGFallbackType_Color;
9342 0 : SetColor(pair.mYValue, NS_RGB(0, 0, 0), aPresContext, aContext,
9343 0 : fallback, aConditions);
9344 : }
9345 :
9346 0 : if (pair.mXValue.GetUnit() == eCSSUnit_URL) {
9347 0 : aResult.SetPaintServer(pair.mXValue.GetURLStructValue(),
9348 0 : fallbackType, fallback);
9349 0 : } else if (pair.mXValue.GetUnit() == eCSSUnit_Enumerated) {
9350 :
9351 0 : switch (pair.mXValue.GetIntValue()) {
9352 : case NS_COLOR_CONTEXT_FILL:
9353 0 : aResult.SetContextValue(eStyleSVGPaintType_ContextFill,
9354 0 : fallbackType, fallback);
9355 0 : break;
9356 : case NS_COLOR_CONTEXT_STROKE:
9357 0 : aResult.SetContextValue(eStyleSVGPaintType_ContextStroke,
9358 0 : fallbackType, fallback);
9359 0 : break;
9360 : default:
9361 0 : NS_NOTREACHED("unknown keyword as paint server value");
9362 : }
9363 :
9364 : } else {
9365 0 : NS_NOTREACHED("malformed paint server value");
9366 : }
9367 :
9368 : } else {
9369 65 : MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Null,
9370 : "malformed paint server value");
9371 : }
9372 132 : }
9373 :
9374 : static void
9375 132 : SetSVGOpacity(const nsCSSValue& aValue,
9376 : float& aOpacityField, nsStyleSVGOpacitySource& aOpacityTypeField,
9377 : RuleNodeCacheConditions& aConditions,
9378 : float aParentOpacity, nsStyleSVGOpacitySource aParentOpacityType)
9379 : {
9380 132 : if (eCSSUnit_Enumerated == aValue.GetUnit()) {
9381 3 : switch (aValue.GetIntValue()) {
9382 : case NS_STYLE_CONTEXT_FILL_OPACITY:
9383 3 : aOpacityTypeField = eStyleSVGOpacitySource_ContextFillOpacity;
9384 3 : break;
9385 : case NS_STYLE_CONTEXT_STROKE_OPACITY:
9386 0 : aOpacityTypeField = eStyleSVGOpacitySource_ContextStrokeOpacity;
9387 0 : break;
9388 : default:
9389 0 : NS_NOTREACHED("SetSVGOpacity: Unknown keyword");
9390 : }
9391 : // Fall back on fully opaque
9392 3 : aOpacityField = 1.0f;
9393 258 : } else if (eCSSUnit_Inherit == aValue.GetUnit() ||
9394 129 : eCSSUnit_Unset == aValue.GetUnit()) {
9395 0 : aConditions.SetUncacheable();
9396 0 : aOpacityField = aParentOpacity;
9397 0 : aOpacityTypeField = aParentOpacityType;
9398 129 : } else if (eCSSUnit_Null != aValue.GetUnit()) {
9399 : SetFactor(aValue, aOpacityField, aConditions,
9400 8 : aParentOpacity, 1.0f, SETFCT_OPACITY);
9401 8 : aOpacityTypeField = eStyleSVGOpacitySource_Normal;
9402 : }
9403 132 : }
9404 :
9405 : /* static */
9406 : void
9407 0 : nsRuleNode::FillAllMaskLists(nsStyleImageLayers& aMask,
9408 : uint32_t aMaxItemCount)
9409 : {
9410 :
9411 : // Delete any extra items. We need to keep layers in which any
9412 : // property was specified.
9413 0 : aMask.mLayers.TruncateLengthNonZero(aMaxItemCount);
9414 :
9415 0 : uint32_t fillCount = aMask.mImageCount;
9416 :
9417 0 : FillImageLayerList(aMask.mLayers,
9418 : &nsStyleImageLayers::Layer::mImage,
9419 0 : aMask.mImageCount, fillCount);
9420 0 : FillImageLayerList(aMask.mLayers,
9421 : &nsStyleImageLayers::Layer::mRepeat,
9422 0 : aMask.mRepeatCount, fillCount);
9423 0 : FillImageLayerList(aMask.mLayers,
9424 : &nsStyleImageLayers::Layer::mClip,
9425 0 : aMask.mClipCount, fillCount);
9426 0 : FillImageLayerList(aMask.mLayers,
9427 : &nsStyleImageLayers::Layer::mOrigin,
9428 0 : aMask.mOriginCount, fillCount);
9429 0 : FillImageLayerPositionCoordList(aMask.mLayers,
9430 : &Position::mXPosition,
9431 0 : aMask.mPositionXCount, fillCount);
9432 0 : FillImageLayerPositionCoordList(aMask.mLayers,
9433 : &Position::mYPosition,
9434 0 : aMask.mPositionYCount, fillCount);
9435 0 : FillImageLayerList(aMask.mLayers,
9436 : &nsStyleImageLayers::Layer::mSize,
9437 0 : aMask.mSizeCount, fillCount);
9438 0 : FillImageLayerList(aMask.mLayers,
9439 : &nsStyleImageLayers::Layer::mMaskMode,
9440 0 : aMask.mMaskModeCount, fillCount);
9441 0 : FillImageLayerList(aMask.mLayers,
9442 : &nsStyleImageLayers::Layer::mComposite,
9443 0 : aMask.mCompositeCount, fillCount);
9444 0 : }
9445 :
9446 : const void*
9447 66 : nsRuleNode::ComputeSVGData(void* aStartStruct,
9448 : const nsRuleData* aRuleData,
9449 : GeckoStyleContext* aContext,
9450 : nsRuleNode* aHighestNode,
9451 : const RuleDetail aRuleDetail,
9452 : const RuleNodeCacheConditions aConditions)
9453 : {
9454 132 : COMPUTE_START_INHERITED(SVG, svg, parentSVG)
9455 :
9456 : // clip-rule: enum, inherit, initial
9457 66 : SetValue(*aRuleData->ValueForClipRule(),
9458 : svg->mClipRule, conditions,
9459 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
9460 66 : parentSVG->mClipRule,
9461 66 : StyleFillRule::Nonzero);
9462 :
9463 : // color-interpolation: enum, inherit, initial
9464 66 : SetValue(*aRuleData->ValueForColorInterpolation(),
9465 : svg->mColorInterpolation, conditions,
9466 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
9467 66 : parentSVG->mColorInterpolation,
9468 66 : NS_STYLE_COLOR_INTERPOLATION_SRGB);
9469 :
9470 : // color-interpolation-filters: enum, inherit, initial
9471 66 : SetValue(*aRuleData->ValueForColorInterpolationFilters(),
9472 : svg->mColorInterpolationFilters, conditions,
9473 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
9474 66 : parentSVG->mColorInterpolationFilters,
9475 66 : NS_STYLE_COLOR_INTERPOLATION_LINEARRGB);
9476 :
9477 : // fill:
9478 132 : SetSVGPaint(*aRuleData->ValueForFill(),
9479 66 : parentSVG->mFill, mPresContext, aContext,
9480 66 : svg->mFill, eStyleSVGPaintType_Color, conditions);
9481 :
9482 : // fill-opacity: factor, inherit, initial,
9483 : // context-fill-opacity, context-stroke-opacity
9484 66 : nsStyleSVGOpacitySource contextFillOpacity = svg->FillOpacitySource();
9485 132 : SetSVGOpacity(*aRuleData->ValueForFillOpacity(),
9486 : svg->mFillOpacity, contextFillOpacity, conditions,
9487 198 : parentSVG->mFillOpacity, parentSVG->FillOpacitySource());
9488 66 : svg->SetFillOpacitySource(contextFillOpacity);
9489 :
9490 : // fill-rule: enum, inherit, initial
9491 66 : SetValue(*aRuleData->ValueForFillRule(),
9492 : svg->mFillRule, conditions,
9493 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
9494 66 : parentSVG->mFillRule,
9495 66 : StyleFillRule::Nonzero);
9496 :
9497 : // marker-end: url, none, inherit
9498 66 : const nsCSSValue* markerEndValue = aRuleData->ValueForMarkerEnd();
9499 66 : if (eCSSUnit_URL == markerEndValue->GetUnit()) {
9500 0 : svg->mMarkerEnd = markerEndValue->GetURLStructValue();
9501 132 : } else if (eCSSUnit_None == markerEndValue->GetUnit() ||
9502 66 : eCSSUnit_Initial == markerEndValue->GetUnit()) {
9503 0 : svg->mMarkerEnd = nullptr;
9504 132 : } else if (eCSSUnit_Inherit == markerEndValue->GetUnit() ||
9505 66 : eCSSUnit_Unset == markerEndValue->GetUnit()) {
9506 0 : conditions.SetUncacheable();
9507 0 : svg->mMarkerEnd = parentSVG->mMarkerEnd;
9508 : }
9509 :
9510 : // marker-mid: url, none, inherit
9511 66 : const nsCSSValue* markerMidValue = aRuleData->ValueForMarkerMid();
9512 66 : if (eCSSUnit_URL == markerMidValue->GetUnit()) {
9513 0 : svg->mMarkerMid = markerMidValue->GetURLStructValue();
9514 132 : } else if (eCSSUnit_None == markerMidValue->GetUnit() ||
9515 66 : eCSSUnit_Initial == markerMidValue->GetUnit()) {
9516 0 : svg->mMarkerMid = nullptr;
9517 132 : } else if (eCSSUnit_Inherit == markerMidValue->GetUnit() ||
9518 66 : eCSSUnit_Unset == markerMidValue->GetUnit()) {
9519 0 : conditions.SetUncacheable();
9520 0 : svg->mMarkerMid = parentSVG->mMarkerMid;
9521 : }
9522 :
9523 : // marker-start: url, none, inherit
9524 66 : const nsCSSValue* markerStartValue = aRuleData->ValueForMarkerStart();
9525 66 : if (eCSSUnit_URL == markerStartValue->GetUnit()) {
9526 0 : svg->mMarkerStart = markerStartValue->GetURLStructValue();
9527 132 : } else if (eCSSUnit_None == markerStartValue->GetUnit() ||
9528 66 : eCSSUnit_Initial == markerStartValue->GetUnit()) {
9529 0 : svg->mMarkerStart = nullptr;
9530 132 : } else if (eCSSUnit_Inherit == markerStartValue->GetUnit() ||
9531 66 : eCSSUnit_Unset == markerStartValue->GetUnit()) {
9532 0 : conditions.SetUncacheable();
9533 0 : svg->mMarkerStart = parentSVG->mMarkerStart;
9534 : }
9535 :
9536 : // paint-order: enum (bit field), inherit, initial
9537 66 : const nsCSSValue* paintOrderValue = aRuleData->ValueForPaintOrder();
9538 66 : switch (paintOrderValue->GetUnit()) {
9539 : case eCSSUnit_Null:
9540 66 : break;
9541 :
9542 : case eCSSUnit_Enumerated:
9543 : static_assert
9544 : (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <= 8,
9545 : "SVGStyleStruct::mPaintOrder not big enough");
9546 0 : svg->mPaintOrder = static_cast<uint8_t>(paintOrderValue->GetIntValue());
9547 0 : break;
9548 :
9549 : case eCSSUnit_Inherit:
9550 : case eCSSUnit_Unset:
9551 0 : conditions.SetUncacheable();
9552 0 : svg->mPaintOrder = parentSVG->mPaintOrder;
9553 0 : break;
9554 :
9555 : case eCSSUnit_Initial:
9556 0 : svg->mPaintOrder = NS_STYLE_PAINT_ORDER_NORMAL;
9557 0 : break;
9558 :
9559 : default:
9560 0 : NS_NOTREACHED("unexpected unit");
9561 : }
9562 :
9563 : // shape-rendering: enum, inherit
9564 66 : SetValue(*aRuleData->ValueForShapeRendering(),
9565 : svg->mShapeRendering, conditions,
9566 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
9567 66 : parentSVG->mShapeRendering,
9568 66 : NS_STYLE_SHAPE_RENDERING_AUTO);
9569 :
9570 : // stroke:
9571 132 : SetSVGPaint(*aRuleData->ValueForStroke(),
9572 66 : parentSVG->mStroke, mPresContext, aContext,
9573 66 : svg->mStroke, eStyleSVGPaintType_None, conditions);
9574 :
9575 : // stroke-dasharray: <dasharray>, none, inherit, context-value
9576 66 : const nsCSSValue* strokeDasharrayValue = aRuleData->ValueForStrokeDasharray();
9577 66 : switch (strokeDasharrayValue->GetUnit()) {
9578 : case eCSSUnit_Null:
9579 66 : break;
9580 :
9581 : case eCSSUnit_Inherit:
9582 : case eCSSUnit_Unset:
9583 0 : conditions.SetUncacheable();
9584 0 : svg->SetStrokeDasharrayFromObject(parentSVG->StrokeDasharrayFromObject());
9585 0 : svg->mStrokeDasharray = parentSVG->mStrokeDasharray;
9586 0 : break;
9587 :
9588 : case eCSSUnit_Enumerated:
9589 0 : MOZ_ASSERT(strokeDasharrayValue->GetIntValue() ==
9590 : NS_STYLE_STROKE_PROP_CONTEXT_VALUE,
9591 : "Unknown keyword for stroke-dasharray");
9592 0 : svg->SetStrokeDasharrayFromObject(true);
9593 0 : svg->mStrokeDasharray.Clear();
9594 0 : break;
9595 :
9596 : case eCSSUnit_Initial:
9597 : case eCSSUnit_None:
9598 0 : svg->SetStrokeDasharrayFromObject(false);
9599 0 : svg->mStrokeDasharray.Clear();
9600 0 : break;
9601 :
9602 : case eCSSUnit_List:
9603 : case eCSSUnit_ListDep: {
9604 0 : svg->SetStrokeDasharrayFromObject(false);
9605 0 : svg->mStrokeDasharray.Clear();
9606 :
9607 : // count number of values
9608 0 : const nsCSSValueList *value = strokeDasharrayValue->GetListValue();
9609 0 : uint32_t strokeDasharrayLength = ListLength(value);
9610 :
9611 0 : MOZ_ASSERT(strokeDasharrayLength != 0, "no dasharray items");
9612 :
9613 0 : svg->mStrokeDasharray.SetLength(strokeDasharrayLength);
9614 :
9615 0 : uint32_t i = 0;
9616 0 : while (nullptr != value) {
9617 0 : SetCoord(value->mValue,
9618 0 : svg->mStrokeDasharray[i++], nsStyleCoord(),
9619 : SETCOORD_LP | SETCOORD_FACTOR,
9620 0 : aContext, mPresContext, conditions);
9621 0 : value = value->mNext;
9622 : }
9623 0 : break;
9624 : }
9625 :
9626 : default:
9627 0 : MOZ_ASSERT(false, "unrecognized dasharray unit");
9628 : }
9629 :
9630 : // stroke-dashoffset: <dashoffset>, inherit
9631 : const nsCSSValue *strokeDashoffsetValue =
9632 66 : aRuleData->ValueForStrokeDashoffset();
9633 66 : svg->SetStrokeDashoffsetFromObject(
9634 66 : strokeDashoffsetValue->GetUnit() == eCSSUnit_Enumerated &&
9635 66 : strokeDashoffsetValue->GetIntValue() == NS_STYLE_STROKE_PROP_CONTEXT_VALUE);
9636 66 : if (svg->StrokeDashoffsetFromObject()) {
9637 0 : svg->mStrokeDashoffset.SetCoordValue(0);
9638 : } else {
9639 66 : SetCoord(*aRuleData->ValueForStrokeDashoffset(),
9640 : svg->mStrokeDashoffset, parentSVG->mStrokeDashoffset,
9641 : SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_INITIAL_ZERO |
9642 : SETCOORD_UNSET_INHERIT,
9643 132 : aContext, mPresContext, conditions);
9644 : }
9645 :
9646 : // stroke-linecap: enum, inherit, initial
9647 66 : SetValue(*aRuleData->ValueForStrokeLinecap(),
9648 : svg->mStrokeLinecap, conditions,
9649 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
9650 66 : parentSVG->mStrokeLinecap,
9651 66 : NS_STYLE_STROKE_LINECAP_BUTT);
9652 :
9653 : // stroke-linejoin: enum, inherit, initial
9654 66 : SetValue(*aRuleData->ValueForStrokeLinejoin(),
9655 : svg->mStrokeLinejoin, conditions,
9656 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
9657 66 : parentSVG->mStrokeLinejoin,
9658 66 : NS_STYLE_STROKE_LINEJOIN_MITER);
9659 :
9660 : // stroke-miterlimit: <miterlimit>, inherit
9661 66 : SetFactor(*aRuleData->ValueForStrokeMiterlimit(),
9662 : svg->mStrokeMiterlimit,
9663 : conditions,
9664 66 : parentSVG->mStrokeMiterlimit, 4.0f,
9665 66 : SETFCT_UNSET_INHERIT);
9666 :
9667 : // stroke-opacity:
9668 66 : nsStyleSVGOpacitySource contextStrokeOpacity = svg->StrokeOpacitySource();
9669 132 : SetSVGOpacity(*aRuleData->ValueForStrokeOpacity(),
9670 : svg->mStrokeOpacity, contextStrokeOpacity, conditions,
9671 198 : parentSVG->mStrokeOpacity, parentSVG->StrokeOpacitySource());
9672 66 : svg->SetStrokeOpacitySource(contextStrokeOpacity);
9673 :
9674 : // stroke-width:
9675 66 : const nsCSSValue* strokeWidthValue = aRuleData->ValueForStrokeWidth();
9676 66 : switch (strokeWidthValue->GetUnit()) {
9677 : case eCSSUnit_Enumerated:
9678 0 : MOZ_ASSERT(strokeWidthValue->GetIntValue() ==
9679 : NS_STYLE_STROKE_PROP_CONTEXT_VALUE,
9680 : "Unrecognized keyword for stroke-width");
9681 0 : svg->SetStrokeWidthFromObject(true);
9682 0 : svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
9683 0 : break;
9684 :
9685 : case eCSSUnit_Initial:
9686 0 : svg->SetStrokeWidthFromObject(false);
9687 0 : svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
9688 0 : break;
9689 :
9690 : default:
9691 66 : svg->SetStrokeWidthFromObject(false);
9692 66 : SetCoord(*strokeWidthValue,
9693 : svg->mStrokeWidth, parentSVG->mStrokeWidth,
9694 : SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_UNSET_INHERIT,
9695 132 : aContext, mPresContext, conditions);
9696 : }
9697 :
9698 : // text-anchor: enum, inherit, initial
9699 66 : SetValue(*aRuleData->ValueForTextAnchor(),
9700 : svg->mTextAnchor, conditions,
9701 : SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
9702 66 : parentSVG->mTextAnchor,
9703 66 : NS_STYLE_TEXT_ANCHOR_START);
9704 :
9705 : // -moz-context-properties:
9706 66 : const nsCSSValue* contextPropsValue = aRuleData->ValueForContextProperties();
9707 66 : switch (contextPropsValue->GetUnit()) {
9708 : case eCSSUnit_Null:
9709 38 : break;
9710 :
9711 : case eCSSUnit_List:
9712 : case eCSSUnit_ListDep: {
9713 28 : svg->mContextProps.Clear();
9714 28 : svg->mContextPropsBits = 0;
9715 59 : for (const nsCSSValueList* item = contextPropsValue->GetListValue();
9716 90 : item; item = item->mNext)
9717 : {
9718 31 : nsIAtom* atom = item->mValue.GetAtomValue();
9719 31 : svg->mContextProps.AppendElement(atom);
9720 31 : if (atom == nsGkAtoms::fill) {
9721 28 : svg->mContextPropsBits |= NS_STYLE_CONTEXT_PROPERTY_FILL;
9722 3 : } else if (atom == nsGkAtoms::stroke) {
9723 0 : svg->mContextPropsBits |= NS_STYLE_CONTEXT_PROPERTY_STROKE;
9724 3 : } else if (atom == nsGkAtoms::fill_opacity) {
9725 3 : svg->mContextPropsBits |= NS_STYLE_CONTEXT_PROPERTY_FILL_OPACITY;
9726 0 : } else if (atom == nsGkAtoms::stroke_opacity) {
9727 0 : svg->mContextPropsBits |= NS_STYLE_CONTEXT_PROPERTY_STROKE_OPACITY;
9728 : }
9729 : }
9730 28 : break;
9731 : }
9732 :
9733 : case eCSSUnit_Inherit:
9734 : case eCSSUnit_Unset:
9735 0 : svg->mContextProps = parentSVG->mContextProps;
9736 0 : svg->mContextPropsBits = parentSVG->mContextPropsBits;
9737 0 : conditions.SetUncacheable();
9738 0 : break;
9739 :
9740 : case eCSSUnit_Initial:
9741 : case eCSSUnit_None:
9742 0 : svg->mContextProps.Clear();
9743 0 : svg->mContextPropsBits = 0;
9744 0 : break;
9745 :
9746 : default:
9747 0 : MOZ_ASSERT(false, "unrecognized -moz-context-properties value");
9748 : }
9749 :
9750 132 : COMPUTE_END_INHERITED(SVG, svg)
9751 : }
9752 :
9753 : static already_AddRefed<StyleBasicShape>
9754 0 : GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
9755 : GeckoStyleContext* aStyleContext,
9756 : nsPresContext* aPresContext,
9757 : RuleNodeCacheConditions& aConditions)
9758 : {
9759 0 : RefPtr<StyleBasicShape> basicShape;
9760 :
9761 0 : nsCSSValue::Array* shapeFunction = aValue.GetArrayValue();
9762 : nsCSSKeyword functionName =
9763 0 : (nsCSSKeyword)shapeFunction->Item(0).GetIntValue();
9764 :
9765 0 : if (functionName == eCSSKeyword_polygon) {
9766 0 : MOZ_ASSERT(!basicShape, "did not expect value");
9767 0 : basicShape = new StyleBasicShape(StyleBasicShapeType::Polygon);
9768 0 : MOZ_ASSERT(shapeFunction->Count() > 1,
9769 : "polygon has wrong number of arguments");
9770 0 : size_t j = 1;
9771 0 : if (shapeFunction->Item(j).GetUnit() == eCSSUnit_Enumerated) {
9772 : StyleFillRule rule;
9773 0 : SetEnumValueHelper::SetEnumeratedValue(rule, shapeFunction->Item(j));
9774 0 : basicShape->SetFillRule(rule);
9775 0 : ++j;
9776 : }
9777 : const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
9778 0 : SETCOORD_STORE_CALC;
9779 : const nsCSSValuePairList* curPair =
9780 0 : shapeFunction->Item(j).GetPairListValue();
9781 0 : nsTArray<nsStyleCoord>& coordinates = basicShape->Coordinates();
9782 0 : while (curPair) {
9783 0 : nsStyleCoord xCoord, yCoord;
9784 0 : DebugOnly<bool> didSetCoordX = SetCoord(curPair->mXValue, xCoord,
9785 0 : nsStyleCoord(), mask,
9786 : aStyleContext, aPresContext,
9787 0 : aConditions);
9788 0 : coordinates.AppendElement(xCoord);
9789 0 : MOZ_ASSERT(didSetCoordX, "unexpected x coordinate unit");
9790 0 : DebugOnly<bool> didSetCoordY = SetCoord(curPair->mYValue, yCoord,
9791 0 : nsStyleCoord(), mask,
9792 : aStyleContext, aPresContext,
9793 0 : aConditions);
9794 0 : coordinates.AppendElement(yCoord);
9795 0 : MOZ_ASSERT(didSetCoordY, "unexpected y coordinate unit");
9796 0 : curPair = curPair->mNext;
9797 : }
9798 0 : } else if (functionName == eCSSKeyword_circle ||
9799 : functionName == eCSSKeyword_ellipse) {
9800 0 : StyleBasicShapeType type = functionName == eCSSKeyword_circle ?
9801 : StyleBasicShapeType::Circle :
9802 0 : StyleBasicShapeType::Ellipse;
9803 0 : MOZ_ASSERT(!basicShape, "did not expect value");
9804 0 : basicShape = new StyleBasicShape(type);
9805 : const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
9806 0 : SETCOORD_STORE_CALC | SETCOORD_ENUMERATED;
9807 0 : size_t count = type == StyleBasicShapeType::Circle ? 2 : 3;
9808 0 : MOZ_ASSERT(shapeFunction->Count() == count + 1,
9809 : "unexpected arguments count");
9810 0 : MOZ_ASSERT(type == StyleBasicShapeType::Circle ||
9811 : (shapeFunction->Item(1).GetUnit() == eCSSUnit_Null) ==
9812 : (shapeFunction->Item(2).GetUnit() == eCSSUnit_Null),
9813 : "ellipse should have two radii or none");
9814 0 : for (size_t j = 1; j < count; ++j) {
9815 0 : const nsCSSValue& val = shapeFunction->Item(j);
9816 0 : nsStyleCoord radius;
9817 0 : if (val.GetUnit() != eCSSUnit_Null) {
9818 0 : DebugOnly<bool> didSetRadius = SetCoord(val, radius,
9819 0 : nsStyleCoord(), mask,
9820 : aStyleContext,
9821 : aPresContext,
9822 0 : aConditions);
9823 0 : MOZ_ASSERT(didSetRadius, "unexpected radius unit");
9824 : } else {
9825 0 : radius.SetEnumValue(StyleShapeRadius::ClosestSide);
9826 : }
9827 0 : basicShape->Coordinates().AppendElement(radius);
9828 : }
9829 0 : const nsCSSValue& positionVal = shapeFunction->Item(count);
9830 0 : if (positionVal.GetUnit() == eCSSUnit_Array) {
9831 0 : ComputePositionValue(aStyleContext, positionVal,
9832 : basicShape->GetPosition(),
9833 0 : aConditions);
9834 : } else {
9835 0 : MOZ_ASSERT(positionVal.GetUnit() == eCSSUnit_Null,
9836 : "expected no value");
9837 0 : }
9838 0 : } else if (functionName == eCSSKeyword_inset) {
9839 0 : MOZ_ASSERT(!basicShape, "did not expect value");
9840 0 : basicShape = new StyleBasicShape(StyleBasicShapeType::Inset);
9841 0 : MOZ_ASSERT(shapeFunction->Count() == 6,
9842 : "inset function has wrong number of arguments");
9843 0 : MOZ_ASSERT(shapeFunction->Item(1).GetUnit() != eCSSUnit_Null,
9844 : "no shape arguments defined");
9845 : const int32_t mask = SETCOORD_PERCENT | SETCOORD_LENGTH |
9846 0 : SETCOORD_STORE_CALC;
9847 0 : nsTArray<nsStyleCoord>& coords = basicShape->Coordinates();
9848 0 : for (size_t j = 1; j <= 4; ++j) {
9849 0 : const nsCSSValue& val = shapeFunction->Item(j);
9850 0 : nsStyleCoord inset;
9851 : // Fill missing values to get 4 at the end.
9852 0 : if (val.GetUnit() == eCSSUnit_Null) {
9853 0 : if (j == 4) {
9854 0 : inset = coords[1];
9855 : } else {
9856 0 : MOZ_ASSERT(j != 1, "first argument not specified");
9857 0 : inset = coords[0];
9858 : }
9859 : } else {
9860 0 : DebugOnly<bool> didSetInset = SetCoord(val, inset,
9861 0 : nsStyleCoord(), mask,
9862 : aStyleContext, aPresContext,
9863 0 : aConditions);
9864 0 : MOZ_ASSERT(didSetInset, "unexpected inset unit");
9865 : }
9866 0 : coords.AppendElement(inset);
9867 : }
9868 :
9869 0 : nsStyleCorners& insetRadius = basicShape->GetRadius();
9870 0 : if (shapeFunction->Item(5).GetUnit() == eCSSUnit_Array) {
9871 0 : nsCSSValue::Array* radiiArray = shapeFunction->Item(5).GetArrayValue();
9872 0 : NS_FOR_CSS_FULL_CORNERS(corner) {
9873 0 : int cx = FullToHalfCorner(corner, false);
9874 0 : int cy = FullToHalfCorner(corner, true);
9875 0 : const nsCSSValue& radius = radiiArray->Item(corner);
9876 0 : nsStyleCoord coordX, coordY;
9877 0 : DebugOnly<bool> didSetRadii = SetPairCoords(radius, coordX, coordY,
9878 0 : nsStyleCoord(),
9879 0 : nsStyleCoord(), mask,
9880 : aStyleContext,
9881 : aPresContext,
9882 0 : aConditions);
9883 0 : MOZ_ASSERT(didSetRadii, "unexpected radius unit");
9884 0 : insetRadius.Set(cx, coordX);
9885 0 : insetRadius.Set(cy, coordY);
9886 : }
9887 : } else {
9888 0 : MOZ_ASSERT(shapeFunction->Item(5).GetUnit() == eCSSUnit_Null,
9889 : "unexpected value");
9890 : // Initialize border-radius
9891 0 : nsStyleCoord zero;
9892 0 : zero.SetCoordValue(0);
9893 0 : NS_FOR_CSS_HALF_CORNERS(j) {
9894 0 : insetRadius.Set(j, zero);
9895 : }
9896 : }
9897 : } else {
9898 0 : NS_NOTREACHED("unexpected basic shape function");
9899 : }
9900 :
9901 0 : return basicShape.forget();
9902 : }
9903 :
9904 : static void
9905 0 : SetStyleShapeSourceToCSSValue(
9906 : StyleShapeSource* aShapeSource,
9907 : const nsCSSValue* aValue,
9908 : GeckoStyleContext* aStyleContext,
9909 : nsPresContext* aPresContext,
9910 : RuleNodeCacheConditions& aConditions)
9911 : {
9912 0 : MOZ_ASSERT(aValue->GetUnit() == eCSSUnit_Array,
9913 : "expected a basic shape or reference box");
9914 :
9915 0 : const nsCSSValue::Array* array = aValue->GetArrayValue();
9916 0 : MOZ_ASSERT(array->Count() == 1 || array->Count() == 2,
9917 : "Expect one or both of a shape function and a reference box");
9918 :
9919 0 : StyleGeometryBox referenceBox = StyleGeometryBox::NoBox;
9920 0 : RefPtr<StyleBasicShape> basicShape;
9921 :
9922 0 : for (size_t i = 0; i < array->Count(); ++i) {
9923 0 : const nsCSSValue& item = array->Item(i);
9924 0 : if (item.GetUnit() == eCSSUnit_Enumerated) {
9925 0 : referenceBox = static_cast<StyleGeometryBox>(item.GetIntValue());
9926 0 : } else if (item.GetUnit() == eCSSUnit_Function) {
9927 0 : basicShape = GetStyleBasicShapeFromCSSValue(item, aStyleContext,
9928 0 : aPresContext, aConditions);
9929 : } else {
9930 0 : MOZ_ASSERT_UNREACHABLE("Unexpected unit!");
9931 : return;
9932 : }
9933 : }
9934 :
9935 0 : if (basicShape) {
9936 0 : aShapeSource->SetBasicShape(basicShape, referenceBox);
9937 : } else {
9938 0 : aShapeSource->SetReferenceBox(referenceBox);
9939 : }
9940 0 : }
9941 :
9942 : // Returns true if the nsStyleFilter was successfully set using the nsCSSValue.
9943 : static bool
9944 0 : SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
9945 : const nsCSSValue& aValue,
9946 : GeckoStyleContext* aStyleContext,
9947 : nsPresContext* aPresContext,
9948 : RuleNodeCacheConditions& aConditions)
9949 : {
9950 0 : nsCSSUnit unit = aValue.GetUnit();
9951 0 : if (unit == eCSSUnit_URL) {
9952 0 : return aStyleFilter->SetURL(aValue.GetURLStructValue());
9953 : }
9954 :
9955 0 : MOZ_ASSERT(unit == eCSSUnit_Function, "expected a filter function");
9956 :
9957 0 : nsCSSValue::Array* filterFunction = aValue.GetArrayValue();
9958 : nsCSSKeyword functionName =
9959 0 : (nsCSSKeyword)filterFunction->Item(0).GetIntValue();
9960 :
9961 : int32_t type;
9962 : DebugOnly<bool> foundKeyword =
9963 0 : nsCSSProps::FindKeyword(functionName,
9964 : nsCSSProps::kFilterFunctionKTable,
9965 0 : type);
9966 0 : MOZ_ASSERT(foundKeyword, "unknown filter type");
9967 0 : if (type == NS_STYLE_FILTER_DROP_SHADOW) {
9968 0 : RefPtr<nsCSSShadowArray> shadowArray = GetShadowData(
9969 0 : filterFunction->Item(1).GetListValue(),
9970 : aStyleContext,
9971 : false,
9972 : aPresContext,
9973 0 : aConditions);
9974 0 : aStyleFilter->SetDropShadow(shadowArray);
9975 0 : return true;
9976 : }
9977 :
9978 0 : int32_t mask = SETCOORD_PERCENT | SETCOORD_FACTOR;
9979 0 : if (type == NS_STYLE_FILTER_BLUR) {
9980 0 : mask = SETCOORD_LENGTH |
9981 : SETCOORD_CALC_LENGTH_ONLY |
9982 : SETCOORD_CALC_CLAMP_NONNEGATIVE;
9983 0 : } else if (type == NS_STYLE_FILTER_HUE_ROTATE) {
9984 0 : mask = SETCOORD_ANGLE;
9985 : }
9986 :
9987 0 : MOZ_ASSERT(filterFunction->Count() == 2,
9988 : "all filter functions should have exactly one argument");
9989 :
9990 0 : nsCSSValue& arg = filterFunction->Item(1);
9991 0 : nsStyleCoord filterParameter;
9992 0 : DebugOnly<bool> didSetCoord = SetCoord(arg, filterParameter,
9993 0 : nsStyleCoord(), mask,
9994 : aStyleContext, aPresContext,
9995 0 : aConditions);
9996 0 : aStyleFilter->SetFilterParameter(filterParameter, type);
9997 0 : MOZ_ASSERT(didSetCoord, "unexpected unit");
9998 0 : return true;
9999 : }
10000 :
10001 : const void*
10002 30 : nsRuleNode::ComputeSVGResetData(void* aStartStruct,
10003 : const nsRuleData* aRuleData,
10004 : GeckoStyleContext* aContext,
10005 : nsRuleNode* aHighestNode,
10006 : const RuleDetail aRuleDetail,
10007 : const RuleNodeCacheConditions aConditions)
10008 : {
10009 60 : COMPUTE_START_RESET(SVGReset, svgReset, parentSVGReset)
10010 :
10011 : // stop-color:
10012 30 : const nsCSSValue* stopColorValue = aRuleData->ValueForStopColor();
10013 60 : if (eCSSUnit_Initial == stopColorValue->GetUnit() ||
10014 30 : eCSSUnit_Unset == stopColorValue->GetUnit()) {
10015 0 : svgReset->mStopColor = NS_RGB(0, 0, 0);
10016 : } else {
10017 60 : SetColor(*stopColorValue, parentSVGReset->mStopColor,
10018 60 : mPresContext, aContext, svgReset->mStopColor, conditions);
10019 : }
10020 :
10021 : // flood-color:
10022 30 : const nsCSSValue* floodColorValue = aRuleData->ValueForFloodColor();
10023 60 : if (eCSSUnit_Initial == floodColorValue->GetUnit() ||
10024 30 : eCSSUnit_Unset == floodColorValue->GetUnit()) {
10025 0 : svgReset->mFloodColor = NS_RGB(0, 0, 0);
10026 : } else {
10027 60 : SetColor(*floodColorValue, parentSVGReset->mFloodColor,
10028 60 : mPresContext, aContext, svgReset->mFloodColor, conditions);
10029 : }
10030 :
10031 : // lighting-color:
10032 30 : const nsCSSValue* lightingColorValue = aRuleData->ValueForLightingColor();
10033 60 : if (eCSSUnit_Initial == lightingColorValue->GetUnit() ||
10034 30 : eCSSUnit_Unset == lightingColorValue->GetUnit()) {
10035 0 : svgReset->mLightingColor = NS_RGB(255, 255, 255);
10036 : } else {
10037 60 : SetColor(*lightingColorValue, parentSVGReset->mLightingColor,
10038 30 : mPresContext, aContext, svgReset->mLightingColor,
10039 30 : conditions);
10040 : }
10041 :
10042 : // clip-path: url, <basic-shape> || <geometry-box>, none, inherit
10043 30 : const nsCSSValue* clipPathValue = aRuleData->ValueForClipPath();
10044 30 : switch (clipPathValue->GetUnit()) {
10045 : case eCSSUnit_Null:
10046 28 : break;
10047 : case eCSSUnit_None:
10048 : case eCSSUnit_Initial:
10049 : case eCSSUnit_Unset:
10050 0 : svgReset->mClipPath = StyleShapeSource();
10051 0 : break;
10052 : case eCSSUnit_Inherit:
10053 0 : conditions.SetUncacheable();
10054 0 : svgReset->mClipPath = parentSVGReset->mClipPath;
10055 0 : break;
10056 : case eCSSUnit_URL: {
10057 2 : svgReset->mClipPath = StyleShapeSource();
10058 2 : svgReset->mClipPath.SetURL(clipPathValue->GetURLStructValue());
10059 2 : break;
10060 : }
10061 : case eCSSUnit_Array: {
10062 0 : svgReset->mClipPath = StyleShapeSource();
10063 0 : SetStyleShapeSourceToCSSValue(&svgReset->mClipPath, clipPathValue, aContext,
10064 0 : mPresContext, conditions);
10065 0 : break;
10066 : }
10067 : default:
10068 0 : NS_NOTREACHED("unexpected unit");
10069 : }
10070 :
10071 : // stop-opacity:
10072 30 : SetFactor(*aRuleData->ValueForStopOpacity(),
10073 : svgReset->mStopOpacity, conditions,
10074 30 : parentSVGReset->mStopOpacity, 1.0f,
10075 30 : SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
10076 :
10077 : // flood-opacity:
10078 30 : SetFactor(*aRuleData->ValueForFloodOpacity(),
10079 : svgReset->mFloodOpacity, conditions,
10080 30 : parentSVGReset->mFloodOpacity, 1.0f,
10081 30 : SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
10082 :
10083 : // dominant-baseline: enum, inherit, initial
10084 30 : SetValue(*aRuleData->ValueForDominantBaseline(),
10085 : svgReset->mDominantBaseline,
10086 : conditions,
10087 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
10088 30 : parentSVGReset->mDominantBaseline,
10089 30 : NS_STYLE_DOMINANT_BASELINE_AUTO);
10090 :
10091 : // vector-effect: enum, inherit, initial
10092 30 : SetValue(*aRuleData->ValueForVectorEffect(),
10093 : svgReset->mVectorEffect,
10094 : conditions,
10095 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
10096 30 : parentSVGReset->mVectorEffect,
10097 30 : NS_STYLE_VECTOR_EFFECT_NONE);
10098 :
10099 : // mask-type: enum, inherit, initial
10100 30 : SetValue(*aRuleData->ValueForMaskType(),
10101 : svgReset->mMaskType,
10102 : conditions,
10103 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
10104 30 : parentSVGReset->mMaskType,
10105 30 : NS_STYLE_MASK_TYPE_LUMINANCE);
10106 :
10107 : #ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
10108 30 : uint32_t maxItemCount = 1;
10109 30 : bool rebuild = false;
10110 :
10111 : // mask-image: none | <url> | <image-list> | <element-reference> | <gradient>
10112 60 : nsStyleImage initialImage;
10113 90 : SetImageLayerList(aContext, *aRuleData->ValueForMaskImage(),
10114 : svgReset->mMask.mLayers,
10115 : parentSVGReset->mMask.mLayers,
10116 : &nsStyleImageLayers::Layer::mImage,
10117 30 : initialImage, parentSVGReset->mMask.mImageCount,
10118 : svgReset->mMask.mImageCount,
10119 30 : maxItemCount, rebuild, conditions);
10120 :
10121 : // mask-repeat: enum, inherit, initial [pair list]
10122 30 : nsStyleImageLayers::Repeat initialRepeat;
10123 30 : initialRepeat.SetInitialValues();
10124 60 : SetImageLayerPairList(aContext, *aRuleData->ValueForMaskRepeat(),
10125 : svgReset->mMask.mLayers,
10126 : parentSVGReset->mMask.mLayers,
10127 : &nsStyleImageLayers::Layer::mRepeat,
10128 30 : initialRepeat, parentSVGReset->mMask.mRepeatCount,
10129 : svgReset->mMask.mRepeatCount, maxItemCount, rebuild,
10130 30 : conditions);
10131 :
10132 : // mask-clip: enum, inherit, initial [list]
10133 60 : SetImageLayerList(aContext, *aRuleData->ValueForMaskClip(),
10134 : svgReset->mMask.mLayers,
10135 : parentSVGReset->mMask.mLayers,
10136 : &nsStyleImageLayers::Layer::mClip,
10137 : StyleGeometryBox::BorderBox,
10138 30 : parentSVGReset->mMask.mClipCount,
10139 : svgReset->mMask.mClipCount, maxItemCount, rebuild,
10140 30 : conditions);
10141 :
10142 : // mask-origin: enum, inherit, initial [list]
10143 60 : SetImageLayerList(aContext, *aRuleData->ValueForMaskOrigin(),
10144 : svgReset->mMask.mLayers,
10145 : parentSVGReset->mMask.mLayers,
10146 : &nsStyleImageLayers::Layer::mOrigin,
10147 : StyleGeometryBox::BorderBox,
10148 30 : parentSVGReset->mMask.mOriginCount,
10149 : svgReset->mMask.mOriginCount, maxItemCount, rebuild,
10150 30 : conditions);
10151 :
10152 : // mask-position-x/y: enum, length, percent (flags), inherit [list]
10153 : Position::Coord initialPositionCoord;
10154 30 : initialPositionCoord.mPercent = 0.0f;
10155 30 : initialPositionCoord.mLength = 0;
10156 30 : initialPositionCoord.mHasPercent = true;
10157 :
10158 60 : SetImageLayerPositionCoordList(
10159 30 : aContext, *aRuleData->ValueForMaskPositionX(),
10160 : svgReset->mMask.mLayers,
10161 : parentSVGReset->mMask.mLayers,
10162 : &Position::mXPosition,
10163 30 : initialPositionCoord, parentSVGReset->mMask.mPositionXCount,
10164 : svgReset->mMask.mPositionXCount, maxItemCount, rebuild,
10165 30 : conditions);
10166 60 : SetImageLayerPositionCoordList(
10167 30 : aContext, *aRuleData->ValueForMaskPositionY(),
10168 : svgReset->mMask.mLayers,
10169 : parentSVGReset->mMask.mLayers,
10170 : &Position::mYPosition,
10171 30 : initialPositionCoord, parentSVGReset->mMask.mPositionYCount,
10172 : svgReset->mMask.mPositionYCount, maxItemCount, rebuild,
10173 30 : conditions);
10174 :
10175 : // mask-size: enum, length, auto, inherit, initial [pair list]
10176 30 : nsStyleImageLayers::Size initialSize;
10177 30 : initialSize.SetInitialValues();
10178 60 : SetImageLayerPairList(aContext, *aRuleData->ValueForMaskSize(),
10179 : svgReset->mMask.mLayers,
10180 : parentSVGReset->mMask.mLayers,
10181 : &nsStyleImageLayers::Layer::mSize,
10182 30 : initialSize, parentSVGReset->mMask.mSizeCount,
10183 : svgReset->mMask.mSizeCount, maxItemCount, rebuild,
10184 30 : conditions);
10185 :
10186 : // mask-mode: enum, inherit, initial [list]
10187 60 : SetImageLayerList(aContext, *aRuleData->ValueForMaskMode(),
10188 : svgReset->mMask.mLayers,
10189 : parentSVGReset->mMask.mLayers,
10190 : &nsStyleImageLayers::Layer::mMaskMode,
10191 : uint8_t(NS_STYLE_MASK_MODE_MATCH_SOURCE),
10192 30 : parentSVGReset->mMask.mMaskModeCount,
10193 30 : svgReset->mMask.mMaskModeCount, maxItemCount, rebuild, conditions);
10194 :
10195 : // mask-composite: enum, inherit, initial [list]
10196 60 : SetImageLayerList(aContext, *aRuleData->ValueForMaskComposite(),
10197 : svgReset->mMask.mLayers,
10198 : parentSVGReset->mMask.mLayers,
10199 : &nsStyleImageLayers::Layer::mComposite,
10200 : uint8_t(NS_STYLE_MASK_COMPOSITE_ADD),
10201 30 : parentSVGReset->mMask.mCompositeCount,
10202 30 : svgReset->mMask.mCompositeCount, maxItemCount, rebuild, conditions);
10203 :
10204 30 : if (rebuild) {
10205 2 : FillAllBackgroundLists(svgReset->mMask, maxItemCount);
10206 : }
10207 : #else
10208 : // mask: none | <url>
10209 : const nsCSSValue* maskValue = aRuleData->ValueForMask();
10210 : if (eCSSUnit_URL == maskValue->GetUnit()) {
10211 : svgReset->mMask.mLayers[0].mSourceURI = maskValue->GetURLStructValue();
10212 : } else if (eCSSUnit_None == maskValue->GetUnit() ||
10213 : eCSSUnit_Initial == maskValue->GetUnit() ||
10214 : eCSSUnit_Unset == maskValue->GetUnit()) {
10215 : svgReset->mMask.mLayers[0].mSourceURI = nullptr;
10216 : } else if (eCSSUnit_Inherit == maskValue->GetUnit()) {
10217 : conditions.SetUncacheable();
10218 : svgReset->mMask.mLayers[0].mSourceURI =
10219 : parentSVGReset->mMask.mLayers[0].mSourceURI;
10220 : }
10221 : #endif
10222 :
10223 60 : COMPUTE_END_RESET(SVGReset, svgReset)
10224 : }
10225 :
10226 : const void*
10227 12 : nsRuleNode::ComputeVariablesData(void* aStartStruct,
10228 : const nsRuleData* aRuleData,
10229 : GeckoStyleContext* aContext,
10230 : nsRuleNode* aHighestNode,
10231 : const RuleDetail aRuleDetail,
10232 : const RuleNodeCacheConditions aConditions)
10233 : {
10234 24 : COMPUTE_START_INHERITED(Variables, variables, parentVariables)
10235 :
10236 12 : MOZ_ASSERT(aRuleData->mVariables,
10237 : "shouldn't be in ComputeVariablesData if there were no variable "
10238 : "declarations specified");
10239 :
10240 24 : CSSVariableResolver resolver(&variables->mVariables);
10241 12 : resolver.Resolve(&parentVariables->mVariables,
10242 24 : aRuleData->mVariables);
10243 12 : conditions.SetUncacheable();
10244 :
10245 24 : COMPUTE_END_INHERITED(Variables, variables)
10246 : }
10247 :
10248 : const void*
10249 87 : nsRuleNode::ComputeEffectsData(void* aStartStruct,
10250 : const nsRuleData* aRuleData,
10251 : GeckoStyleContext* aContext,
10252 : nsRuleNode* aHighestNode,
10253 : const RuleDetail aRuleDetail,
10254 : const RuleNodeCacheConditions aConditions)
10255 : {
10256 174 : COMPUTE_START_RESET(Effects, effects, parentEffects)
10257 :
10258 : // filter: url, none, inherit
10259 87 : const nsCSSValue* filterValue = aRuleData->ValueForFilter();
10260 87 : switch (filterValue->GetUnit()) {
10261 : case eCSSUnit_Null:
10262 87 : break;
10263 : case eCSSUnit_None:
10264 : case eCSSUnit_Initial:
10265 : case eCSSUnit_Unset:
10266 0 : effects->mFilters.Clear();
10267 0 : break;
10268 : case eCSSUnit_Inherit:
10269 0 : conditions.SetUncacheable();
10270 0 : effects->mFilters = parentEffects->mFilters;
10271 0 : break;
10272 : case eCSSUnit_List:
10273 : case eCSSUnit_ListDep: {
10274 0 : effects->mFilters.Clear();
10275 0 : const nsCSSValueList* cur = filterValue->GetListValue();
10276 0 : while (cur) {
10277 0 : nsStyleFilter styleFilter;
10278 0 : if (!SetStyleFilterToCSSValue(&styleFilter, cur->mValue, aContext,
10279 0 : mPresContext, conditions)) {
10280 0 : effects->mFilters.Clear();
10281 0 : break;
10282 : }
10283 0 : MOZ_ASSERT(styleFilter.GetType() != NS_STYLE_FILTER_NONE,
10284 : "filter should be set");
10285 0 : effects->mFilters.AppendElement(styleFilter);
10286 0 : cur = cur->mNext;
10287 : }
10288 0 : break;
10289 : }
10290 : default:
10291 0 : NS_NOTREACHED("unexpected unit");
10292 : }
10293 :
10294 : // box-shadow: none, list, inherit, initial
10295 87 : const nsCSSValue* boxShadowValue = aRuleData->ValueForBoxShadow();
10296 87 : switch (boxShadowValue->GetUnit()) {
10297 : case eCSSUnit_Null:
10298 81 : break;
10299 :
10300 : case eCSSUnit_Initial:
10301 : case eCSSUnit_Unset:
10302 : case eCSSUnit_None:
10303 0 : effects->mBoxShadow = nullptr;
10304 0 : break;
10305 :
10306 : case eCSSUnit_Inherit:
10307 0 : effects->mBoxShadow = parentEffects->mBoxShadow;
10308 0 : conditions.SetUncacheable();
10309 0 : break;
10310 :
10311 : case eCSSUnit_List:
10312 : case eCSSUnit_ListDep:
10313 12 : effects->mBoxShadow = GetShadowData(boxShadowValue->GetListValue(),
10314 12 : aContext, true, mPresContext, conditions);
10315 6 : break;
10316 :
10317 : default:
10318 0 : MOZ_ASSERT(false, "unrecognized shadow unit");
10319 : }
10320 :
10321 : // clip property: length, auto, inherit
10322 87 : const nsCSSValue* clipValue = aRuleData->ValueForClip();
10323 87 : switch (clipValue->GetUnit()) {
10324 : case eCSSUnit_Inherit:
10325 0 : conditions.SetUncacheable();
10326 0 : effects->mClipFlags = parentEffects->mClipFlags;
10327 0 : effects->mClip = parentEffects->mClip;
10328 0 : break;
10329 :
10330 : case eCSSUnit_Initial:
10331 : case eCSSUnit_Unset:
10332 : case eCSSUnit_Auto:
10333 0 : effects->mClipFlags = NS_STYLE_CLIP_AUTO;
10334 0 : effects->mClip.SetRect(0,0,0,0);
10335 0 : break;
10336 :
10337 : case eCSSUnit_Null:
10338 87 : break;
10339 :
10340 : case eCSSUnit_Rect: {
10341 0 : const nsCSSRect& clipRect = clipValue->GetRectValue();
10342 :
10343 0 : effects->mClipFlags = NS_STYLE_CLIP_RECT;
10344 :
10345 0 : if (clipRect.mTop.GetUnit() == eCSSUnit_Auto) {
10346 0 : effects->mClip.y = 0;
10347 0 : effects->mClipFlags |= NS_STYLE_CLIP_TOP_AUTO;
10348 : }
10349 0 : else if (clipRect.mTop.IsLengthUnit()) {
10350 0 : effects->mClip.y = CalcLength(clipRect.mTop, aContext,
10351 0 : mPresContext, conditions);
10352 : }
10353 :
10354 0 : if (clipRect.mBottom.GetUnit() == eCSSUnit_Auto) {
10355 : // Setting to NS_MAXSIZE for the 'auto' case ensures that
10356 : // the clip rect is nonempty. It is important that mClip be
10357 : // nonempty if the actual clip rect could be nonempty.
10358 0 : effects->mClip.height = NS_MAXSIZE;
10359 0 : effects->mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO;
10360 : }
10361 0 : else if (clipRect.mBottom.IsLengthUnit()) {
10362 0 : effects->mClip.height = CalcLength(clipRect.mBottom, aContext,
10363 0 : mPresContext, conditions) -
10364 0 : effects->mClip.y;
10365 : }
10366 :
10367 0 : if (clipRect.mLeft.GetUnit() == eCSSUnit_Auto) {
10368 0 : effects->mClip.x = 0;
10369 0 : effects->mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO;
10370 : }
10371 0 : else if (clipRect.mLeft.IsLengthUnit()) {
10372 0 : effects->mClip.x = CalcLength(clipRect.mLeft, aContext,
10373 0 : mPresContext, conditions);
10374 : }
10375 :
10376 0 : if (clipRect.mRight.GetUnit() == eCSSUnit_Auto) {
10377 : // Setting to NS_MAXSIZE for the 'auto' case ensures that
10378 : // the clip rect is nonempty. It is important that mClip be
10379 : // nonempty if the actual clip rect could be nonempty.
10380 0 : effects->mClip.width = NS_MAXSIZE;
10381 0 : effects->mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO;
10382 : }
10383 0 : else if (clipRect.mRight.IsLengthUnit()) {
10384 0 : effects->mClip.width = CalcLength(clipRect.mRight, aContext,
10385 0 : mPresContext, conditions) -
10386 0 : effects->mClip.x;
10387 : }
10388 0 : break;
10389 : }
10390 :
10391 : default:
10392 0 : MOZ_ASSERT(false, "unrecognized clip unit");
10393 : }
10394 :
10395 : // opacity: factor, inherit, initial
10396 87 : SetFactor(*aRuleData->ValueForOpacity(), effects->mOpacity, conditions,
10397 87 : parentEffects->mOpacity, 1.0f,
10398 87 : SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
10399 :
10400 : // mix-blend-mode: enum, inherit, initial
10401 87 : SetValue(*aRuleData->ValueForMixBlendMode(), effects->mMixBlendMode,
10402 : conditions,
10403 : SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
10404 174 : parentEffects->mMixBlendMode, NS_STYLE_BLEND_NORMAL);
10405 :
10406 174 : COMPUTE_END_RESET(Effects, effects)
10407 : }
10408 :
10409 : const void*
10410 827 : nsRuleNode::GetStyleData(nsStyleStructID aSID,
10411 : GeckoStyleContext* aContext,
10412 : bool aComputeData)
10413 : {
10414 827 : NS_ASSERTION(IsUsedDirectly(),
10415 : "if we ever call this on rule nodes that aren't used "
10416 : "directly, we should adjust handling of mDependentBits "
10417 : "in some way.");
10418 827 : MOZ_ASSERT(!aContext->GetCachedStyleData(aSID),
10419 : "style context should not have cached data for struct");
10420 :
10421 : const void *data;
10422 :
10423 : // Never use cached data for animated style inside a pseudo-element;
10424 : // see comment on cacheability in AnimValuesStyleRule::MapRuleInfoInto.
10425 827 : if (!(HasAnimationData() && ParentHasPseudoElementData(aContext))) {
10426 827 : data = mStyleData.GetStyleData(aSID, aContext, aComputeData);
10427 827 : if (MOZ_LIKELY(data != nullptr)) {
10428 : // For inherited structs, mark the struct (which will be set on
10429 : // the context by our caller) as not being owned by the context.
10430 318 : if (!nsCachedStyleData::IsReset(aSID)) {
10431 1 : aContext->AddStyleBit(nsCachedStyleData::GetBitForSID(aSID));
10432 317 : } else if (HasAnimationData()) {
10433 : // If we have animation data, the struct should be cached on the style
10434 : // context so that we can peek the struct.
10435 : // See comment in AnimValuesStyleRule::MapRuleInfoInto.
10436 0 : StoreStyleOnContext(aContext, aSID, const_cast<void*>(data));
10437 : }
10438 :
10439 318 : return data; // We have a fully specified struct. Just return it.
10440 : }
10441 : }
10442 :
10443 509 : if (MOZ_UNLIKELY(!aComputeData))
10444 0 : return nullptr;
10445 :
10446 : // Nothing is cached. We'll have to delve further and examine our rules.
10447 509 : data = WalkRuleTree(aSID, aContext);
10448 :
10449 509 : MOZ_ASSERT(data, "should have aborted on out-of-memory");
10450 509 : return data;
10451 : }
10452 :
10453 : void
10454 0 : nsRuleNode::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
10455 : nsCSSValue* aValue)
10456 : {
10457 0 : for (nsRuleNode* node = this; node; node = node->GetParent()) {
10458 0 : nsIStyleRule* rule = node->GetRule();
10459 0 : if (!rule) {
10460 0 : continue;
10461 : }
10462 0 : if (rule->GetDiscretelyAnimatedCSSValue(aProperty, aValue)) {
10463 0 : return;
10464 : }
10465 : }
10466 : }
10467 :
10468 : /* static */ bool
10469 0 : nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
10470 : uint32_t ruleTypeMask,
10471 : bool aAuthorColorsAllowed)
10472 : {
10473 : #ifdef MOZ_STYLO
10474 : if (aStyleContext->IsServo()) {
10475 : NS_WARNING("stylo: nsRuleNode::HasAuthorSpecifiedRules not implemented");
10476 : return true;
10477 : }
10478 : #endif
10479 :
10480 0 : RefPtr<GeckoStyleContext> styleContext = aStyleContext->AsGecko();
10481 :
10482 0 : uint32_t inheritBits = 0;
10483 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND)
10484 0 : inheritBits |= NS_STYLE_INHERIT_BIT(Background);
10485 :
10486 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER)
10487 0 : inheritBits |= NS_STYLE_INHERIT_BIT(Border);
10488 :
10489 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING)
10490 0 : inheritBits |= NS_STYLE_INHERIT_BIT(Padding);
10491 :
10492 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW)
10493 0 : inheritBits |= NS_STYLE_INHERIT_BIT(Text);
10494 :
10495 : // properties in the SIDS, whether or not we care about them
10496 0 : size_t nprops = 0,
10497 : backgroundOffset, borderOffset, paddingOffset, textShadowOffset;
10498 :
10499 : // We put the reset properties the start of the nsCSSValue array....
10500 :
10501 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
10502 0 : backgroundOffset = nprops;
10503 0 : nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Background);
10504 : }
10505 :
10506 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
10507 0 : borderOffset = nprops;
10508 0 : nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Border);
10509 : }
10510 :
10511 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
10512 0 : paddingOffset = nprops;
10513 0 : nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Padding);
10514 : }
10515 :
10516 : // ...and the inherited properties at the end of the array.
10517 0 : size_t inheritedOffset = nprops;
10518 :
10519 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
10520 0 : textShadowOffset = nprops;
10521 0 : nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Text);
10522 : }
10523 :
10524 0 : void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
10525 0 : AutoCSSValueArray dataArray(dataStorage, nprops);
10526 :
10527 : /* We're relying on the use of |styleContext| not mutating it! */
10528 : nsRuleData ruleData(inheritBits, dataArray.get(),
10529 0 : styleContext->PresContext(), styleContext);
10530 :
10531 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
10532 0 : ruleData.mValueOffsets[eStyleStruct_Background] = backgroundOffset;
10533 : }
10534 :
10535 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
10536 0 : ruleData.mValueOffsets[eStyleStruct_Border] = borderOffset;
10537 : }
10538 :
10539 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
10540 0 : ruleData.mValueOffsets[eStyleStruct_Padding] = paddingOffset;
10541 : }
10542 :
10543 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
10544 0 : ruleData.mValueOffsets[eStyleStruct_Text] = textShadowOffset;
10545 : }
10546 :
10547 : static const nsCSSPropertyID backgroundValues[] = {
10548 : eCSSProperty_background_color,
10549 : eCSSProperty_background_image,
10550 : };
10551 :
10552 : static const nsCSSPropertyID borderValues[] = {
10553 : eCSSProperty_border_top_color,
10554 : eCSSProperty_border_top_style,
10555 : eCSSProperty_border_top_width,
10556 : eCSSProperty_border_right_color,
10557 : eCSSProperty_border_right_style,
10558 : eCSSProperty_border_right_width,
10559 : eCSSProperty_border_bottom_color,
10560 : eCSSProperty_border_bottom_style,
10561 : eCSSProperty_border_bottom_width,
10562 : eCSSProperty_border_left_color,
10563 : eCSSProperty_border_left_style,
10564 : eCSSProperty_border_left_width,
10565 : eCSSProperty_border_top_left_radius,
10566 : eCSSProperty_border_top_right_radius,
10567 : eCSSProperty_border_bottom_right_radius,
10568 : eCSSProperty_border_bottom_left_radius,
10569 : };
10570 :
10571 : static const nsCSSPropertyID paddingValues[] = {
10572 : eCSSProperty_padding_top,
10573 : eCSSProperty_padding_right,
10574 : eCSSProperty_padding_bottom,
10575 : eCSSProperty_padding_left,
10576 : };
10577 :
10578 : static const nsCSSPropertyID textShadowValues[] = {
10579 : eCSSProperty_text_shadow
10580 : };
10581 :
10582 : // Number of properties we care about
10583 0 : size_t nValues = 0;
10584 :
10585 : nsCSSValue* values[MOZ_ARRAY_LENGTH(backgroundValues) +
10586 : MOZ_ARRAY_LENGTH(borderValues) +
10587 : MOZ_ARRAY_LENGTH(paddingValues) +
10588 : MOZ_ARRAY_LENGTH(textShadowValues)];
10589 :
10590 : nsCSSPropertyID properties[MOZ_ARRAY_LENGTH(backgroundValues) +
10591 : MOZ_ARRAY_LENGTH(borderValues) +
10592 : MOZ_ARRAY_LENGTH(paddingValues) +
10593 : MOZ_ARRAY_LENGTH(textShadowValues)];
10594 :
10595 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
10596 0 : for (uint32_t i = 0, i_end = ArrayLength(backgroundValues);
10597 0 : i < i_end; ++i) {
10598 0 : properties[nValues] = backgroundValues[i];
10599 0 : values[nValues++] = ruleData.ValueFor(backgroundValues[i]);
10600 : }
10601 : }
10602 :
10603 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
10604 0 : for (uint32_t i = 0, i_end = ArrayLength(borderValues);
10605 0 : i < i_end; ++i) {
10606 0 : properties[nValues] = borderValues[i];
10607 0 : values[nValues++] = ruleData.ValueFor(borderValues[i]);
10608 : }
10609 : }
10610 :
10611 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
10612 0 : for (uint32_t i = 0, i_end = ArrayLength(paddingValues);
10613 0 : i < i_end; ++i) {
10614 0 : properties[nValues] = paddingValues[i];
10615 0 : values[nValues++] = ruleData.ValueFor(paddingValues[i]);
10616 : }
10617 : }
10618 :
10619 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_TEXT_SHADOW) {
10620 0 : for (uint32_t i = 0, i_end = ArrayLength(textShadowValues);
10621 0 : i < i_end; ++i) {
10622 0 : properties[nValues] = textShadowValues[i];
10623 0 : values[nValues++] = ruleData.ValueFor(textShadowValues[i]);
10624 : }
10625 : }
10626 :
10627 0 : GeckoStyleContext* styleContextRef = styleContext;
10628 :
10629 : // We need to be careful not to count styles covered up by user-important or
10630 : // UA-important declarations. But we do want to catch explicit inherit
10631 : // styling in those and check our parent style context to see whether we have
10632 : // user styling for those properties. Note that we don't care here about
10633 : // inheritance due to lack of a specified value, since all the properties we
10634 : // care about are reset properties.
10635 : bool haveExplicitUAInherit;
10636 0 : do {
10637 0 : haveExplicitUAInherit = false;
10638 0 : for (nsRuleNode* ruleNode = styleContextRef->RuleNode(); ruleNode;
10639 : ruleNode = ruleNode->GetParent()) {
10640 0 : nsIStyleRule *rule = ruleNode->GetRule();
10641 0 : if (rule) {
10642 0 : ruleData.mLevel = ruleNode->GetLevel();
10643 0 : ruleData.mIsImportantRule = ruleNode->IsImportantRule();
10644 :
10645 0 : rule->MapRuleInfoInto(&ruleData);
10646 :
10647 0 : if (ruleData.mLevel == SheetType::Agent ||
10648 0 : ruleData.mLevel == SheetType::User) {
10649 : // This is a rule whose effect we want to ignore, so if any of
10650 : // the properties we care about were set, set them to the dummy
10651 : // value that they'll never otherwise get.
10652 0 : for (uint32_t i = 0; i < nValues; ++i) {
10653 0 : nsCSSUnit unit = values[i]->GetUnit();
10654 0 : if (unit != eCSSUnit_Null &&
10655 0 : unit != eCSSUnit_Dummy &&
10656 : unit != eCSSUnit_DummyInherit) {
10657 0 : if (unit == eCSSUnit_Inherit ||
10658 0 : (i >= inheritedOffset && unit == eCSSUnit_Unset)) {
10659 0 : haveExplicitUAInherit = true;
10660 0 : values[i]->SetDummyInheritValue();
10661 : } else {
10662 0 : values[i]->SetDummyValue();
10663 : }
10664 : }
10665 0 : }
10666 : } else {
10667 : // If any of the values we care about was set by the above rule,
10668 : // we have author style.
10669 0 : for (uint32_t i = 0; i < nValues; ++i) {
10670 0 : if (values[i]->GetUnit() != eCSSUnit_Null &&
10671 0 : values[i]->GetUnit() != eCSSUnit_Dummy && // see above
10672 0 : values[i]->GetUnit() != eCSSUnit_DummyInherit) {
10673 : // If author colors are not allowed, only claim to have
10674 : // author-specified rules if we're looking at a non-color
10675 : // property or if we're looking at the background color and it's
10676 : // set to transparent. Anything else should get set to a dummy
10677 : // value instead.
10678 0 : if (aAuthorColorsAllowed ||
10679 0 : !nsCSSProps::PropHasFlags(properties[i],
10680 0 : CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED) ||
10681 0 : (properties[i] == eCSSProperty_background_color &&
10682 0 : !values[i]->IsNonTransparentColor())) {
10683 0 : return true;
10684 : }
10685 :
10686 0 : values[i]->SetDummyValue();
10687 : }
10688 : }
10689 : }
10690 : }
10691 : }
10692 :
10693 0 : if (haveExplicitUAInherit) {
10694 : // reset all the eCSSUnit_Null values to eCSSUnit_Dummy (since they're
10695 : // not styled by the author, or by anyone else), and then reset all the
10696 : // eCSSUnit_DummyInherit values to eCSSUnit_Null (so we will be able to
10697 : // detect them being styled by the author) and move up to our parent
10698 : // style context.
10699 0 : for (uint32_t i = 0; i < nValues; ++i)
10700 0 : if (values[i]->GetUnit() == eCSSUnit_Null)
10701 0 : values[i]->SetDummyValue();
10702 0 : for (uint32_t i = 0; i < nValues; ++i)
10703 0 : if (values[i]->GetUnit() == eCSSUnit_DummyInherit)
10704 0 : values[i]->Reset();
10705 0 : styleContextRef = styleContextRef->GetParent();
10706 : }
10707 0 : } while (haveExplicitUAInherit && styleContext);
10708 :
10709 0 : return false;
10710 : }
10711 :
10712 : /* static */ void
10713 8 : nsRuleNode::ComputePropertiesOverridingAnimation(
10714 : const nsTArray<nsCSSPropertyID>& aProperties,
10715 : GeckoStyleContext* aStyleContext,
10716 : nsCSSPropertyIDSet& aPropertiesOverridden)
10717 : {
10718 : /*
10719 : * Set up an nsRuleData with all the structs needed for all of the
10720 : * properties in aProperties.
10721 : */
10722 8 : uint32_t structBits = 0;
10723 8 : size_t nprops = 0;
10724 : size_t offsets[nsStyleStructID_Length];
10725 16 : for (size_t propIdx = 0, propEnd = aProperties.Length();
10726 16 : propIdx < propEnd; ++propIdx) {
10727 8 : nsCSSPropertyID prop = aProperties[propIdx];
10728 8 : nsStyleStructID sid = nsCSSProps::kSIDTable[prop];
10729 8 : uint32_t bit = nsCachedStyleData::GetBitForSID(sid);
10730 8 : if (!(structBits & bit)) {
10731 8 : structBits |= bit;
10732 8 : offsets[sid] = nprops;
10733 8 : nprops += nsCSSProps::PropertyCountInStruct(sid);
10734 : }
10735 : }
10736 :
10737 8 : void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
10738 16 : AutoCSSValueArray dataArray(dataStorage, nprops);
10739 :
10740 : // We're relying on the use of |aStyleContext| not mutating it!
10741 : nsRuleData ruleData(structBits, dataArray.get(),
10742 16 : aStyleContext->PresContext(), aStyleContext);
10743 200 : for (nsStyleStructID sid = nsStyleStructID(0);
10744 392 : sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) {
10745 192 : if (structBits & nsCachedStyleData::GetBitForSID(sid)) {
10746 8 : ruleData.mValueOffsets[sid] = offsets[sid];
10747 : }
10748 : }
10749 :
10750 : /*
10751 : * Actually walk up the rule tree until we're someplace less
10752 : * specific than animations.
10753 : */
10754 14 : for (nsRuleNode* ruleNode = aStyleContext->RuleNode(); ruleNode;
10755 : ruleNode = ruleNode->GetParent()) {
10756 14 : nsIStyleRule *rule = ruleNode->GetRule();
10757 14 : if (rule) {
10758 14 : ruleData.mLevel = ruleNode->GetLevel();
10759 14 : ruleData.mIsImportantRule = ruleNode->IsImportantRule();
10760 :
10761 : // Transitions are the only non-!important level overriding
10762 : // animations in the cascade ordering. They also don't actually
10763 : // override animations, since transitions are suppressed when both
10764 : // are present. And since we might not have called
10765 : // UpdateCascadeResults (which updates when they are suppressed
10766 : // due to the presence of animations for the same element and
10767 : // property) for transitions yet (which will make their
10768 : // MapRuleInfoInto skip the properties that are currently
10769 : // animating), we should skip them explicitly.
10770 14 : if (ruleData.mLevel == SheetType::Transition) {
10771 6 : continue;
10772 : }
10773 :
10774 8 : if (!ruleData.mIsImportantRule) {
10775 : // We're now equal to or less than the animation level; stop.
10776 8 : break;
10777 : }
10778 :
10779 0 : rule->MapRuleInfoInto(&ruleData);
10780 : }
10781 : }
10782 :
10783 : /*
10784 : * Fill in which properties were overridden.
10785 : */
10786 16 : for (size_t propIdx = 0, propEnd = aProperties.Length();
10787 16 : propIdx < propEnd; ++propIdx) {
10788 8 : nsCSSPropertyID prop = aProperties[propIdx];
10789 8 : if (ruleData.ValueFor(prop)->GetUnit() != eCSSUnit_Null) {
10790 0 : aPropertiesOverridden.AddProperty(prop);
10791 : }
10792 : }
10793 8 : }
10794 :
10795 : /* static */
10796 : bool
10797 152 : nsRuleNode::ComputeColor(const nsCSSValue& aValue, nsPresContext* aPresContext,
10798 : nsStyleContext* aStyleContext, nscolor& aResult)
10799 : {
10800 152 : MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Inherit,
10801 : "aValue shouldn't have eCSSUnit_Inherit");
10802 152 : MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Initial,
10803 : "aValue shouldn't have eCSSUnit_Initial");
10804 152 : MOZ_ASSERT(aValue.GetUnit() != eCSSUnit_Unset,
10805 : "aValue shouldn't have eCSSUnit_Unset");
10806 :
10807 152 : RuleNodeCacheConditions conditions;
10808 : bool ok = SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aStyleContext,
10809 152 : aResult, conditions);
10810 152 : MOZ_ASSERT(ok || !(aPresContext && aStyleContext));
10811 152 : return ok;
10812 : }
10813 :
10814 : /* static */ bool
10815 298 : nsRuleNode::ParentHasPseudoElementData(GeckoStyleContext* aContext)
10816 : {
10817 298 : GeckoStyleContext* parent = aContext->GetParent();
10818 298 : return parent && parent->HasPseudoElementData();
10819 : }
10820 :
10821 : /* static */ void
10822 130 : nsRuleNode::StoreStyleOnContext(GeckoStyleContext* aContext,
10823 : nsStyleStructID aSID,
10824 : void* aStruct)
10825 : {
10826 130 : aContext->AddStyleBit(nsCachedStyleData::GetBitForSID(aSID));
10827 130 : aContext->SetStyle(aSID, aStruct);
10828 130 : }
10829 :
10830 : #ifdef DEBUG
10831 : bool
10832 286889 : nsRuleNode::ContextHasCachedData(GeckoStyleContext* aContext,
10833 : nsStyleStructID aSID)
10834 : {
10835 286889 : return !!aContext->GetCachedStyleData(aSID);
10836 : }
10837 : #endif
|