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