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 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Original Author: David W. Hyatt (hyatt@netscape.com)
25 : * Daniel Glazman <glazman@netscape.com>
26 : * Roger B. Sidje <rbs@maths.uq.edu.au>
27 : * Mats Palmgren <matspal@gmail.com>
28 : * L. David Baron <dbaron@dbaron.org>
29 : * Christian Biesinger <cbiesinger@web.de>
30 : * Michael Ventnor <m.ventnor@gmail.com>
31 : * Keith Rarick <kr@xph.us>
32 : * Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
33 : *
34 : * Alternatively, the contents of this file may be used under the terms of
35 : * either of the GNU General Public License Version 2 or later (the "GPL"),
36 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
37 : * in which case the provisions of the GPL or the LGPL are applicable instead
38 : * of those above. If you wish to allow use of your version of this file only
39 : * under the terms of either the GPL or the LGPL, and not to allow others to
40 : * use your version of this file under the terms of the MPL, indicate your
41 : * decision by deleting the provisions above and replace them with the notice
42 : * and other provisions required by the GPL or the LGPL. If you do not delete
43 : * the provisions above, a recipient may use your version of this file under
44 : * the terms of any one of the MPL, the GPL or the LGPL.
45 : *
46 : * ***** END LICENSE BLOCK ***** */
47 :
48 : /*
49 : * a node in the lexicographic tree of rules that match an element,
50 : * responsible for converting the rules' information into computed style
51 : */
52 :
53 : #include "nsRuleNode.h"
54 : #include "nscore.h"
55 : #include "nsIServiceManager.h"
56 : #include "nsIWidget.h"
57 : #include "mozilla/LookAndFeel.h"
58 : #include "nsIPresShell.h"
59 : #include "nsFontMetrics.h"
60 : #include "gfxFont.h"
61 : #include "nsStyleUtil.h"
62 : #include "nsCSSPseudoElements.h"
63 : #include "nsThemeConstants.h"
64 : #include "nsITheme.h"
65 : #include "pldhash.h"
66 : #include "nsStyleContext.h"
67 : #include "nsStyleSet.h"
68 : #include "nsSize.h"
69 : #include "imgIRequest.h"
70 : #include "nsRuleData.h"
71 : #include "nsIStyleRule.h"
72 : #include "nsBidiUtils.h"
73 : #include "nsUnicharUtils.h"
74 : #include "nsStyleStructInlines.h"
75 : #include "nsStyleTransformMatrix.h"
76 : #include "nsCSSKeywords.h"
77 : #include "nsCSSProps.h"
78 : #include "nsTArray.h"
79 : #include "nsContentUtils.h"
80 : #include "mozilla/dom/Element.h"
81 : #include "CSSCalc.h"
82 : #include "nsPrintfCString.h"
83 : #include "mozilla/Util.h"
84 :
85 : #if defined(_MSC_VER) || defined(__MINGW32__)
86 : #include <malloc.h>
87 : #ifdef _MSC_VER
88 : #define alloca _alloca
89 : #endif
90 : #endif
91 : #ifdef SOLARIS
92 : #include <alloca.h>
93 : #endif
94 :
95 : using namespace mozilla;
96 : using namespace mozilla::dom;
97 :
98 : #define NS_SET_IMAGE_REQUEST(method_, context_, request_) \
99 : if ((context_)->PresContext()->IsDynamic()) { \
100 : method_(request_); \
101 : } else { \
102 : nsCOMPtr<imgIRequest> req = nsContentUtils::GetStaticRequest(request_); \
103 : method_(req); \
104 : }
105 :
106 : /*
107 : * For storage of an |nsRuleNode|'s children in a PLDHashTable.
108 : */
109 :
110 : struct ChildrenHashEntry : public PLDHashEntryHdr {
111 : // key is |mRuleNode->GetKey()|
112 : nsRuleNode *mRuleNode;
113 : };
114 :
115 : /* static */ PLDHashNumber
116 0 : nsRuleNode::ChildrenHashHashKey(PLDHashTable *aTable, const void *aKey)
117 : {
118 : const nsRuleNode::Key *key =
119 0 : static_cast<const nsRuleNode::Key*>(aKey);
120 : // Disagreement on importance and level for the same rule is extremely
121 : // rare, so hash just on the rule.
122 0 : return PL_DHashVoidPtrKeyStub(aTable, key->mRule);
123 : }
124 :
125 : /* static */ bool
126 0 : nsRuleNode::ChildrenHashMatchEntry(PLDHashTable *aTable,
127 : const PLDHashEntryHdr *aHdr,
128 : const void *aKey)
129 : {
130 : const ChildrenHashEntry *entry =
131 0 : static_cast<const ChildrenHashEntry*>(aHdr);
132 : const nsRuleNode::Key *key =
133 0 : static_cast<const nsRuleNode::Key*>(aKey);
134 0 : return entry->mRuleNode->GetKey() == *key;
135 : }
136 :
137 : /* static */ PLDHashTableOps
138 : nsRuleNode::ChildrenHashOps = {
139 : // It's probably better to allocate the table itself using malloc and
140 : // free rather than the pres shell's arena because the table doesn't
141 : // grow very often and the pres shell's arena doesn't recycle very
142 : // large size allocations.
143 : PL_DHashAllocTable,
144 : PL_DHashFreeTable,
145 : ChildrenHashHashKey,
146 : ChildrenHashMatchEntry,
147 : PL_DHashMoveEntryStub,
148 : PL_DHashClearEntryStub,
149 : PL_DHashFinalizeStub,
150 : NULL
151 : };
152 :
153 :
154 : // EnsureBlockDisplay:
155 : // - if the display value (argument) is not a block-type
156 : // then we set it to a valid block display value
157 : // - For enforcing the floated/positioned element CSS2 rules
158 0 : static void EnsureBlockDisplay(PRUint8& display)
159 : {
160 : // see if the display value is already a block
161 0 : switch (display) {
162 : case NS_STYLE_DISPLAY_NONE :
163 : // never change display:none *ever*
164 : case NS_STYLE_DISPLAY_TABLE :
165 : case NS_STYLE_DISPLAY_BLOCK :
166 : case NS_STYLE_DISPLAY_LIST_ITEM :
167 : // do not muck with these at all - already blocks
168 : // This is equivalent to nsStyleDisplay::IsBlockOutside. (XXX Maybe we
169 : // should just call that?)
170 : // This needs to match the check done in
171 : // nsCSSFrameConstructor::FindMathMLData for <math>.
172 0 : break;
173 :
174 : case NS_STYLE_DISPLAY_INLINE_TABLE :
175 : // make inline tables into tables
176 0 : display = NS_STYLE_DISPLAY_TABLE;
177 0 : break;
178 :
179 : default :
180 : // make it a block
181 0 : display = NS_STYLE_DISPLAY_BLOCK;
182 : }
183 0 : }
184 :
185 : static nscoord CalcLengthWith(const nsCSSValue& aValue,
186 : nscoord aFontSize,
187 : const nsStyleFont* aStyleFont,
188 : nsStyleContext* aStyleContext,
189 : nsPresContext* aPresContext,
190 : bool aUseProvidedRootEmSize,
191 : bool aUseUserFontSet,
192 : bool& aCanStoreInRuleTree);
193 :
194 : struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
195 : public css::NumbersAlreadyNormalizedOps
196 : {
197 : // All of the parameters to CalcLengthWith except aValue.
198 : const nscoord mFontSize;
199 : const nsStyleFont* const mStyleFont;
200 : nsStyleContext* const mStyleContext;
201 : nsPresContext* const mPresContext;
202 : const bool mUseProvidedRootEmSize;
203 : const bool mUseUserFontSet;
204 : bool& mCanStoreInRuleTree;
205 :
206 0 : CalcLengthCalcOps(nscoord aFontSize, const nsStyleFont* aStyleFont,
207 : nsStyleContext* aStyleContext, nsPresContext* aPresContext,
208 : bool aUseProvidedRootEmSize, bool aUseUserFontSet,
209 : bool& aCanStoreInRuleTree)
210 : : mFontSize(aFontSize),
211 : mStyleFont(aStyleFont),
212 : mStyleContext(aStyleContext),
213 : mPresContext(aPresContext),
214 : mUseProvidedRootEmSize(aUseProvidedRootEmSize),
215 : mUseUserFontSet(aUseUserFontSet),
216 0 : mCanStoreInRuleTree(aCanStoreInRuleTree)
217 : {
218 0 : }
219 :
220 0 : result_type ComputeLeafValue(const nsCSSValue& aValue)
221 : {
222 : return CalcLengthWith(aValue, mFontSize, mStyleFont,
223 : mStyleContext, mPresContext, mUseProvidedRootEmSize,
224 0 : mUseUserFontSet, mCanStoreInRuleTree);
225 : }
226 : };
227 :
228 0 : static inline nscoord ScaleCoord(const nsCSSValue &aValue, float factor)
229 : {
230 0 : return NSToCoordRoundWithClamp(aValue.GetFloatValue() * factor);
231 : }
232 :
233 : already_AddRefed<nsFontMetrics>
234 0 : GetMetricsFor(nsPresContext* aPresContext,
235 : nsStyleContext* aStyleContext,
236 : const nsStyleFont* aStyleFont,
237 : nscoord aFontSize, // overrides value from aStyleFont
238 : bool aUseUserFontSet)
239 : {
240 0 : nsFont font = aStyleFont->mFont;
241 0 : font.size = aFontSize;
242 0 : gfxUserFontSet *fs = nsnull;
243 0 : if (aUseUserFontSet) {
244 0 : fs = aPresContext->GetUserFontSet();
245 : }
246 0 : nsRefPtr<nsFontMetrics> fm;
247 : aPresContext->DeviceContext()->GetMetricsFor(font,
248 : aStyleFont->mLanguage,
249 0 : fs, *getter_AddRefs(fm));
250 0 : return fm.forget();
251 : }
252 :
253 0 : static nscoord CalcLengthWith(const nsCSSValue& aValue,
254 : nscoord aFontSize,
255 : const nsStyleFont* aStyleFont,
256 : nsStyleContext* aStyleContext,
257 : nsPresContext* aPresContext,
258 : bool aUseProvidedRootEmSize,
259 : // aUseUserFontSet should always be true
260 : // except when called from
261 : // CalcLengthWithInitialFont.
262 : bool aUseUserFontSet,
263 : bool& aCanStoreInRuleTree)
264 : {
265 0 : NS_ASSERTION(aValue.IsLengthUnit() || aValue.IsCalcUnit(),
266 : "not a length or calc unit");
267 0 : NS_ASSERTION(aStyleFont || aStyleContext,
268 : "Must have style data");
269 0 : NS_ASSERTION(!aStyleFont || !aStyleContext,
270 : "Duplicate sources of data");
271 0 : NS_ASSERTION(aPresContext, "Must have prescontext");
272 :
273 0 : if (aValue.IsFixedLengthUnit()) {
274 0 : return aValue.GetFixedLength(aPresContext);
275 : }
276 0 : if (aValue.IsPixelLengthUnit()) {
277 0 : return aValue.GetPixelLength();
278 : }
279 : // Common code for all units other than pixel-based units and fixed-length
280 : // units:
281 0 : aCanStoreInRuleTree = false;
282 : const nsStyleFont *styleFont =
283 0 : aStyleFont ? aStyleFont : aStyleContext->GetStyleFont();
284 0 : if (aFontSize == -1) {
285 : // XXX Should this be styleFont->mSize instead to avoid taking minfontsize
286 : // prefs into account?
287 0 : aFontSize = styleFont->mFont.size;
288 : }
289 0 : switch (aValue.GetUnit()) {
290 : case eCSSUnit_RootEM: {
291 : nscoord rootFontSize;
292 :
293 0 : if (aUseProvidedRootEmSize) {
294 : // We should use the provided aFontSize as the reference length to
295 : // scale. This only happens when we are calculating font-size or
296 : // an equivalent (scriptminsize or CalcLengthWithInitialFont) on
297 : // the root element, in which case aFontSize is already the
298 : // value we want.
299 0 : rootFontSize = aFontSize;
300 0 : } else if (aStyleContext && !aStyleContext->GetParent()) {
301 : // This is the root element (XXX we don't really know this, but
302 : // nsRuleNode::SetFont makes the same assumption!), so we should
303 : // use GetStyleFont on this context to get the root element's
304 : // font size.
305 0 : rootFontSize = styleFont->mFont.size;
306 : } else {
307 : // This is not the root element or we are calculating something other
308 : // than font size, so rem is relative to the root element's font size.
309 0 : nsRefPtr<nsStyleContext> rootStyle;
310 0 : const nsStyleFont *rootStyleFont = styleFont;
311 0 : Element* docElement = aPresContext->Document()->GetRootElement();
312 :
313 0 : if (docElement) {
314 : rootStyle = aPresContext->StyleSet()->ResolveStyleFor(docElement,
315 0 : nsnull);
316 0 : if (rootStyle) {
317 0 : rootStyleFont = rootStyle->GetStyleFont();
318 : }
319 : }
320 :
321 0 : rootFontSize = rootStyleFont->mFont.size;
322 : }
323 :
324 0 : return ScaleCoord(aValue, float(rootFontSize));
325 : }
326 : case eCSSUnit_EM: {
327 0 : return ScaleCoord(aValue, float(aFontSize));
328 : // XXX scale against font metrics height instead?
329 : }
330 : case eCSSUnit_XHeight: {
331 : nsRefPtr<nsFontMetrics> fm =
332 : GetMetricsFor(aPresContext, aStyleContext, styleFont,
333 0 : aFontSize, aUseUserFontSet);
334 0 : return ScaleCoord(aValue, float(fm->XHeight()));
335 : }
336 : case eCSSUnit_Char: {
337 : nsRefPtr<nsFontMetrics> fm =
338 : GetMetricsFor(aPresContext, aStyleContext, styleFont,
339 0 : aFontSize, aUseUserFontSet);
340 0 : gfxFloat zeroWidth = (fm->GetThebesFontGroup()->GetFontAt(0)
341 0 : ->GetMetrics().zeroOrAveCharWidth);
342 :
343 0 : return ScaleCoord(aValue, ceil(aPresContext->AppUnitsPerDevPixel() *
344 0 : zeroWidth));
345 : }
346 : // For properties for which lengths are the *only* units accepted in
347 : // calc(), we can handle calc() here and just compute a final
348 : // result. We ensure that we don't get to this code for other
349 : // properties by not calling CalcLength in those cases: SetCoord
350 : // only calls CalcLength for a calc when it is appropriate to do so.
351 : case eCSSUnit_Calc:
352 : case eCSSUnit_Calc_Plus:
353 : case eCSSUnit_Calc_Minus:
354 : case eCSSUnit_Calc_Times_L:
355 : case eCSSUnit_Calc_Times_R:
356 : case eCSSUnit_Calc_Divided: {
357 : CalcLengthCalcOps ops(aFontSize, aStyleFont,
358 : aStyleContext, aPresContext,
359 : aUseProvidedRootEmSize, aUseUserFontSet,
360 0 : aCanStoreInRuleTree);
361 0 : return css::ComputeCalc(aValue, ops);
362 : }
363 : default:
364 0 : NS_NOTREACHED("unexpected unit");
365 : break;
366 : }
367 0 : return 0;
368 : }
369 :
370 : /* static */ nscoord
371 0 : nsRuleNode::CalcLength(const nsCSSValue& aValue,
372 : nsStyleContext* aStyleContext,
373 : nsPresContext* aPresContext,
374 : bool& aCanStoreInRuleTree)
375 : {
376 0 : NS_ASSERTION(aStyleContext, "Must have style data");
377 :
378 : return CalcLengthWith(aValue, -1, nsnull,
379 : aStyleContext, aPresContext,
380 0 : false, true, aCanStoreInRuleTree);
381 : }
382 :
383 : /* Inline helper function to redirect requests to CalcLength. */
384 0 : static inline nscoord CalcLength(const nsCSSValue& aValue,
385 : nsStyleContext* aStyleContext,
386 : nsPresContext* aPresContext,
387 : bool& aCanStoreInRuleTree)
388 : {
389 : return nsRuleNode::CalcLength(aValue, aStyleContext,
390 0 : aPresContext, aCanStoreInRuleTree);
391 : }
392 :
393 : /* static */ nscoord
394 0 : nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
395 : const nsCSSValue& aValue)
396 : {
397 0 : nsStyleFont defaultFont(aPresContext); // FIXME: best language?
398 : bool canStoreInRuleTree;
399 : return CalcLengthWith(aValue, -1, &defaultFont,
400 : nsnull, aPresContext,
401 0 : true, false, canStoreInRuleTree);
402 : }
403 :
404 : struct LengthPercentPairCalcOps : public css::NumbersAlreadyNormalizedOps
405 : {
406 : typedef nsRuleNode::ComputedCalc result_type;
407 :
408 0 : LengthPercentPairCalcOps(nsStyleContext* aContext,
409 : nsPresContext* aPresContext,
410 : bool& aCanStoreInRuleTree)
411 : : mContext(aContext),
412 : mPresContext(aPresContext),
413 : mCanStoreInRuleTree(aCanStoreInRuleTree),
414 0 : mHasPercent(false) {}
415 :
416 : nsStyleContext* mContext;
417 : nsPresContext* mPresContext;
418 : bool& mCanStoreInRuleTree;
419 : bool mHasPercent;
420 :
421 0 : result_type ComputeLeafValue(const nsCSSValue& aValue)
422 : {
423 0 : if (aValue.GetUnit() == eCSSUnit_Percent) {
424 0 : mHasPercent = true;
425 0 : return result_type(0, aValue.GetPercentValue());
426 : }
427 : return result_type(CalcLength(aValue, mContext, mPresContext,
428 : mCanStoreInRuleTree),
429 0 : 0.0f);
430 : }
431 :
432 : result_type
433 0 : MergeAdditive(nsCSSUnit aCalcFunction,
434 : result_type aValue1, result_type aValue2)
435 : {
436 0 : if (aCalcFunction == eCSSUnit_Calc_Plus) {
437 : return result_type(NSCoordSaturatingAdd(aValue1.mLength,
438 : aValue2.mLength),
439 0 : aValue1.mPercent + aValue2.mPercent);
440 : }
441 0 : NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Minus,
442 : "min() and max() are not allowed in calc() on "
443 : "transform");
444 : return result_type(NSCoordSaturatingSubtract(aValue1.mLength,
445 : aValue2.mLength, 0),
446 0 : aValue1.mPercent - aValue2.mPercent);
447 : }
448 :
449 : result_type
450 0 : MergeMultiplicativeL(nsCSSUnit aCalcFunction,
451 : float aValue1, result_type aValue2)
452 : {
453 0 : NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_L,
454 : "unexpected unit");
455 : return result_type(NSCoordSaturatingMultiply(aValue2.mLength, aValue1),
456 0 : aValue1 * aValue2.mPercent);
457 : }
458 :
459 : result_type
460 0 : MergeMultiplicativeR(nsCSSUnit aCalcFunction,
461 : result_type aValue1, float aValue2)
462 : {
463 0 : NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_R ||
464 : aCalcFunction == eCSSUnit_Calc_Divided,
465 : "unexpected unit");
466 0 : if (aCalcFunction == eCSSUnit_Calc_Divided) {
467 0 : aValue2 = 1.0f / aValue2;
468 : }
469 : return result_type(NSCoordSaturatingMultiply(aValue1.mLength, aValue2),
470 0 : aValue1.mPercent * aValue2);
471 : }
472 :
473 : };
474 :
475 : static void
476 0 : SpecifiedCalcToComputedCalc(const nsCSSValue& aValue, nsStyleCoord& aCoord,
477 : nsStyleContext* aStyleContext,
478 : bool& aCanStoreInRuleTree)
479 : {
480 : LengthPercentPairCalcOps ops(aStyleContext, aStyleContext->PresContext(),
481 0 : aCanStoreInRuleTree);
482 0 : nsRuleNode::ComputedCalc vals = ComputeCalc(aValue, ops);
483 :
484 : nsStyleCoord::Calc *calcObj =
485 0 : new (aStyleContext->Alloc(sizeof(nsStyleCoord::Calc))) nsStyleCoord::Calc;
486 : // Because we use aStyleContext->Alloc(), we have to store the result
487 : // on the style context and not in the rule tree.
488 0 : aCanStoreInRuleTree = false;
489 :
490 0 : calcObj->mLength = vals.mLength;
491 0 : calcObj->mPercent = vals.mPercent;
492 0 : calcObj->mHasPercent = ops.mHasPercent;
493 :
494 0 : aCoord.SetCalcValue(calcObj);
495 0 : }
496 :
497 : /* static */ nsRuleNode::ComputedCalc
498 0 : nsRuleNode::SpecifiedCalcToComputedCalc(const nsCSSValue& aValue,
499 : nsStyleContext* aStyleContext,
500 : nsPresContext* aPresContext,
501 : bool& aCanStoreInRuleTree)
502 : {
503 : LengthPercentPairCalcOps ops(aStyleContext, aPresContext,
504 0 : aCanStoreInRuleTree);
505 0 : return ComputeCalc(aValue, ops);
506 : }
507 :
508 : // This is our public API for handling calc() expressions that involve
509 : // percentages.
510 : /* static */ nscoord
511 0 : nsRuleNode::ComputeComputedCalc(const nsStyleCoord& aValue,
512 : nscoord aPercentageBasis)
513 : {
514 0 : nsStyleCoord::Calc *calc = aValue.GetCalcValue();
515 : return calc->mLength +
516 0 : NSToCoordFloorClamped(aPercentageBasis * calc->mPercent);
517 : }
518 :
519 : /* static */ nscoord
520 0 : nsRuleNode::ComputeCoordPercentCalc(const nsStyleCoord& aCoord,
521 : nscoord aPercentageBasis)
522 : {
523 0 : switch (aCoord.GetUnit()) {
524 : case eStyleUnit_Coord:
525 0 : return aCoord.GetCoordValue();
526 : case eStyleUnit_Percent:
527 0 : return NSToCoordFloorClamped(aPercentageBasis * aCoord.GetPercentValue());
528 : case eStyleUnit_Calc:
529 0 : return ComputeComputedCalc(aCoord, aPercentageBasis);
530 : default:
531 0 : NS_ABORT_IF_FALSE(false, "unexpected unit");
532 0 : return 0;
533 : }
534 : }
535 :
536 : /* Given an enumerated value that represents a box position, converts it to
537 : * a float representing the percentage of the box it corresponds to. For
538 : * example, "center" becomes 0.5f.
539 : *
540 : * @param aEnumValue The enumerated value.
541 : * @return The float percent it corresponds to.
542 : */
543 : static float
544 0 : GetFloatFromBoxPosition(PRInt32 aEnumValue)
545 : {
546 0 : switch (aEnumValue) {
547 : case NS_STYLE_BG_POSITION_LEFT:
548 : case NS_STYLE_BG_POSITION_TOP:
549 0 : return 0.0f;
550 : case NS_STYLE_BG_POSITION_RIGHT:
551 : case NS_STYLE_BG_POSITION_BOTTOM:
552 0 : return 1.0f;
553 : default:
554 0 : NS_NOTREACHED("unexpected value");
555 : // fall through
556 : case NS_STYLE_BG_POSITION_CENTER:
557 0 : return 0.5f;
558 : }
559 : }
560 :
561 : #define SETCOORD_NORMAL 0x01 // N
562 : #define SETCOORD_AUTO 0x02 // A
563 : #define SETCOORD_INHERIT 0x04 // H
564 : #define SETCOORD_PERCENT 0x08 // P
565 : #define SETCOORD_FACTOR 0x10 // F
566 : #define SETCOORD_LENGTH 0x20 // L
567 : #define SETCOORD_INTEGER 0x40 // I
568 : #define SETCOORD_ENUMERATED 0x80 // E
569 : #define SETCOORD_NONE 0x100 // O
570 : #define SETCOORD_INITIAL_ZERO 0x200
571 : #define SETCOORD_INITIAL_AUTO 0x400
572 : #define SETCOORD_INITIAL_NONE 0x800
573 : #define SETCOORD_INITIAL_NORMAL 0x1000
574 : #define SETCOORD_INITIAL_HALF 0x2000
575 : #define SETCOORD_INITIAL_HUNDRED_PCT 0x00004000
576 : #define SETCOORD_INITIAL_FACTOR_ONE 0x00008000
577 : #define SETCOORD_INITIAL_FACTOR_ZERO 0x00010000
578 : #define SETCOORD_CALC_LENGTH_ONLY 0x00020000
579 : #define SETCOORD_CALC_CLAMP_NONNEGATIVE 0x00040000 // modifier for CALC_LENGTH_ONLY
580 : #define SETCOORD_STORE_CALC 0x00080000
581 : #define SETCOORD_BOX_POSITION 0x00100000 // exclusive with _ENUMERATED
582 :
583 : #define SETCOORD_LP (SETCOORD_LENGTH | SETCOORD_PERCENT)
584 : #define SETCOORD_LH (SETCOORD_LENGTH | SETCOORD_INHERIT)
585 : #define SETCOORD_AH (SETCOORD_AUTO | SETCOORD_INHERIT)
586 : #define SETCOORD_LAH (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT)
587 : #define SETCOORD_LPH (SETCOORD_LP | SETCOORD_INHERIT)
588 : #define SETCOORD_LPAH (SETCOORD_LP | SETCOORD_AH)
589 : #define SETCOORD_LPEH (SETCOORD_LP | SETCOORD_ENUMERATED | SETCOORD_INHERIT)
590 : #define SETCOORD_LPAEH (SETCOORD_LPAH | SETCOORD_ENUMERATED)
591 : #define SETCOORD_LPO (SETCOORD_LP | SETCOORD_NONE)
592 : #define SETCOORD_LPOH (SETCOORD_LPH | SETCOORD_NONE)
593 : #define SETCOORD_LPOEH (SETCOORD_LPOH | SETCOORD_ENUMERATED)
594 : #define SETCOORD_LE (SETCOORD_LENGTH | SETCOORD_ENUMERATED)
595 : #define SETCOORD_LEH (SETCOORD_LE | SETCOORD_INHERIT)
596 : #define SETCOORD_IA (SETCOORD_INTEGER | SETCOORD_AUTO)
597 : #define SETCOORD_LAE (SETCOORD_LENGTH | SETCOORD_AUTO | SETCOORD_ENUMERATED)
598 :
599 : // changes aCoord iff it returns true
600 0 : static bool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
601 : const nsStyleCoord& aParentCoord,
602 : PRInt32 aMask, nsStyleContext* aStyleContext,
603 : nsPresContext* aPresContext,
604 : bool& aCanStoreInRuleTree)
605 : {
606 0 : bool result = true;
607 0 : if (aValue.GetUnit() == eCSSUnit_Null) {
608 0 : result = false;
609 : }
610 0 : else if ((((aMask & SETCOORD_LENGTH) != 0) &&
611 0 : aValue.IsLengthUnit()) ||
612 : (((aMask & SETCOORD_CALC_LENGTH_ONLY) != 0) &&
613 0 : aValue.IsCalcUnit())) {
614 : nscoord len = CalcLength(aValue, aStyleContext, aPresContext,
615 0 : aCanStoreInRuleTree);
616 0 : if ((aMask & SETCOORD_CALC_CLAMP_NONNEGATIVE) && len < 0) {
617 0 : NS_ASSERTION(aValue.IsCalcUnit(),
618 : "parser should have ensured no nonnegative lengths");
619 0 : len = 0;
620 : }
621 0 : aCoord.SetCoordValue(len);
622 : }
623 0 : else if (((aMask & SETCOORD_PERCENT) != 0) &&
624 0 : (aValue.GetUnit() == eCSSUnit_Percent)) {
625 0 : aCoord.SetPercentValue(aValue.GetPercentValue());
626 : }
627 0 : else if (((aMask & SETCOORD_INTEGER) != 0) &&
628 0 : (aValue.GetUnit() == eCSSUnit_Integer)) {
629 0 : aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Integer);
630 : }
631 0 : else if (((aMask & SETCOORD_ENUMERATED) != 0) &&
632 0 : (aValue.GetUnit() == eCSSUnit_Enumerated)) {
633 0 : aCoord.SetIntValue(aValue.GetIntValue(), eStyleUnit_Enumerated);
634 : }
635 0 : else if (((aMask & SETCOORD_BOX_POSITION) != 0) &&
636 0 : (aValue.GetUnit() == eCSSUnit_Enumerated)) {
637 0 : aCoord.SetPercentValue(GetFloatFromBoxPosition(aValue.GetIntValue()));
638 : }
639 0 : else if (((aMask & SETCOORD_AUTO) != 0) &&
640 0 : (aValue.GetUnit() == eCSSUnit_Auto)) {
641 0 : aCoord.SetAutoValue();
642 : }
643 0 : else if (((aMask & SETCOORD_INHERIT) != 0) &&
644 0 : (aValue.GetUnit() == eCSSUnit_Inherit)) {
645 0 : aCoord = aParentCoord; // just inherit value from parent
646 0 : aCanStoreInRuleTree = false;
647 : }
648 0 : else if (((aMask & SETCOORD_NORMAL) != 0) &&
649 0 : (aValue.GetUnit() == eCSSUnit_Normal)) {
650 0 : aCoord.SetNormalValue();
651 : }
652 0 : else if (((aMask & SETCOORD_NONE) != 0) &&
653 0 : (aValue.GetUnit() == eCSSUnit_None)) {
654 0 : aCoord.SetNoneValue();
655 : }
656 0 : else if (((aMask & SETCOORD_FACTOR) != 0) &&
657 0 : (aValue.GetUnit() == eCSSUnit_Number)) {
658 0 : aCoord.SetFactorValue(aValue.GetFloatValue());
659 : }
660 0 : else if (((aMask & SETCOORD_STORE_CALC) != 0) &&
661 0 : (aValue.IsCalcUnit())) {
662 : SpecifiedCalcToComputedCalc(aValue, aCoord, aStyleContext,
663 0 : aCanStoreInRuleTree);
664 : }
665 0 : else if (aValue.GetUnit() == eCSSUnit_Initial) {
666 0 : if ((aMask & SETCOORD_INITIAL_AUTO) != 0) {
667 0 : aCoord.SetAutoValue();
668 : }
669 0 : else if ((aMask & SETCOORD_INITIAL_ZERO) != 0) {
670 0 : aCoord.SetCoordValue(0);
671 : }
672 0 : else if ((aMask & SETCOORD_INITIAL_FACTOR_ZERO) != 0) {
673 0 : aCoord.SetFactorValue(0.0f);
674 : }
675 0 : else if ((aMask & SETCOORD_INITIAL_NONE) != 0) {
676 0 : aCoord.SetNoneValue();
677 : }
678 0 : else if ((aMask & SETCOORD_INITIAL_NORMAL) != 0) {
679 0 : aCoord.SetNormalValue();
680 : }
681 0 : else if ((aMask & SETCOORD_INITIAL_HALF) != 0) {
682 0 : aCoord.SetPercentValue(0.5f);
683 : }
684 0 : else if ((aMask & SETCOORD_INITIAL_HUNDRED_PCT) != 0) {
685 0 : aCoord.SetPercentValue(1.0f);
686 : }
687 0 : else if ((aMask & SETCOORD_INITIAL_FACTOR_ONE) != 0) {
688 0 : aCoord.SetFactorValue(1.0f);
689 : }
690 : else {
691 0 : result = false; // didn't set anything
692 : }
693 : }
694 : else {
695 0 : result = false; // didn't set anything
696 : }
697 0 : return result;
698 : }
699 :
700 : // This inline function offers a shortcut for SetCoord() by refusing to accept
701 : // SETCOORD_LENGTH and SETCOORD_INHERIT masks.
702 0 : static inline bool SetAbsCoord(const nsCSSValue& aValue,
703 : nsStyleCoord& aCoord,
704 : PRInt32 aMask)
705 : {
706 0 : NS_ABORT_IF_FALSE((aMask & SETCOORD_LH) == 0,
707 : "does not handle SETCOORD_LENGTH and SETCOORD_INHERIT");
708 :
709 : // The values of the following variables will never be used; so it does not
710 : // matter what to set.
711 0 : const nsStyleCoord dummyParentCoord;
712 0 : nsStyleContext* dummyStyleContext = nsnull;
713 0 : nsPresContext* dummyPresContext = nsnull;
714 0 : bool dummyCanStoreInRuleTree = true;
715 :
716 : bool rv = SetCoord(aValue, aCoord, dummyParentCoord, aMask,
717 : dummyStyleContext, dummyPresContext,
718 0 : dummyCanStoreInRuleTree);
719 0 : NS_ABORT_IF_FALSE(dummyCanStoreInRuleTree,
720 : "SetCoord() should not modify dummyCanStoreInRuleTree.");
721 :
722 0 : return rv;
723 : }
724 :
725 : /* Given a specified value that might be a pair value, call SetCoord twice,
726 : * either using each member of the pair, or using the unpaired value twice.
727 : */
728 : static bool
729 0 : SetPairCoords(const nsCSSValue& aValue,
730 : nsStyleCoord& aCoordX, nsStyleCoord& aCoordY,
731 : const nsStyleCoord& aParentX, const nsStyleCoord& aParentY,
732 : PRInt32 aMask, nsStyleContext* aStyleContext,
733 : nsPresContext* aPresContext, bool& aCanStoreInRuleTree)
734 : {
735 : const nsCSSValue& valX =
736 0 : aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mXValue : aValue;
737 : const nsCSSValue& valY =
738 0 : aValue.GetUnit() == eCSSUnit_Pair ? aValue.GetPairValue().mYValue : aValue;
739 :
740 : bool cX = SetCoord(valX, aCoordX, aParentX, aMask, aStyleContext,
741 0 : aPresContext, aCanStoreInRuleTree);
742 : mozilla::DebugOnly<bool> cY = SetCoord(valY, aCoordY, aParentY, aMask,
743 0 : aStyleContext, aPresContext, aCanStoreInRuleTree);
744 0 : NS_ABORT_IF_FALSE(cX == cY, "changed one but not the other");
745 0 : return cX;
746 : }
747 :
748 0 : static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
749 : nsPresContext* aPresContext, nsStyleContext *aContext,
750 : nscolor& aResult, bool& aCanStoreInRuleTree)
751 : {
752 0 : bool result = false;
753 0 : nsCSSUnit unit = aValue.GetUnit();
754 :
755 0 : if (eCSSUnit_Color == unit) {
756 0 : aResult = aValue.GetColorValue();
757 0 : result = true;
758 : }
759 0 : else if (eCSSUnit_Ident == unit) {
760 0 : nsAutoString value;
761 0 : aValue.GetStringValue(value);
762 : nscolor rgba;
763 0 : if (NS_ColorNameToRGB(value, &rgba)) {
764 0 : aResult = rgba;
765 0 : result = true;
766 : }
767 : }
768 0 : else if (eCSSUnit_EnumColor == unit) {
769 0 : PRInt32 intValue = aValue.GetIntValue();
770 0 : if (0 <= intValue) {
771 0 : LookAndFeel::ColorID colorID = (LookAndFeel::ColorID) intValue;
772 0 : if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID, &aResult))) {
773 0 : result = true;
774 : }
775 : }
776 : else {
777 0 : switch (intValue) {
778 : case NS_COLOR_MOZ_HYPERLINKTEXT:
779 0 : aResult = aPresContext->DefaultLinkColor();
780 0 : break;
781 : case NS_COLOR_MOZ_VISITEDHYPERLINKTEXT:
782 0 : aResult = aPresContext->DefaultVisitedLinkColor();
783 0 : break;
784 : case NS_COLOR_MOZ_ACTIVEHYPERLINKTEXT:
785 0 : aResult = aPresContext->DefaultActiveLinkColor();
786 0 : break;
787 : case NS_COLOR_CURRENTCOLOR:
788 : // The data computed from this can't be shared in the rule tree
789 : // because they could be used on a node with a different color
790 0 : aCanStoreInRuleTree = false;
791 0 : aResult = aContext->GetStyleColor()->mColor;
792 0 : break;
793 : case NS_COLOR_MOZ_DEFAULT_COLOR:
794 0 : aResult = aPresContext->DefaultColor();
795 0 : break;
796 : case NS_COLOR_MOZ_DEFAULT_BACKGROUND_COLOR:
797 0 : aResult = aPresContext->DefaultBackgroundColor();
798 0 : break;
799 : default:
800 0 : NS_NOTREACHED("Should never have an unknown negative colorID.");
801 0 : break;
802 : }
803 0 : result = true;
804 : }
805 : }
806 0 : else if (eCSSUnit_Inherit == unit) {
807 0 : aResult = aParentColor;
808 0 : result = true;
809 0 : aCanStoreInRuleTree = false;
810 : }
811 0 : else if (eCSSUnit_Enumerated == unit &&
812 0 : aValue.GetIntValue() == NS_STYLE_COLOR_INHERIT_FROM_BODY) {
813 0 : NS_ASSERTION(aPresContext->CompatibilityMode() == eCompatibility_NavQuirks,
814 : "Should only get this value in quirks mode");
815 : // We just grab the color from the prescontext, and rely on the fact that
816 : // if the body color ever changes all its descendants will get new style
817 : // contexts (but NOT necessarily new rulenodes).
818 0 : aResult = aPresContext->BodyTextColor();
819 0 : result = true;
820 0 : aCanStoreInRuleTree = false;
821 : }
822 0 : return result;
823 : }
824 :
825 0 : static void SetGradientCoord(const nsCSSValue& aValue, nsPresContext* aPresContext,
826 : nsStyleContext* aContext, nsStyleCoord& aResult,
827 : bool& aCanStoreInRuleTree)
828 : {
829 : // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
830 0 : if (!SetCoord(aValue, aResult, nsStyleCoord(),
831 : SETCOORD_LPO | SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC,
832 0 : aContext, aPresContext, aCanStoreInRuleTree)) {
833 0 : NS_NOTREACHED("unexpected unit for gradient anchor point");
834 0 : aResult.SetNoneValue();
835 : }
836 0 : }
837 :
838 0 : static void SetGradient(const nsCSSValue& aValue, nsPresContext* aPresContext,
839 : nsStyleContext* aContext, nsStyleGradient& aResult,
840 : bool& aCanStoreInRuleTree)
841 : {
842 0 : NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Gradient,
843 : "The given data is not a gradient");
844 :
845 0 : nsCSSValueGradient* gradient = aValue.GetGradientValue();
846 :
847 0 : if (gradient->mIsRadial) {
848 0 : if (gradient->mRadialShape.GetUnit() == eCSSUnit_Enumerated) {
849 0 : aResult.mShape = gradient->mRadialShape.GetIntValue();
850 : } else {
851 0 : NS_ASSERTION(gradient->mRadialShape.GetUnit() == eCSSUnit_None,
852 : "bad unit for radial shape");
853 0 : aResult.mShape = NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL;
854 : }
855 0 : if (gradient->mRadialSize.GetUnit() == eCSSUnit_Enumerated) {
856 0 : aResult.mSize = gradient->mRadialSize.GetIntValue();
857 : } else {
858 0 : NS_ASSERTION(gradient->mRadialSize.GetUnit() == eCSSUnit_None,
859 : "bad unit for radial shape");
860 0 : aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
861 : }
862 : } else {
863 0 : NS_ASSERTION(gradient->mRadialShape.GetUnit() == eCSSUnit_None,
864 : "bad unit for linear shape");
865 0 : NS_ASSERTION(gradient->mRadialSize.GetUnit() == eCSSUnit_None,
866 : "bad unit for linear size");
867 0 : aResult.mShape = NS_STYLE_GRADIENT_SHAPE_LINEAR;
868 0 : aResult.mSize = NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER;
869 :
870 0 : aResult.mToCorner = gradient->mIsToCorner;
871 : }
872 :
873 : // bg-position
874 : SetGradientCoord(gradient->mBgPos.mXValue, aPresContext, aContext,
875 0 : aResult.mBgPosX, aCanStoreInRuleTree);
876 :
877 : SetGradientCoord(gradient->mBgPos.mYValue, aPresContext, aContext,
878 0 : aResult.mBgPosY, aCanStoreInRuleTree);
879 :
880 0 : aResult.mRepeating = gradient->mIsRepeating;
881 :
882 : // angle
883 0 : if (gradient->mAngle.IsAngularUnit()) {
884 : nsStyleUnit unit;
885 0 : switch (gradient->mAngle.GetUnit()) {
886 0 : case eCSSUnit_Degree: unit = eStyleUnit_Degree; break;
887 0 : case eCSSUnit_Grad: unit = eStyleUnit_Grad; break;
888 0 : case eCSSUnit_Radian: unit = eStyleUnit_Radian; break;
889 0 : case eCSSUnit_Turn: unit = eStyleUnit_Turn; break;
890 0 : default: NS_NOTREACHED("unrecognized angular unit");
891 0 : unit = eStyleUnit_Degree;
892 : }
893 0 : aResult.mAngle.SetAngleValue(gradient->mAngle.GetAngleValue(), unit);
894 : } else {
895 0 : NS_ASSERTION(gradient->mAngle.GetUnit() == eCSSUnit_None,
896 : "bad unit for gradient angle");
897 0 : aResult.mAngle.SetNoneValue();
898 : }
899 :
900 : // stops
901 0 : for (PRUint32 i = 0; i < gradient->mStops.Length(); i++) {
902 0 : nsStyleGradientStop stop;
903 0 : nsCSSValueGradientStop &valueStop = gradient->mStops[i];
904 :
905 0 : if (!SetCoord(valueStop.mLocation, stop.mLocation,
906 : nsStyleCoord(), SETCOORD_LPO,
907 0 : aContext, aPresContext, aCanStoreInRuleTree)) {
908 0 : NS_NOTREACHED("unexpected unit for gradient stop location");
909 : }
910 :
911 : // inherit is not a valid color for stops, so we pass in a dummy
912 : // parent color
913 0 : NS_ASSERTION(valueStop.mColor.GetUnit() != eCSSUnit_Inherit,
914 : "inherit is not a valid color for gradient stops");
915 : SetColor(valueStop.mColor, NS_RGB(0, 0, 0), aPresContext,
916 0 : aContext, stop.mColor, aCanStoreInRuleTree);
917 :
918 0 : aResult.mStops.AppendElement(stop);
919 : }
920 0 : }
921 :
922 : // -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
923 0 : static void SetStyleImageToImageRect(nsStyleContext* aStyleContext,
924 : const nsCSSValue& aValue,
925 : nsStyleImage& aResult)
926 : {
927 0 : NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Function &&
928 : aValue.EqualsFunction(eCSSKeyword__moz_image_rect),
929 : "the value is not valid -moz-image-rect()");
930 :
931 0 : nsCSSValue::Array* arr = aValue.GetArrayValue();
932 0 : NS_ABORT_IF_FALSE(arr && arr->Count() == 6, "invalid number of arguments");
933 :
934 : // <uri>
935 0 : if (arr->Item(1).GetUnit() == eCSSUnit_Image) {
936 0 : NS_SET_IMAGE_REQUEST(aResult.SetImageData,
937 : aStyleContext,
938 : arr->Item(1).GetImageValue())
939 : } else {
940 0 : NS_WARNING("nsCSSValue::Image::Image() failed?");
941 : }
942 :
943 : // <top>, <right>, <bottom>, <left>
944 0 : nsStyleSides cropRect;
945 0 : NS_FOR_CSS_SIDES(side) {
946 0 : nsStyleCoord coord;
947 0 : const nsCSSValue& val = arr->Item(2 + side);
948 :
949 : #ifdef DEBUG
950 : bool unitOk =
951 : #endif
952 0 : SetAbsCoord(val, coord, SETCOORD_FACTOR | SETCOORD_PERCENT);
953 0 : NS_ABORT_IF_FALSE(unitOk, "Incorrect data structure created by CSS parser");
954 0 : cropRect.Set(side, coord);
955 : }
956 0 : aResult.SetCropRect(&cropRect);
957 0 : }
958 :
959 0 : static void SetStyleImage(nsStyleContext* aStyleContext,
960 : const nsCSSValue& aValue,
961 : nsStyleImage& aResult,
962 : bool& aCanStoreInRuleTree)
963 : {
964 0 : aResult.SetNull();
965 :
966 0 : switch (aValue.GetUnit()) {
967 : case eCSSUnit_Image:
968 0 : NS_SET_IMAGE_REQUEST(aResult.SetImageData,
969 : aStyleContext,
970 : aValue.GetImageValue())
971 0 : break;
972 : case eCSSUnit_Function:
973 0 : if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
974 0 : SetStyleImageToImageRect(aStyleContext, aValue, aResult);
975 : } else {
976 0 : NS_NOTREACHED("-moz-image-rect() is the only expected function");
977 : }
978 0 : break;
979 : case eCSSUnit_Gradient:
980 : {
981 0 : nsStyleGradient* gradient = new nsStyleGradient();
982 0 : if (gradient) {
983 : SetGradient(aValue, aStyleContext->PresContext(), aStyleContext,
984 0 : *gradient, aCanStoreInRuleTree);
985 0 : aResult.SetGradientData(gradient);
986 : }
987 0 : break;
988 : }
989 : case eCSSUnit_Element:
990 0 : aResult.SetElementId(aValue.GetStringBufferValue());
991 0 : break;
992 : case eCSSUnit_None:
993 0 : break;
994 : default:
995 : // We might have eCSSUnit_URL values for if-visited style
996 : // contexts, which we can safely treat like 'none'. Otherwise
997 : // this is an unexpected unit.
998 0 : NS_ASSERTION(aStyleContext->IsStyleIfVisited() &&
999 : aValue.GetUnit() == eCSSUnit_URL,
1000 : "unexpected unit; maybe nsCSSValue::Image::Image() failed?");
1001 0 : break;
1002 : }
1003 0 : }
1004 :
1005 : // flags for SetDiscrete - align values with SETCOORD_* constants
1006 : // where possible
1007 :
1008 : #define SETDSC_NORMAL 0x01 // N
1009 : #define SETDSC_AUTO 0x02 // A
1010 : #define SETDSC_INTEGER 0x40 // I
1011 : #define SETDSC_ENUMERATED 0x80 // E
1012 : #define SETDSC_NONE 0x100 // O
1013 : #define SETDSC_SYSTEM_FONT 0x2000
1014 :
1015 : // no caller cares whether aField was changed or not
1016 : template <typename FieldT,
1017 : typename T1, typename T2, typename T3, typename T4, typename T5>
1018 : static void
1019 0 : SetDiscrete(const nsCSSValue& aValue, FieldT & aField,
1020 : bool& aCanStoreInRuleTree, PRUint32 aMask,
1021 : FieldT aParentValue,
1022 : T1 aInitialValue,
1023 : T2 aAutoValue,
1024 : T3 aNoneValue,
1025 : T4 aNormalValue,
1026 : T5 aSystemFontValue)
1027 : {
1028 0 : switch (aValue.GetUnit()) {
1029 : case eCSSUnit_Null:
1030 0 : return;
1031 :
1032 : // every caller of SetDiscrete provides inherit and initial
1033 : // alternatives, so we don't require them to say so in the mask
1034 : case eCSSUnit_Inherit:
1035 0 : aCanStoreInRuleTree = false;
1036 0 : aField = aParentValue;
1037 0 : return;
1038 :
1039 : case eCSSUnit_Initial:
1040 0 : aField = aInitialValue;
1041 0 : return;
1042 :
1043 : // every caller provides one or other of these alternatives,
1044 : // but they have to say which
1045 : case eCSSUnit_Enumerated:
1046 0 : if (aMask & SETDSC_ENUMERATED) {
1047 0 : aField = aValue.GetIntValue();
1048 0 : return;
1049 : }
1050 0 : break;
1051 :
1052 : case eCSSUnit_Integer:
1053 0 : if (aMask & SETDSC_INTEGER) {
1054 0 : aField = aValue.GetIntValue();
1055 0 : return;
1056 : }
1057 0 : break;
1058 :
1059 : // remaining possibilities in descending order of frequency of use
1060 : case eCSSUnit_Auto:
1061 0 : if (aMask & SETDSC_AUTO) {
1062 0 : aField = aAutoValue;
1063 0 : return;
1064 : }
1065 0 : break;
1066 :
1067 : case eCSSUnit_None:
1068 0 : if (aMask & SETDSC_NONE) {
1069 0 : aField = aNoneValue;
1070 0 : return;
1071 : }
1072 0 : break;
1073 :
1074 : case eCSSUnit_Normal:
1075 0 : if (aMask & SETDSC_NORMAL) {
1076 0 : aField = aNormalValue;
1077 0 : return;
1078 : }
1079 0 : break;
1080 :
1081 : case eCSSUnit_System_Font:
1082 0 : if (aMask & SETDSC_SYSTEM_FONT) {
1083 0 : aField = aSystemFontValue;
1084 0 : return;
1085 : }
1086 0 : break;
1087 :
1088 : default:
1089 0 : break;
1090 : }
1091 :
1092 0 : NS_NOTREACHED("SetDiscrete: inappropriate unit");
1093 : }
1094 :
1095 : // flags for SetFactor
1096 : #define SETFCT_POSITIVE 0x01 // assert value is >= 0.0f
1097 : #define SETFCT_OPACITY 0x02 // clamp value to [0.0f .. 1.0f]
1098 : #define SETFCT_NONE 0x04 // allow _None (uses aInitialValue).
1099 :
1100 : static void
1101 0 : SetFactor(const nsCSSValue& aValue, float& aField, bool& aCanStoreInRuleTree,
1102 : float aParentValue, float aInitialValue, PRUint32 aFlags = 0)
1103 : {
1104 0 : switch (aValue.GetUnit()) {
1105 : case eCSSUnit_Null:
1106 0 : return;
1107 :
1108 : case eCSSUnit_Number:
1109 0 : aField = aValue.GetFloatValue();
1110 0 : if (aFlags & SETFCT_POSITIVE) {
1111 0 : NS_ASSERTION(aField >= 0.0f, "negative value for positive-only property");
1112 0 : if (aField < 0.0f)
1113 0 : aField = 0.0f;
1114 : }
1115 0 : if (aFlags & SETFCT_OPACITY) {
1116 0 : if (aField < 0.0f)
1117 0 : aField = 0.0f;
1118 0 : if (aField > 1.0f)
1119 0 : aField = 1.0f;
1120 : }
1121 0 : return;
1122 :
1123 : case eCSSUnit_Inherit:
1124 0 : aCanStoreInRuleTree = false;
1125 0 : aField = aParentValue;
1126 0 : return;
1127 :
1128 : case eCSSUnit_Initial:
1129 0 : aField = aInitialValue;
1130 0 : return;
1131 :
1132 : case eCSSUnit_None:
1133 0 : if (aFlags & SETFCT_NONE) {
1134 0 : aField = aInitialValue;
1135 0 : return;
1136 : }
1137 0 : break;
1138 :
1139 : default:
1140 0 : break;
1141 : }
1142 :
1143 0 : NS_NOTREACHED("SetFactor: inappropriate unit");
1144 : }
1145 :
1146 : // Overloaded new operator. Initializes the memory to 0 and relies on an arena
1147 : // (which comes from the presShell) to perform the allocation.
1148 : void*
1149 0 : nsRuleNode::operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
1150 : {
1151 : // Check the recycle list first.
1152 0 : return aPresContext->AllocateFromShell(sz);
1153 : }
1154 :
1155 : /* static */ PLDHashOperator
1156 0 : nsRuleNode::EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
1157 : PRUint32 number, void *arg)
1158 : {
1159 0 : ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
1160 0 : nsRuleNode ***destroyQueueTail = static_cast<nsRuleNode***>(arg);
1161 0 : **destroyQueueTail = entry->mRuleNode;
1162 0 : *destroyQueueTail = &entry->mRuleNode->mNextSibling;
1163 0 : return PL_DHASH_NEXT;
1164 : }
1165 :
1166 : // Overridden to prevent the global delete from being called, since the memory
1167 : // came out of an nsIArena instead of the global delete operator's heap.
1168 : void
1169 0 : nsRuleNode::DestroyInternal(nsRuleNode ***aDestroyQueueTail)
1170 : {
1171 : nsRuleNode *destroyQueue, **destroyQueueTail;
1172 0 : if (aDestroyQueueTail) {
1173 0 : destroyQueueTail = *aDestroyQueueTail;
1174 : } else {
1175 0 : destroyQueue = nsnull;
1176 0 : destroyQueueTail = &destroyQueue;
1177 : }
1178 :
1179 0 : if (ChildrenAreHashed()) {
1180 0 : PLDHashTable *children = ChildrenHash();
1181 : PL_DHashTableEnumerate(children, EnqueueRuleNodeChildren,
1182 0 : &destroyQueueTail);
1183 0 : *destroyQueueTail = nsnull; // ensure null-termination
1184 0 : PL_DHashTableDestroy(children);
1185 0 : } else if (HaveChildren()) {
1186 0 : *destroyQueueTail = ChildrenList();
1187 0 : do {
1188 0 : destroyQueueTail = &(*destroyQueueTail)->mNextSibling;
1189 : } while (*destroyQueueTail);
1190 : }
1191 0 : mChildren.asVoid = nsnull;
1192 :
1193 0 : if (aDestroyQueueTail) {
1194 : // Our caller destroys the queue.
1195 0 : *aDestroyQueueTail = destroyQueueTail;
1196 : } else {
1197 : // We have to do destroy the queue. When we destroy each node, it
1198 : // will add its children to the queue.
1199 0 : while (destroyQueue) {
1200 0 : nsRuleNode *cur = destroyQueue;
1201 0 : destroyQueue = destroyQueue->mNextSibling;
1202 0 : if (!destroyQueue) {
1203 0 : NS_ASSERTION(destroyQueueTail == &cur->mNextSibling, "mangled list");
1204 0 : destroyQueueTail = &destroyQueue;
1205 : }
1206 0 : cur->DestroyInternal(&destroyQueueTail);
1207 : }
1208 : }
1209 :
1210 : // Destroy ourselves.
1211 0 : this->~nsRuleNode();
1212 :
1213 : // Don't let the memory be freed, since it will be recycled
1214 : // instead. Don't call the global operator delete.
1215 0 : mPresContext->FreeToShell(sizeof(nsRuleNode), this);
1216 0 : }
1217 :
1218 0 : nsRuleNode* nsRuleNode::CreateRootNode(nsPresContext* aPresContext)
1219 : {
1220 : return new (aPresContext)
1221 0 : nsRuleNode(aPresContext, nsnull, nsnull, 0xff, false);
1222 : }
1223 :
1224 0 : nsRuleNode::nsRuleNode(nsPresContext* aContext, nsRuleNode* aParent,
1225 : nsIStyleRule* aRule, PRUint8 aLevel,
1226 : bool aIsImportant)
1227 : : mPresContext(aContext),
1228 : mParent(aParent),
1229 : mRule(aRule),
1230 : mDependentBits((PRUint32(aLevel) << NS_RULE_NODE_LEVEL_SHIFT) |
1231 : (aIsImportant ? NS_RULE_NODE_IS_IMPORTANT : 0)),
1232 : mNoneBits(0),
1233 0 : mRefCnt(0)
1234 : {
1235 0 : mChildren.asVoid = nsnull;
1236 0 : MOZ_COUNT_CTOR(nsRuleNode);
1237 0 : NS_IF_ADDREF(mRule);
1238 :
1239 0 : NS_ASSERTION(IsRoot() || GetLevel() == aLevel, "not enough bits");
1240 0 : NS_ASSERTION(IsRoot() || IsImportantRule() == aIsImportant, "yikes");
1241 : /* If IsRoot(), then aContext->StyleSet() is typically null at this
1242 : point. In any case, we don't want to treat the root rulenode as
1243 : unused. */
1244 0 : if (!IsRoot()) {
1245 0 : mParent->AddRef();
1246 0 : aContext->StyleSet()->RuleNodeUnused();
1247 : }
1248 :
1249 : // nsStyleSet::GetContext depends on there being only one animation
1250 : // rule.
1251 0 : NS_ABORT_IF_FALSE(IsRoot() || GetLevel() != nsStyleSet::eAnimationSheet ||
1252 : mParent->IsRoot() ||
1253 : mParent->GetLevel() != nsStyleSet::eAnimationSheet,
1254 : "must be only one rule at animation level");
1255 0 : }
1256 :
1257 0 : nsRuleNode::~nsRuleNode()
1258 : {
1259 0 : MOZ_COUNT_DTOR(nsRuleNode);
1260 0 : if (mStyleData.mResetData || mStyleData.mInheritedData)
1261 0 : mStyleData.Destroy(0, mPresContext);
1262 0 : NS_IF_RELEASE(mRule);
1263 0 : }
1264 :
1265 : nsRuleNode*
1266 0 : nsRuleNode::Transition(nsIStyleRule* aRule, PRUint8 aLevel,
1267 : bool aIsImportantRule)
1268 : {
1269 0 : nsRuleNode* next = nsnull;
1270 0 : nsRuleNode::Key key(aRule, aLevel, aIsImportantRule);
1271 :
1272 0 : if (HaveChildren() && !ChildrenAreHashed()) {
1273 0 : PRInt32 numKids = 0;
1274 0 : nsRuleNode* curr = ChildrenList();
1275 0 : while (curr && curr->GetKey() != key) {
1276 0 : curr = curr->mNextSibling;
1277 0 : ++numKids;
1278 : }
1279 0 : if (curr)
1280 0 : next = curr;
1281 0 : else if (numKids >= kMaxChildrenInList)
1282 0 : ConvertChildrenToHash();
1283 : }
1284 :
1285 0 : if (ChildrenAreHashed()) {
1286 : ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>
1287 0 : (PL_DHashTableOperate(ChildrenHash(), &key, PL_DHASH_ADD));
1288 0 : if (!entry) {
1289 0 : NS_WARNING("out of memory");
1290 0 : return this;
1291 : }
1292 0 : if (entry->mRuleNode)
1293 0 : next = entry->mRuleNode;
1294 : else {
1295 : next = entry->mRuleNode = new (mPresContext)
1296 0 : nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
1297 0 : if (!next) {
1298 0 : PL_DHashTableRawRemove(ChildrenHash(), entry);
1299 0 : NS_WARNING("out of memory");
1300 0 : return this;
1301 : }
1302 : }
1303 0 : } else if (!next) {
1304 : // Create the new entry in our list.
1305 : next = new (mPresContext)
1306 0 : nsRuleNode(mPresContext, this, aRule, aLevel, aIsImportantRule);
1307 0 : if (!next) {
1308 0 : NS_WARNING("out of memory");
1309 0 : return this;
1310 : }
1311 0 : next->mNextSibling = ChildrenList();
1312 0 : SetChildrenList(next);
1313 : }
1314 :
1315 0 : return next;
1316 : }
1317 :
1318 : void
1319 0 : nsRuleNode::ConvertChildrenToHash()
1320 : {
1321 0 : NS_ASSERTION(!ChildrenAreHashed() && HaveChildren(),
1322 : "must have a non-empty list of children");
1323 : PLDHashTable *hash = PL_NewDHashTable(&ChildrenHashOps, nsnull,
1324 : sizeof(ChildrenHashEntry),
1325 0 : kMaxChildrenInList * 4);
1326 0 : if (!hash)
1327 0 : return;
1328 0 : for (nsRuleNode* curr = ChildrenList(); curr; curr = curr->mNextSibling) {
1329 : // This will never fail because of the initial size we gave the table.
1330 : ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(
1331 0 : PL_DHashTableOperate(hash, curr->mRule, PL_DHASH_ADD));
1332 0 : NS_ASSERTION(!entry->mRuleNode, "duplicate entries in list");
1333 0 : entry->mRuleNode = curr;
1334 : }
1335 0 : SetChildrenHash(hash);
1336 : }
1337 :
1338 : inline void
1339 0 : nsRuleNode::PropagateNoneBit(PRUint32 aBit, nsRuleNode* aHighestNode)
1340 : {
1341 0 : nsRuleNode* curr = this;
1342 0 : for (;;) {
1343 0 : NS_ASSERTION(!(curr->mNoneBits & aBit), "propagating too far");
1344 0 : curr->mNoneBits |= aBit;
1345 0 : if (curr == aHighestNode)
1346 : break;
1347 0 : curr = curr->mParent;
1348 : }
1349 0 : }
1350 :
1351 : inline void
1352 0 : nsRuleNode::PropagateDependentBit(PRUint32 aBit, nsRuleNode* aHighestNode)
1353 : {
1354 0 : for (nsRuleNode* curr = this; curr != aHighestNode; curr = curr->mParent) {
1355 0 : if (curr->mDependentBits & aBit) {
1356 : #ifdef DEBUG
1357 0 : while (curr != aHighestNode) {
1358 0 : NS_ASSERTION(curr->mDependentBits & aBit, "bit not set");
1359 0 : curr = curr->mParent;
1360 : }
1361 : #endif
1362 0 : break;
1363 : }
1364 :
1365 0 : curr->mDependentBits |= aBit;
1366 : }
1367 0 : }
1368 :
1369 : /*
1370 : * The following "Check" functions are used for determining what type of
1371 : * sharing can be used for the data on this rule node. MORE HERE...
1372 : */
1373 :
1374 : /*
1375 : * a callback function that that can revise the result of
1376 : * CheckSpecifiedProperties before finishing; aResult is the current
1377 : * result, and it returns the revised one.
1378 : */
1379 : typedef nsRuleNode::RuleDetail
1380 : (* CheckCallbackFn)(const nsRuleData* aRuleData,
1381 : nsRuleNode::RuleDetail aResult);
1382 :
1383 : /**
1384 : * @param aValue the value being examined
1385 : * @param aSpecifiedCount to be incremented by one if the value is specified
1386 : * @param aInherited to be incremented by one if the value is set to inherit
1387 : */
1388 : inline void
1389 0 : ExamineCSSValue(const nsCSSValue& aValue,
1390 : PRUint32& aSpecifiedCount, PRUint32& aInheritedCount)
1391 : {
1392 0 : if (aValue.GetUnit() != eCSSUnit_Null) {
1393 0 : ++aSpecifiedCount;
1394 0 : if (aValue.GetUnit() == eCSSUnit_Inherit) {
1395 0 : ++aInheritedCount;
1396 : }
1397 : }
1398 0 : }
1399 :
1400 : static nsRuleNode::RuleDetail
1401 0 : CheckFontCallback(const nsRuleData* aRuleData,
1402 : nsRuleNode::RuleDetail aResult)
1403 : {
1404 : // em, ex, percent, 'larger', and 'smaller' values on font-size depend
1405 : // on the parent context's font-size
1406 : // Likewise, 'lighter' and 'bolder' values of 'font-weight', and 'wider'
1407 : // and 'narrower' values of 'font-stretch' depend on the parent.
1408 0 : const nsCSSValue& size = *aRuleData->ValueForFontSize();
1409 0 : const nsCSSValue& weight = *aRuleData->ValueForFontWeight();
1410 0 : if (size.IsRelativeLengthUnit() ||
1411 0 : size.GetUnit() == eCSSUnit_Percent ||
1412 0 : (size.GetUnit() == eCSSUnit_Enumerated &&
1413 0 : (size.GetIntValue() == NS_STYLE_FONT_SIZE_SMALLER ||
1414 0 : size.GetIntValue() == NS_STYLE_FONT_SIZE_LARGER)) ||
1415 0 : aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Integer ||
1416 0 : (weight.GetUnit() == eCSSUnit_Enumerated &&
1417 0 : (weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_BOLDER ||
1418 0 : weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_LIGHTER))) {
1419 0 : NS_ASSERTION(aResult == nsRuleNode::eRulePartialReset ||
1420 : aResult == nsRuleNode::eRuleFullReset ||
1421 : aResult == nsRuleNode::eRulePartialMixed ||
1422 : aResult == nsRuleNode::eRuleFullMixed,
1423 : "we know we already have a reset-counted property");
1424 : // Promote reset to mixed since we have something that depends on
1425 : // the parent. But never promote to inherited since that could
1426 : // cause inheritance of the exact value.
1427 0 : if (aResult == nsRuleNode::eRulePartialReset)
1428 0 : aResult = nsRuleNode::eRulePartialMixed;
1429 0 : else if (aResult == nsRuleNode::eRuleFullReset)
1430 0 : aResult = nsRuleNode::eRuleFullMixed;
1431 : }
1432 :
1433 0 : return aResult;
1434 : }
1435 :
1436 : static nsRuleNode::RuleDetail
1437 0 : CheckColorCallback(const nsRuleData* aRuleData,
1438 : nsRuleNode::RuleDetail aResult)
1439 : {
1440 : // currentColor values for color require inheritance
1441 0 : const nsCSSValue* colorValue = aRuleData->ValueForColor();
1442 0 : if (colorValue->GetUnit() == eCSSUnit_EnumColor &&
1443 0 : colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
1444 0 : NS_ASSERTION(aResult == nsRuleNode::eRuleFullReset,
1445 : "we should already be counted as full-reset");
1446 0 : aResult = nsRuleNode::eRuleFullInherited;
1447 : }
1448 :
1449 0 : return aResult;
1450 : }
1451 :
1452 : static nsRuleNode::RuleDetail
1453 0 : CheckTextCallback(const nsRuleData* aRuleData,
1454 : nsRuleNode::RuleDetail aResult)
1455 : {
1456 0 : const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
1457 0 : if (textAlignValue->GetUnit() == eCSSUnit_Enumerated &&
1458 0 : textAlignValue->GetIntValue() ==
1459 : NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT) {
1460 : // Promote reset to mixed since we have something that depends on
1461 : // the parent.
1462 0 : if (aResult == nsRuleNode::eRulePartialReset)
1463 0 : aResult = nsRuleNode::eRulePartialMixed;
1464 0 : else if (aResult == nsRuleNode::eRuleFullReset)
1465 0 : aResult = nsRuleNode::eRuleFullMixed;
1466 : }
1467 :
1468 0 : return aResult;
1469 : }
1470 :
1471 : #define FLAG_DATA_FOR_PROPERTY(name_, id_, method_, flags_, parsevariant_, \
1472 : kwtable_, stylestructoffset_, animtype_) \
1473 : flags_,
1474 :
1475 : // The order here must match the enums in *CheckCounter in nsCSSProps.cpp.
1476 :
1477 : static const PRUint32 gFontFlags[] = {
1478 : #define CSS_PROP_FONT FLAG_DATA_FOR_PROPERTY
1479 : #include "nsCSSPropList.h"
1480 : #undef CSS_PROP_FONT
1481 : };
1482 :
1483 : static const PRUint32 gDisplayFlags[] = {
1484 : #define CSS_PROP_DISPLAY FLAG_DATA_FOR_PROPERTY
1485 : #include "nsCSSPropList.h"
1486 : #undef CSS_PROP_DISPLAY
1487 : };
1488 :
1489 : static const PRUint32 gVisibilityFlags[] = {
1490 : #define CSS_PROP_VISIBILITY FLAG_DATA_FOR_PROPERTY
1491 : #include "nsCSSPropList.h"
1492 : #undef CSS_PROP_VISIBILITY
1493 : };
1494 :
1495 : static const PRUint32 gMarginFlags[] = {
1496 : #define CSS_PROP_MARGIN FLAG_DATA_FOR_PROPERTY
1497 : #include "nsCSSPropList.h"
1498 : #undef CSS_PROP_MARGIN
1499 : };
1500 :
1501 : static const PRUint32 gBorderFlags[] = {
1502 : #define CSS_PROP_BORDER FLAG_DATA_FOR_PROPERTY
1503 : #include "nsCSSPropList.h"
1504 : #undef CSS_PROP_BORDER
1505 : };
1506 :
1507 : static const PRUint32 gPaddingFlags[] = {
1508 : #define CSS_PROP_PADDING FLAG_DATA_FOR_PROPERTY
1509 : #include "nsCSSPropList.h"
1510 : #undef CSS_PROP_PADDING
1511 : };
1512 :
1513 : static const PRUint32 gOutlineFlags[] = {
1514 : #define CSS_PROP_OUTLINE FLAG_DATA_FOR_PROPERTY
1515 : #include "nsCSSPropList.h"
1516 : #undef CSS_PROP_OUTLINE
1517 : };
1518 :
1519 : static const PRUint32 gListFlags[] = {
1520 : #define CSS_PROP_LIST FLAG_DATA_FOR_PROPERTY
1521 : #include "nsCSSPropList.h"
1522 : #undef CSS_PROP_LIST
1523 : };
1524 :
1525 : static const PRUint32 gColorFlags[] = {
1526 : #define CSS_PROP_COLOR FLAG_DATA_FOR_PROPERTY
1527 : #include "nsCSSPropList.h"
1528 : #undef CSS_PROP_COLOR
1529 : };
1530 :
1531 : static const PRUint32 gBackgroundFlags[] = {
1532 : #define CSS_PROP_BACKGROUND FLAG_DATA_FOR_PROPERTY
1533 : #include "nsCSSPropList.h"
1534 : #undef CSS_PROP_BACKGROUND
1535 : };
1536 :
1537 : static const PRUint32 gPositionFlags[] = {
1538 : #define CSS_PROP_POSITION FLAG_DATA_FOR_PROPERTY
1539 : #include "nsCSSPropList.h"
1540 : #undef CSS_PROP_POSITION
1541 : };
1542 :
1543 : static const PRUint32 gTableFlags[] = {
1544 : #define CSS_PROP_TABLE FLAG_DATA_FOR_PROPERTY
1545 : #include "nsCSSPropList.h"
1546 : #undef CSS_PROP_TABLE
1547 : };
1548 :
1549 : static const PRUint32 gTableBorderFlags[] = {
1550 : #define CSS_PROP_TABLEBORDER FLAG_DATA_FOR_PROPERTY
1551 : #include "nsCSSPropList.h"
1552 : #undef CSS_PROP_TABLEBORDER
1553 : };
1554 :
1555 : static const PRUint32 gContentFlags[] = {
1556 : #define CSS_PROP_CONTENT FLAG_DATA_FOR_PROPERTY
1557 : #include "nsCSSPropList.h"
1558 : #undef CSS_PROP_CONTENT
1559 : };
1560 :
1561 : static const PRUint32 gQuotesFlags[] = {
1562 : #define CSS_PROP_QUOTES FLAG_DATA_FOR_PROPERTY
1563 : #include "nsCSSPropList.h"
1564 : #undef CSS_PROP_QUOTES
1565 : };
1566 :
1567 : static const PRUint32 gTextFlags[] = {
1568 : #define CSS_PROP_TEXT FLAG_DATA_FOR_PROPERTY
1569 : #include "nsCSSPropList.h"
1570 : #undef CSS_PROP_TEXT
1571 : };
1572 :
1573 : static const PRUint32 gTextResetFlags[] = {
1574 : #define CSS_PROP_TEXTRESET FLAG_DATA_FOR_PROPERTY
1575 : #include "nsCSSPropList.h"
1576 : #undef CSS_PROP_TEXTRESET
1577 : };
1578 :
1579 : static const PRUint32 gUserInterfaceFlags[] = {
1580 : #define CSS_PROP_USERINTERFACE FLAG_DATA_FOR_PROPERTY
1581 : #include "nsCSSPropList.h"
1582 : #undef CSS_PROP_USERINTERFACE
1583 : };
1584 :
1585 : static const PRUint32 gUIResetFlags[] = {
1586 : #define CSS_PROP_UIRESET FLAG_DATA_FOR_PROPERTY
1587 : #include "nsCSSPropList.h"
1588 : #undef CSS_PROP_UIRESET
1589 : };
1590 :
1591 : static const PRUint32 gXULFlags[] = {
1592 : #define CSS_PROP_XUL FLAG_DATA_FOR_PROPERTY
1593 : #include "nsCSSPropList.h"
1594 : #undef CSS_PROP_XUL
1595 : };
1596 :
1597 : static const PRUint32 gSVGFlags[] = {
1598 : #define CSS_PROP_SVG FLAG_DATA_FOR_PROPERTY
1599 : #include "nsCSSPropList.h"
1600 : #undef CSS_PROP_SVG
1601 : };
1602 :
1603 : static const PRUint32 gSVGResetFlags[] = {
1604 : #define CSS_PROP_SVGRESET FLAG_DATA_FOR_PROPERTY
1605 : #include "nsCSSPropList.h"
1606 : #undef CSS_PROP_SVGRESET
1607 : };
1608 :
1609 : static const PRUint32 gColumnFlags[] = {
1610 : #define CSS_PROP_COLUMN FLAG_DATA_FOR_PROPERTY
1611 : #include "nsCSSPropList.h"
1612 : #undef CSS_PROP_COLUMN
1613 : };
1614 :
1615 : #undef FLAG_DATA_FOR_PROPERTY
1616 :
1617 : static const PRUint32* gFlagsByStruct[] = {
1618 :
1619 : #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
1620 : g##name##Flags,
1621 : #include "nsStyleStructList.h"
1622 : #undef STYLE_STRUCT
1623 :
1624 : };
1625 :
1626 : static const CheckCallbackFn gCheckCallbacks[] = {
1627 :
1628 : #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
1629 : checkdata_cb,
1630 : #include "nsStyleStructList.h"
1631 : #undef STYLE_STRUCT
1632 :
1633 : };
1634 :
1635 : #ifdef DEBUG
1636 : static bool
1637 0 : AreAllMathMLPropertiesUndefined(const nsRuleData* aRuleData)
1638 : {
1639 : return
1640 0 : aRuleData->ValueForScriptLevel()->GetUnit() == eCSSUnit_Null &&
1641 0 : aRuleData->ValueForScriptSizeMultiplier()->GetUnit() == eCSSUnit_Null &&
1642 0 : aRuleData->ValueForScriptMinSize()->GetUnit() == eCSSUnit_Null;
1643 : }
1644 : #endif
1645 :
1646 : inline nsRuleNode::RuleDetail
1647 0 : nsRuleNode::CheckSpecifiedProperties(const nsStyleStructID aSID,
1648 : const nsRuleData* aRuleData)
1649 : {
1650 : // Build a count of the:
1651 0 : PRUint32 total = 0, // total number of props in the struct
1652 0 : specified = 0, // number that were specified for this node
1653 0 : inherited = 0; // number that were 'inherit' (and not
1654 : // eCSSUnit_Inherit) for this node
1655 :
1656 : // See comment in nsRuleData.h above mValueOffsets.
1657 0 : NS_ABORT_IF_FALSE(aRuleData->mValueOffsets[aSID] == 0,
1658 : "we assume the value offset is zero instead of adding it");
1659 0 : for (nsCSSValue *values = aRuleData->mValueStorage,
1660 0 : *values_end = values + nsCSSProps::PropertyCountInStruct(aSID);
1661 : values != values_end; ++values) {
1662 0 : ++total;
1663 0 : ExamineCSSValue(*values, specified, inherited);
1664 : }
1665 :
1666 : #if 0
1667 : printf("CheckSpecifiedProperties: SID=%d total=%d spec=%d inh=%d.\n",
1668 : aSID, total, specified, inherited);
1669 : #endif
1670 :
1671 0 : NS_ASSERTION(aSID != eStyleStruct_Font ||
1672 : mPresContext->Document()->GetMathMLEnabled() ||
1673 : AreAllMathMLPropertiesUndefined(aRuleData),
1674 : "MathML style property was defined even though MathML is disabled");
1675 :
1676 : /*
1677 : * Return the most specific information we can: prefer None or Full
1678 : * over Partial, and Reset or Inherited over Mixed, since we can
1679 : * optimize based on the edge cases and not the in-between cases.
1680 : */
1681 : nsRuleNode::RuleDetail result;
1682 0 : if (inherited == total)
1683 0 : result = eRuleFullInherited;
1684 0 : else if (specified == total
1685 : // MathML defines 3 properties in Font that will never be set when
1686 : // MathML is not in use. Therefore if all but three
1687 : // properties have been set, and MathML is not enabled, we can treat
1688 : // this as fully specified. Code in nsMathMLElementFactory will
1689 : // rebuild the rule tree and style data when MathML is first enabled
1690 : // (see nsMathMLElement::BindToTree).
1691 : || (aSID == eStyleStruct_Font && specified + 3 == total &&
1692 0 : !mPresContext->Document()->GetMathMLEnabled())
1693 : ) {
1694 0 : if (inherited == 0)
1695 0 : result = eRuleFullReset;
1696 : else
1697 0 : result = eRuleFullMixed;
1698 0 : } else if (specified == 0)
1699 0 : result = eRuleNone;
1700 0 : else if (specified == inherited)
1701 0 : result = eRulePartialInherited;
1702 0 : else if (inherited == 0)
1703 0 : result = eRulePartialReset;
1704 : else
1705 0 : result = eRulePartialMixed;
1706 :
1707 0 : CheckCallbackFn cb = gCheckCallbacks[aSID];
1708 0 : if (cb) {
1709 0 : result = (*cb)(aRuleData, result);
1710 : }
1711 :
1712 0 : return result;
1713 : }
1714 :
1715 : // If we need to restrict which properties apply to the style context,
1716 : // return the bit to check in nsCSSProp's flags table. Otherwise,
1717 : // return 0.
1718 : inline PRUint32
1719 0 : GetPseudoRestriction(nsStyleContext *aContext)
1720 : {
1721 : // This needs to match nsStyleSet::WalkRestrictionRule.
1722 0 : PRUint32 pseudoRestriction = 0;
1723 0 : nsIAtom *pseudoType = aContext->GetPseudo();
1724 0 : if (pseudoType) {
1725 0 : if (pseudoType == nsCSSPseudoElements::firstLetter) {
1726 0 : pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LETTER;
1727 0 : } else if (pseudoType == nsCSSPseudoElements::firstLine) {
1728 0 : pseudoRestriction = CSS_PROPERTY_APPLIES_TO_FIRST_LINE;
1729 : }
1730 : }
1731 0 : return pseudoRestriction;
1732 : }
1733 :
1734 : static void
1735 0 : UnsetPropertiesWithoutFlags(const nsStyleStructID aSID,
1736 : nsRuleData* aRuleData,
1737 : PRUint32 aFlags)
1738 : {
1739 0 : NS_ASSERTION(aFlags != 0, "aFlags must be nonzero");
1740 :
1741 0 : const PRUint32 *flagData = gFlagsByStruct[aSID];
1742 :
1743 : // See comment in nsRuleData.h above mValueOffsets.
1744 0 : NS_ABORT_IF_FALSE(aRuleData->mValueOffsets[aSID] == 0,
1745 : "we assume the value offset is zero instead of adding it");
1746 0 : nsCSSValue *values = aRuleData->mValueStorage;
1747 :
1748 0 : for (size_t i = 0, i_end = nsCSSProps::PropertyCountInStruct(aSID);
1749 : i != i_end; ++i) {
1750 0 : if ((flagData[i] & aFlags) != aFlags)
1751 0 : values[i].Reset();
1752 : }
1753 0 : }
1754 :
1755 : /**
1756 : * We allocate arrays of CSS values with alloca. (These arrays are a
1757 : * fixed size per style struct, but we don't want to waste the
1758 : * allocation and construction/destruction costs of the big structs when
1759 : * we're handling much smaller ones.) Since the lifetime of an alloca
1760 : * allocation is the life of the calling function, the caller must call
1761 : * alloca. However, to ensure that constructors and destructors are
1762 : * balanced, we do the constructor and destructor calling from this RAII
1763 : * class, AutoCSSValueArray.
1764 : */
1765 : struct AutoCSSValueArray {
1766 : /**
1767 : * aStorage must be the result of alloca(aCount * sizeof(nsCSSValue))
1768 : */
1769 0 : AutoCSSValueArray(void* aStorage, size_t aCount) {
1770 0 : NS_ABORT_IF_FALSE(size_t(aStorage) % NS_ALIGNMENT_OF(nsCSSValue) == 0,
1771 : "bad alignment from alloca");
1772 0 : mCount = aCount;
1773 : // Don't use placement new[], since it might store extra data
1774 : // for the count (on Windows!).
1775 0 : mArray = static_cast<nsCSSValue*>(aStorage);
1776 0 : for (size_t i = 0; i < mCount; ++i) {
1777 0 : new (mArray + i) nsCSSValue();
1778 : }
1779 0 : }
1780 :
1781 0 : ~AutoCSSValueArray() {
1782 0 : for (size_t i = 0; i < mCount; ++i) {
1783 0 : mArray[i].~nsCSSValue();
1784 : }
1785 0 : }
1786 :
1787 0 : nsCSSValue* get() { return mArray; }
1788 :
1789 : private:
1790 : nsCSSValue *mArray;
1791 : size_t mCount;
1792 : };
1793 :
1794 : const void*
1795 0 : nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
1796 : nsStyleContext* aContext)
1797 : {
1798 : // use placement new[] on the result of alloca() to allocate a
1799 : // variable-sized stack array, including execution of constructors,
1800 : // and use an RAII class to run the destructors too.
1801 0 : size_t nprops = nsCSSProps::PropertyCountInStruct(aSID);
1802 0 : void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
1803 0 : AutoCSSValueArray dataArray(dataStorage, nprops);
1804 :
1805 : nsRuleData ruleData(nsCachedStyleData::GetBitForSID(aSID),
1806 0 : dataArray.get(), mPresContext, aContext);
1807 0 : ruleData.mValueOffsets[aSID] = 0;
1808 :
1809 : // We start at the most specific rule in the tree.
1810 0 : void* startStruct = nsnull;
1811 :
1812 0 : nsRuleNode* ruleNode = this;
1813 0 : nsRuleNode* highestNode = nsnull; // The highest node in the rule tree
1814 : // that has the same properties
1815 : // specified for struct |aSID| as
1816 : // |this| does.
1817 0 : nsRuleNode* rootNode = this; // After the loop below, this will be the
1818 : // highest node that we've walked without
1819 : // finding cached data on the rule tree.
1820 : // If we don't find any cached data, it
1821 : // will be the root. (XXX misnamed)
1822 0 : RuleDetail detail = eRuleNone;
1823 0 : PRUint32 bit = nsCachedStyleData::GetBitForSID(aSID);
1824 :
1825 0 : while (ruleNode) {
1826 : // See if this rule node has cached the fact that the remaining
1827 : // nodes along this path specify no data whatsoever.
1828 0 : if (ruleNode->mNoneBits & bit)
1829 0 : break;
1830 :
1831 : // If the dependent bit is set on a rule node for this struct, that
1832 : // means its rule won't have any information to add, so skip it.
1833 0 : while (ruleNode->mDependentBits & bit) {
1834 0 : NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nsnull,
1835 : "dependent bit with cached data makes no sense");
1836 : // Climb up to the next rule in the tree (a less specific rule).
1837 0 : rootNode = ruleNode;
1838 0 : ruleNode = ruleNode->mParent;
1839 0 : NS_ASSERTION(!(ruleNode->mNoneBits & bit), "can't have both bits set");
1840 : }
1841 :
1842 : // Check for cached data after the inner loop above -- otherwise
1843 : // we'll miss it.
1844 0 : startStruct = ruleNode->mStyleData.GetStyleData(aSID);
1845 0 : if (startStruct)
1846 0 : break; // We found a rule with fully specified data. We don't
1847 : // need to go up the tree any further, since the remainder
1848 : // of this branch has already been computed.
1849 :
1850 : // Ask the rule to fill in the properties that it specifies.
1851 0 : nsIStyleRule *rule = ruleNode->mRule;
1852 0 : if (rule) {
1853 0 : ruleData.mLevel = ruleNode->GetLevel();
1854 0 : ruleData.mIsImportantRule = ruleNode->IsImportantRule();
1855 0 : rule->MapRuleInfoInto(&ruleData);
1856 : }
1857 :
1858 : // Now we check to see how many properties have been specified by
1859 : // the rules we've examined so far.
1860 0 : RuleDetail oldDetail = detail;
1861 0 : detail = CheckSpecifiedProperties(aSID, &ruleData);
1862 :
1863 0 : if (oldDetail == eRuleNone && detail != eRuleNone)
1864 0 : highestNode = ruleNode;
1865 :
1866 0 : if (detail == eRuleFullReset ||
1867 : detail == eRuleFullMixed ||
1868 : detail == eRuleFullInherited)
1869 0 : break; // We don't need to examine any more rules. All properties
1870 : // have been fully specified.
1871 :
1872 : // Climb up to the next rule in the tree (a less specific rule).
1873 0 : rootNode = ruleNode;
1874 0 : ruleNode = ruleNode->mParent;
1875 : }
1876 :
1877 : // If needed, unset the properties that don't have a flag that allows
1878 : // them to be set for this style context. (For example, only some
1879 : // properties apply to :first-line and :first-letter.)
1880 0 : PRUint32 pseudoRestriction = GetPseudoRestriction(aContext);
1881 0 : if (pseudoRestriction) {
1882 0 : UnsetPropertiesWithoutFlags(aSID, &ruleData, pseudoRestriction);
1883 :
1884 : // Recompute |detail| based on the restrictions we just applied.
1885 : // We can adjust |detail| arbitrarily because of the restriction
1886 : // rule added in nsStyleSet::WalkRestrictionRule.
1887 0 : detail = CheckSpecifiedProperties(aSID, &ruleData);
1888 : }
1889 :
1890 0 : NS_ASSERTION(!startStruct || (detail != eRuleFullReset &&
1891 : detail != eRuleFullMixed &&
1892 : detail != eRuleFullInherited),
1893 : "can't have start struct and be fully specified");
1894 :
1895 0 : bool isReset = nsCachedStyleData::IsReset(aSID);
1896 0 : if (!highestNode)
1897 0 : highestNode = rootNode;
1898 :
1899 0 : if (!ruleData.mCanStoreInRuleTree)
1900 0 : detail = eRulePartialMixed; // Treat as though some data is specified to avoid
1901 : // the optimizations and force data computation.
1902 :
1903 0 : if (detail == eRuleNone && startStruct && !ruleData.mPostResolveCallback) {
1904 : // We specified absolutely no rule information, but a parent rule in the tree
1905 : // specified all the rule information. We set a bit along the branch from our
1906 : // node in the tree to the node that specified the data that tells nodes on that
1907 : // branch that they never need to examine their rules for this particular struct type
1908 : // ever again.
1909 0 : PropagateDependentBit(bit, ruleNode);
1910 0 : return startStruct;
1911 : }
1912 : // FIXME Do we need to check for mPostResolveCallback?
1913 0 : if ((!startStruct && !isReset &&
1914 : (detail == eRuleNone || detail == eRulePartialInherited)) ||
1915 : detail == eRuleFullInherited) {
1916 : // We specified no non-inherited information and neither did any of
1917 : // our parent rules.
1918 :
1919 : // We set a bit along the branch from the highest node (ruleNode)
1920 : // down to our node (this) indicating that no non-inherited data was
1921 : // specified. This bit is guaranteed to be set already on the path
1922 : // from the highest node to the root node in the case where
1923 : // (detail == eRuleNone), which is the most common case here.
1924 : // We must check |!isReset| because the Compute*Data functions for
1925 : // reset structs wouldn't handle none bits correctly.
1926 0 : if (highestNode != this && !isReset)
1927 0 : PropagateNoneBit(bit, highestNode);
1928 :
1929 : // All information must necessarily be inherited from our parent style context.
1930 : // In the absence of any computed data in the rule tree and with
1931 : // no rules specified that didn't have values of 'inherit', we should check our parent.
1932 0 : nsStyleContext* parentContext = aContext->GetParent();
1933 0 : if (isReset) {
1934 : /* Reset structs don't inherit from first-line. */
1935 : /* See similar code in COMPUTE_START_RESET */
1936 0 : while (parentContext &&
1937 0 : parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) {
1938 0 : parentContext = parentContext->GetParent();
1939 : }
1940 : }
1941 0 : if (parentContext) {
1942 : // We have a parent, and so we should just inherit from the parent.
1943 : // Set the inherit bits on our context. These bits tell the style context that
1944 : // it never has to go back to the rule tree for data. Instead the style context tree
1945 : // should be walked to find the data.
1946 0 : const void* parentStruct = parentContext->GetStyleData(aSID);
1947 0 : aContext->AddStyleBit(bit); // makes const_cast OK.
1948 0 : aContext->SetStyle(aSID, const_cast<void*>(parentStruct));
1949 0 : return parentStruct;
1950 : }
1951 : else
1952 : // We are the root. In the case of fonts, the default values just
1953 : // come from the pres context.
1954 0 : return SetDefaultOnRoot(aSID, aContext);
1955 : }
1956 :
1957 : // We need to compute the data from the information that the rules specified.
1958 : const void* res;
1959 : #define STYLE_STRUCT_TEST aSID
1960 : #define STYLE_STRUCT(name, checkdata_cb, ctor_args) \
1961 : res = Compute##name##Data(startStruct, &ruleData, aContext, \
1962 : highestNode, detail, ruleData.mCanStoreInRuleTree);
1963 : #include "nsStyleStructList.h"
1964 : #undef STYLE_STRUCT
1965 : #undef STYLE_STRUCT_TEST
1966 :
1967 : // If we have a post-resolve callback, handle that now.
1968 0 : if (ruleData.mPostResolveCallback && (NS_LIKELY(res != nsnull)))
1969 0 : (*ruleData.mPostResolveCallback)(const_cast<void*>(res), &ruleData);
1970 :
1971 : // Now return the result.
1972 0 : return res;
1973 : }
1974 :
1975 : const void*
1976 0 : nsRuleNode::SetDefaultOnRoot(const nsStyleStructID aSID, nsStyleContext* aContext)
1977 : {
1978 0 : switch (aSID) {
1979 : case eStyleStruct_Font:
1980 : {
1981 0 : nsStyleFont* fontData = new (mPresContext) nsStyleFont(mPresContext);
1982 0 : if (NS_LIKELY(fontData != nsnull)) {
1983 0 : nscoord minimumFontSize = mPresContext->MinFontSize(fontData->mLanguage);
1984 :
1985 0 : if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
1986 0 : fontData->mFont.size = NS_MAX(fontData->mSize, minimumFontSize);
1987 : }
1988 : else {
1989 0 : fontData->mFont.size = fontData->mSize;
1990 : }
1991 0 : aContext->SetStyle(eStyleStruct_Font, fontData);
1992 : }
1993 0 : return fontData;
1994 : }
1995 : case eStyleStruct_Display:
1996 : {
1997 0 : nsStyleDisplay* disp = new (mPresContext) nsStyleDisplay();
1998 0 : if (NS_LIKELY(disp != nsnull)) {
1999 0 : aContext->SetStyle(eStyleStruct_Display, disp);
2000 : }
2001 0 : return disp;
2002 : }
2003 : case eStyleStruct_Visibility:
2004 : {
2005 0 : nsStyleVisibility* vis = new (mPresContext) nsStyleVisibility(mPresContext);
2006 0 : if (NS_LIKELY(vis != nsnull)) {
2007 0 : aContext->SetStyle(eStyleStruct_Visibility, vis);
2008 : }
2009 0 : return vis;
2010 : }
2011 : case eStyleStruct_Text:
2012 : {
2013 0 : nsStyleText* text = new (mPresContext) nsStyleText();
2014 0 : if (NS_LIKELY(text != nsnull)) {
2015 0 : aContext->SetStyle(eStyleStruct_Text, text);
2016 : }
2017 0 : return text;
2018 : }
2019 : case eStyleStruct_TextReset:
2020 : {
2021 0 : nsStyleTextReset* text = new (mPresContext) nsStyleTextReset();
2022 0 : if (NS_LIKELY(text != nsnull)) {
2023 0 : aContext->SetStyle(eStyleStruct_TextReset, text);
2024 : }
2025 0 : return text;
2026 : }
2027 : case eStyleStruct_Color:
2028 : {
2029 0 : nsStyleColor* color = new (mPresContext) nsStyleColor(mPresContext);
2030 0 : if (NS_LIKELY(color != nsnull)) {
2031 0 : aContext->SetStyle(eStyleStruct_Color, color);
2032 : }
2033 0 : return color;
2034 : }
2035 : case eStyleStruct_Background:
2036 : {
2037 0 : nsStyleBackground* bg = new (mPresContext) nsStyleBackground();
2038 0 : if (NS_LIKELY(bg != nsnull)) {
2039 0 : aContext->SetStyle(eStyleStruct_Background, bg);
2040 : }
2041 0 : return bg;
2042 : }
2043 : case eStyleStruct_Margin:
2044 : {
2045 0 : nsStyleMargin* margin = new (mPresContext) nsStyleMargin();
2046 0 : if (NS_LIKELY(margin != nsnull)) {
2047 0 : aContext->SetStyle(eStyleStruct_Margin, margin);
2048 : }
2049 0 : return margin;
2050 : }
2051 : case eStyleStruct_Border:
2052 : {
2053 0 : nsStyleBorder* border = new (mPresContext) nsStyleBorder(mPresContext);
2054 0 : if (NS_LIKELY(border != nsnull)) {
2055 0 : aContext->SetStyle(eStyleStruct_Border, border);
2056 : }
2057 0 : return border;
2058 : }
2059 : case eStyleStruct_Padding:
2060 : {
2061 0 : nsStylePadding* padding = new (mPresContext) nsStylePadding();
2062 0 : if (NS_LIKELY(padding != nsnull)) {
2063 0 : aContext->SetStyle(eStyleStruct_Padding, padding);
2064 : }
2065 0 : return padding;
2066 : }
2067 : case eStyleStruct_Outline:
2068 : {
2069 0 : nsStyleOutline* outline = new (mPresContext) nsStyleOutline(mPresContext);
2070 0 : if (NS_LIKELY(outline != nsnull)) {
2071 0 : aContext->SetStyle(eStyleStruct_Outline, outline);
2072 : }
2073 0 : return outline;
2074 : }
2075 : case eStyleStruct_List:
2076 : {
2077 0 : nsStyleList* list = new (mPresContext) nsStyleList();
2078 0 : if (NS_LIKELY(list != nsnull)) {
2079 0 : aContext->SetStyle(eStyleStruct_List, list);
2080 : }
2081 0 : return list;
2082 : }
2083 : case eStyleStruct_Position:
2084 : {
2085 0 : nsStylePosition* pos = new (mPresContext) nsStylePosition();
2086 0 : if (NS_LIKELY(pos != nsnull)) {
2087 0 : aContext->SetStyle(eStyleStruct_Position, pos);
2088 : }
2089 0 : return pos;
2090 : }
2091 : case eStyleStruct_Table:
2092 : {
2093 0 : nsStyleTable* table = new (mPresContext) nsStyleTable();
2094 0 : if (NS_LIKELY(table != nsnull)) {
2095 0 : aContext->SetStyle(eStyleStruct_Table, table);
2096 : }
2097 0 : return table;
2098 : }
2099 : case eStyleStruct_TableBorder:
2100 : {
2101 0 : nsStyleTableBorder* table = new (mPresContext) nsStyleTableBorder(mPresContext);
2102 0 : if (NS_LIKELY(table != nsnull)) {
2103 0 : aContext->SetStyle(eStyleStruct_TableBorder, table);
2104 : }
2105 0 : return table;
2106 : }
2107 : case eStyleStruct_Content:
2108 : {
2109 0 : nsStyleContent* content = new (mPresContext) nsStyleContent();
2110 0 : if (NS_LIKELY(content != nsnull)) {
2111 0 : aContext->SetStyle(eStyleStruct_Content, content);
2112 : }
2113 0 : return content;
2114 : }
2115 : case eStyleStruct_Quotes:
2116 : {
2117 0 : nsStyleQuotes* quotes = new (mPresContext) nsStyleQuotes();
2118 0 : if (NS_LIKELY(quotes != nsnull)) {
2119 0 : aContext->SetStyle(eStyleStruct_Quotes, quotes);
2120 : }
2121 0 : return quotes;
2122 : }
2123 : case eStyleStruct_UserInterface:
2124 : {
2125 0 : nsStyleUserInterface* ui = new (mPresContext) nsStyleUserInterface();
2126 0 : if (NS_LIKELY(ui != nsnull)) {
2127 0 : aContext->SetStyle(eStyleStruct_UserInterface, ui);
2128 : }
2129 0 : return ui;
2130 : }
2131 : case eStyleStruct_UIReset:
2132 : {
2133 0 : nsStyleUIReset* ui = new (mPresContext) nsStyleUIReset();
2134 0 : if (NS_LIKELY(ui != nsnull)) {
2135 0 : aContext->SetStyle(eStyleStruct_UIReset, ui);
2136 : }
2137 0 : return ui;
2138 : }
2139 :
2140 : case eStyleStruct_XUL:
2141 : {
2142 0 : nsStyleXUL* xul = new (mPresContext) nsStyleXUL();
2143 0 : if (NS_LIKELY(xul != nsnull)) {
2144 0 : aContext->SetStyle(eStyleStruct_XUL, xul);
2145 : }
2146 0 : return xul;
2147 : }
2148 :
2149 : case eStyleStruct_Column:
2150 : {
2151 0 : nsStyleColumn* column = new (mPresContext) nsStyleColumn(mPresContext);
2152 0 : if (NS_LIKELY(column != nsnull)) {
2153 0 : aContext->SetStyle(eStyleStruct_Column, column);
2154 : }
2155 0 : return column;
2156 : }
2157 :
2158 : case eStyleStruct_SVG:
2159 : {
2160 0 : nsStyleSVG* svg = new (mPresContext) nsStyleSVG();
2161 0 : if (NS_LIKELY(svg != nsnull)) {
2162 0 : aContext->SetStyle(eStyleStruct_SVG, svg);
2163 : }
2164 0 : return svg;
2165 : }
2166 :
2167 : case eStyleStruct_SVGReset:
2168 : {
2169 0 : nsStyleSVGReset* svgReset = new (mPresContext) nsStyleSVGReset();
2170 0 : if (NS_LIKELY(svgReset != nsnull)) {
2171 0 : aContext->SetStyle(eStyleStruct_SVGReset, svgReset);
2172 : }
2173 0 : return svgReset;
2174 : }
2175 : default:
2176 : /*
2177 : * unhandled case: nsStyleStructID_Length.
2178 : * last item of nsStyleStructID, to know its length.
2179 : */
2180 0 : return nsnull;
2181 : }
2182 : return nsnull;
2183 : }
2184 :
2185 : /*
2186 : * This function handles cascading of *-left or *-right box properties
2187 : * against *-start (which is L for LTR and R for RTL) or *-end (which is
2188 : * R for LTR and L for RTL).
2189 : *
2190 : * Cascading these properties correctly is hard because we need to
2191 : * cascade two properties as one, but which two properties depends on a
2192 : * third property ('direction'). We solve this by treating each of
2193 : * these properties (say, 'margin-start') as a shorthand that sets a
2194 : * property containing the value of the property specified
2195 : * ('margin-start-value') and sets a pair of properties
2196 : * ('margin-left-ltr-source' and 'margin-right-rtl-source') saying which
2197 : * of the properties we use. Thus, when we want to compute the value of
2198 : * 'margin-left' when 'direction' is 'ltr', we look at the value of
2199 : * 'margin-left-ltr-source', which tells us whether to use the highest
2200 : * 'margin-left' in the cascade or the highest 'margin-start'.
2201 : *
2202 : * Finally, since we can compute the normal (*-left and *-right)
2203 : * properties in a loop, this function works by modifying the data we
2204 : * will use in that loop (which the caller must copy from the const
2205 : * input).
2206 : */
2207 : void
2208 0 : nsRuleNode::AdjustLogicalBoxProp(nsStyleContext* aContext,
2209 : const nsCSSValue& aLTRSource,
2210 : const nsCSSValue& aRTLSource,
2211 : const nsCSSValue& aLTRLogicalValue,
2212 : const nsCSSValue& aRTLLogicalValue,
2213 : mozilla::css::Side aSide,
2214 : nsCSSRect& aValueRect,
2215 : bool& aCanStoreInRuleTree)
2216 : {
2217 0 : bool LTRlogical = aLTRSource.GetUnit() == eCSSUnit_Enumerated &&
2218 0 : aLTRSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
2219 0 : bool RTLlogical = aRTLSource.GetUnit() == eCSSUnit_Enumerated &&
2220 0 : aRTLSource.GetIntValue() == NS_BOXPROP_SOURCE_LOGICAL;
2221 0 : if (LTRlogical || RTLlogical) {
2222 : // We can't cache anything on the rule tree if we use any data from
2223 : // the style context, since data cached in the rule tree could be
2224 : // used with a style context with a different value.
2225 0 : aCanStoreInRuleTree = false;
2226 0 : PRUint8 dir = aContext->GetStyleVisibility()->mDirection;
2227 :
2228 0 : if (dir == NS_STYLE_DIRECTION_LTR) {
2229 0 : if (LTRlogical)
2230 0 : aValueRect.*(nsCSSRect::sides[aSide]) = aLTRLogicalValue;
2231 : } else {
2232 0 : if (RTLlogical)
2233 0 : aValueRect.*(nsCSSRect::sides[aSide]) = aRTLLogicalValue;
2234 0 : }
2235 0 : } else if (aLTRLogicalValue.GetUnit() == eCSSUnit_Inherit ||
2236 0 : aRTLLogicalValue.GetUnit() == eCSSUnit_Inherit) {
2237 : // It actually is valid to store this in the ruletree, since
2238 : // LTRlogical and RTLlogical are both false, but doing that will
2239 : // trigger asserts. Silence those.
2240 0 : aCanStoreInRuleTree = false;
2241 : }
2242 0 : }
2243 :
2244 : /**
2245 : * Begin an nsRuleNode::Compute*Data function for an inherited struct.
2246 : *
2247 : * @param type_ The nsStyle* type this function computes.
2248 : * @param ctorargs_ The arguments used for the default nsStyle* constructor.
2249 : * @param data_ Variable (declared here) holding the result of this
2250 : * function.
2251 : * @param parentdata_ Variable (declared here) holding the parent style
2252 : * context's data for this struct.
2253 : */
2254 : #define COMPUTE_START_INHERITED(type_, ctorargs_, data_, parentdata_) \
2255 : NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
2256 : "should not have bothered calling Compute*Data"); \
2257 : \
2258 : nsStyleContext* parentContext = aContext->GetParent(); \
2259 : \
2260 : nsStyle##type_* data_ = nsnull; \
2261 : const nsStyle##type_* parentdata_ = nsnull; \
2262 : bool canStoreInRuleTree = aCanStoreInRuleTree; \
2263 : \
2264 : /* If |canStoreInRuleTree| might be true by the time we're done, we */ \
2265 : /* can't call parentContext->GetStyle##type_() since it could recur into */ \
2266 : /* setting the same struct on the same rule node, causing a leak. */ \
2267 : if (parentContext && aRuleDetail != eRuleFullReset && \
2268 : (!aStartStruct || (aRuleDetail != eRulePartialReset && \
2269 : aRuleDetail != eRuleNone))) \
2270 : parentdata_ = parentContext->GetStyle##type_(); \
2271 : if (aStartStruct) \
2272 : /* We only need to compute the delta between this computed data and */ \
2273 : /* our computed data. */ \
2274 : data_ = new (mPresContext) \
2275 : nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
2276 : else { \
2277 : if (aRuleDetail != eRuleFullMixed && aRuleDetail != eRuleFullReset) { \
2278 : /* No question. We will have to inherit. Go ahead and init */ \
2279 : /* with inherited vals from parent. */ \
2280 : canStoreInRuleTree = false; \
2281 : if (parentdata_) \
2282 : data_ = new (mPresContext) nsStyle##type_(*parentdata_); \
2283 : else \
2284 : data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2285 : } \
2286 : else \
2287 : data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2288 : } \
2289 : \
2290 : if (NS_UNLIKELY(!data_)) \
2291 : return nsnull; /* Out Of Memory */ \
2292 : if (!parentdata_) \
2293 : parentdata_ = data_;
2294 :
2295 : /**
2296 : * Begin an nsRuleNode::Compute*Data function for a reset struct.
2297 : *
2298 : * @param type_ The nsStyle* type this function computes.
2299 : * @param ctorargs_ The arguments used for the default nsStyle* constructor.
2300 : * @param data_ Variable (declared here) holding the result of this
2301 : * function.
2302 : * @param parentdata_ Variable (declared here) holding the parent style
2303 : * context's data for this struct.
2304 : */
2305 : #define COMPUTE_START_RESET(type_, ctorargs_, data_, parentdata_) \
2306 : NS_ASSERTION(aRuleDetail != eRuleFullInherited, \
2307 : "should not have bothered calling Compute*Data"); \
2308 : \
2309 : nsStyleContext* parentContext = aContext->GetParent(); \
2310 : /* Reset structs don't inherit from first-line */ \
2311 : /* See similar code in WalkRuleTree */ \
2312 : while (parentContext && \
2313 : parentContext->GetPseudo() == nsCSSPseudoElements::firstLine) { \
2314 : parentContext = parentContext->GetParent(); \
2315 : } \
2316 : \
2317 : nsStyle##type_* data_; \
2318 : if (aStartStruct) \
2319 : /* We only need to compute the delta between this computed data and */ \
2320 : /* our computed data. */ \
2321 : data_ = new (mPresContext) \
2322 : nsStyle##type_(*static_cast<nsStyle##type_*>(aStartStruct)); \
2323 : else \
2324 : data_ = new (mPresContext) nsStyle##type_ ctorargs_; \
2325 : \
2326 : if (NS_UNLIKELY(!data_)) \
2327 : return nsnull; /* Out Of Memory */ \
2328 : \
2329 : /* If |canStoreInRuleTree| might be true by the time we're done, we */ \
2330 : /* can't call parentContext->GetStyle##type_() since it could recur into */ \
2331 : /* setting the same struct on the same rule node, causing a leak. */ \
2332 : const nsStyle##type_* parentdata_ = data_; \
2333 : if (parentContext && \
2334 : aRuleDetail != eRuleFullReset && \
2335 : aRuleDetail != eRulePartialReset && \
2336 : aRuleDetail != eRuleNone) \
2337 : parentdata_ = parentContext->GetStyle##type_(); \
2338 : bool canStoreInRuleTree = aCanStoreInRuleTree;
2339 :
2340 : /**
2341 : * Begin an nsRuleNode::Compute*Data function for an inherited struct.
2342 : *
2343 : * @param type_ The nsStyle* type this function computes.
2344 : * @param data_ Variable holding the result of this function.
2345 : */
2346 : #define COMPUTE_END_INHERITED(type_, data_) \
2347 : NS_POSTCONDITION(!canStoreInRuleTree || aRuleDetail == eRuleFullReset || \
2348 : (aStartStruct && aRuleDetail == eRulePartialReset), \
2349 : "canStoreInRuleTree must be false for inherited structs " \
2350 : "unless all properties have been specified with values " \
2351 : "other than inherit"); \
2352 : if (canStoreInRuleTree) { \
2353 : /* We were fully specified and can therefore be cached right on the */ \
2354 : /* rule node. */ \
2355 : if (!aHighestNode->mStyleData.mInheritedData) { \
2356 : aHighestNode->mStyleData.mInheritedData = \
2357 : new (mPresContext) nsInheritedStyleData; \
2358 : if (NS_UNLIKELY(!aHighestNode->mStyleData.mInheritedData)) { \
2359 : data_->Destroy(mPresContext); \
2360 : return nsnull; \
2361 : } \
2362 : } \
2363 : NS_ASSERTION(!aHighestNode->mStyleData.mInheritedData-> \
2364 : mStyleStructs[eStyleStruct_##type_], \
2365 : "Going to leak style data"); \
2366 : aHighestNode->mStyleData.mInheritedData-> \
2367 : mStyleStructs[eStyleStruct_##type_] = data_; \
2368 : /* Propagate the bit down. */ \
2369 : PropagateDependentBit(NS_STYLE_INHERIT_BIT(type_), aHighestNode); \
2370 : /* Tell the style context that it doesn't own the data */ \
2371 : aContext-> \
2372 : AddStyleBit(nsCachedStyleData::GetBitForSID(eStyleStruct_##type_)); \
2373 : } \
2374 : /* Always cache inherited data on the style context */ \
2375 : aContext->SetStyle##type_(data_); \
2376 : \
2377 : return data_;
2378 :
2379 : /**
2380 : * Begin an nsRuleNode::Compute*Data function for a reset struct.
2381 : *
2382 : * @param type_ The nsStyle* type this function computes.
2383 : * @param data_ Variable holding the result of this function.
2384 : */
2385 : #define COMPUTE_END_RESET(type_, data_) \
2386 : NS_POSTCONDITION(!canStoreInRuleTree || \
2387 : aRuleDetail == eRuleNone || \
2388 : aRuleDetail == eRulePartialReset || \
2389 : aRuleDetail == eRuleFullReset, \
2390 : "canStoreInRuleTree must be false for reset structs " \
2391 : "if any properties were specified as inherit"); \
2392 : if (!canStoreInRuleTree) \
2393 : /* We can't be cached in the rule node. We have to be put right */ \
2394 : /* on the style context. */ \
2395 : aContext->SetStyle(eStyleStruct_##type_, data_); \
2396 : else { \
2397 : /* We were fully specified and can therefore be cached right on the */ \
2398 : /* rule node. */ \
2399 : if (!aHighestNode->mStyleData.mResetData) { \
2400 : aHighestNode->mStyleData.mResetData = \
2401 : new (mPresContext) nsResetStyleData; \
2402 : if (NS_UNLIKELY(!aHighestNode->mStyleData.mResetData)) { \
2403 : data_->Destroy(mPresContext); \
2404 : return nsnull; \
2405 : } \
2406 : } \
2407 : NS_ASSERTION(!aHighestNode->mStyleData.mResetData-> \
2408 : mStyleStructs[eStyleStruct_##type_], \
2409 : "Going to leak style data"); \
2410 : aHighestNode->mStyleData.mResetData-> \
2411 : mStyleStructs[eStyleStruct_##type_] = data_; \
2412 : /* Propagate the bit down. */ \
2413 : PropagateDependentBit(NS_STYLE_INHERIT_BIT(type_), aHighestNode); \
2414 : } \
2415 : \
2416 : return data_;
2417 :
2418 : // This function figures out how much scaling should be suppressed to
2419 : // satisfy scriptminsize. This is our attempt to implement
2420 : // http://www.w3.org/TR/MathML2/chapter3.html#id.3.3.4.2.2
2421 : // This is called after mScriptLevel, mScriptMinSize and mScriptSizeMultiplier
2422 : // have been set in aFont.
2423 : //
2424 : // Here are the invariants we enforce:
2425 : // 1) A decrease in size must not reduce the size below minscriptsize.
2426 : // 2) An increase in size must not increase the size above the size we would
2427 : // have if minscriptsize had not been applied anywhere.
2428 : // 3) The scriptlevel-induced size change must between 1.0 and the parent's
2429 : // scriptsizemultiplier^(new script level - old script level), as close to the
2430 : // latter as possible subject to constraints 1 and 2.
2431 : static nscoord
2432 0 : ComputeScriptLevelSize(const nsStyleFont* aFont, const nsStyleFont* aParentFont,
2433 : nsPresContext* aPresContext, nscoord* aUnconstrainedSize)
2434 : {
2435 : PRInt32 scriptLevelChange =
2436 0 : aFont->mScriptLevel - aParentFont->mScriptLevel;
2437 0 : if (scriptLevelChange == 0) {
2438 0 : *aUnconstrainedSize = aParentFont->mScriptUnconstrainedSize;
2439 : // Constraint #3 says that we cannot change size, and #1 and #2 are always
2440 : // satisfied with no change. It's important this be fast because it covers
2441 : // all non-MathML content.
2442 0 : return aParentFont->mSize;
2443 : }
2444 :
2445 : // Compute actual value of minScriptSize
2446 : nscoord minScriptSize =
2447 0 : nsStyleFont::ZoomText(aPresContext, aParentFont->mScriptMinSize);
2448 :
2449 : double scriptLevelScale =
2450 0 : pow(aParentFont->mScriptSizeMultiplier, scriptLevelChange);
2451 : // Compute the size we would have had if minscriptsize had never been
2452 : // applied, also prevent overflow (bug 413274)
2453 : *aUnconstrainedSize =
2454 : NSToCoordRound(NS_MIN(aParentFont->mScriptUnconstrainedSize*scriptLevelScale,
2455 0 : double(nscoord_MAX)));
2456 : // Compute the size we could get via scriptlevel change
2457 : nscoord scriptLevelSize =
2458 : NSToCoordRound(NS_MIN(aParentFont->mSize*scriptLevelScale,
2459 0 : double(nscoord_MAX)));
2460 0 : if (scriptLevelScale <= 1.0) {
2461 0 : if (aParentFont->mSize <= minScriptSize) {
2462 : // We can't decrease the font size at all, so just stick to no change
2463 : // (authors are allowed to explicitly set the font size smaller than
2464 : // minscriptsize)
2465 0 : return aParentFont->mSize;
2466 : }
2467 : // We can decrease, so apply constraint #1
2468 0 : return NS_MAX(minScriptSize, scriptLevelSize);
2469 : } else {
2470 : // scriptminsize can only make sizes larger than the unconstrained size
2471 0 : NS_ASSERTION(*aUnconstrainedSize <= scriptLevelSize, "How can this ever happen?");
2472 : // Apply constraint #2
2473 0 : return NS_MIN(scriptLevelSize, NS_MAX(*aUnconstrainedSize, minScriptSize));
2474 : }
2475 : }
2476 :
2477 : struct SetFontSizeCalcOps : public css::BasicCoordCalcOps,
2478 : public css::NumbersAlreadyNormalizedOps
2479 : {
2480 : // The parameters beyond aValue that we need for CalcLengthWith.
2481 : const nscoord mParentSize;
2482 : const nsStyleFont* const mParentFont;
2483 : nsPresContext* const mPresContext;
2484 : const bool mAtRoot;
2485 : bool& mCanStoreInRuleTree;
2486 :
2487 0 : SetFontSizeCalcOps(nscoord aParentSize, const nsStyleFont* aParentFont,
2488 : nsPresContext* aPresContext, bool aAtRoot,
2489 : bool& aCanStoreInRuleTree)
2490 : : mParentSize(aParentSize),
2491 : mParentFont(aParentFont),
2492 : mPresContext(aPresContext),
2493 : mAtRoot(aAtRoot),
2494 0 : mCanStoreInRuleTree(aCanStoreInRuleTree)
2495 : {
2496 0 : }
2497 :
2498 0 : result_type ComputeLeafValue(const nsCSSValue& aValue)
2499 : {
2500 : nscoord size;
2501 0 : if (aValue.IsLengthUnit()) {
2502 : // Note that font-based length units use the parent's size
2503 : // unadjusted for scriptlevel changes. A scriptlevel change
2504 : // between us and the parent is simply ignored.
2505 : size = CalcLengthWith(aValue, mParentSize,
2506 : mParentFont,
2507 : nsnull, mPresContext, mAtRoot,
2508 0 : true, mCanStoreInRuleTree);
2509 0 : if (!aValue.IsRelativeLengthUnit()) {
2510 0 : size = nsStyleFont::ZoomText(mPresContext, size);
2511 : }
2512 : }
2513 0 : else if (eCSSUnit_Percent == aValue.GetUnit()) {
2514 0 : mCanStoreInRuleTree = false;
2515 : // Note that % units use the parent's size unadjusted for scriptlevel
2516 : // changes. A scriptlevel change between us and the parent is simply
2517 : // ignored.
2518 : // aValue.GetPercentValue() may be negative for, e.g., calc(-50%)
2519 0 : size = NSCoordSaturatingMultiply(mParentSize, aValue.GetPercentValue());
2520 : } else {
2521 0 : NS_ABORT_IF_FALSE(false, "unexpected value");
2522 0 : size = mParentSize;
2523 : }
2524 :
2525 0 : return size;
2526 : }
2527 : };
2528 :
2529 : /* static */ void
2530 0 : nsRuleNode::SetFontSize(nsPresContext* aPresContext,
2531 : const nsRuleData* aRuleData,
2532 : const nsStyleFont* aFont,
2533 : const nsStyleFont* aParentFont,
2534 : nscoord* aSize,
2535 : const nsFont& aSystemFont,
2536 : nscoord aParentSize,
2537 : nscoord aScriptLevelAdjustedParentSize,
2538 : bool aUsedStartStruct,
2539 : bool aAtRoot,
2540 : bool& aCanStoreInRuleTree)
2541 : {
2542 0 : bool zoom = false;
2543 : PRInt32 baseSize = (PRInt32) aPresContext->
2544 0 : GetDefaultFont(aFont->mGenericID, aFont->mLanguage)->size;
2545 0 : const nsCSSValue* sizeValue = aRuleData->ValueForFontSize();
2546 0 : if (eCSSUnit_Enumerated == sizeValue->GetUnit()) {
2547 0 : PRInt32 value = sizeValue->GetIntValue();
2548 :
2549 0 : zoom = true;
2550 0 : if ((NS_STYLE_FONT_SIZE_XXSMALL <= value) &&
2551 : (value <= NS_STYLE_FONT_SIZE_XXLARGE)) {
2552 : *aSize = nsStyleUtil::CalcFontPointSize(value, baseSize,
2553 0 : aPresContext, eFontSize_CSS);
2554 : }
2555 0 : else if (NS_STYLE_FONT_SIZE_XXXLARGE == value) {
2556 : // <font size="7"> is not specified in CSS, so we don't use eFontSize_CSS.
2557 0 : *aSize = nsStyleUtil::CalcFontPointSize(value, baseSize, aPresContext);
2558 : }
2559 0 : else if (NS_STYLE_FONT_SIZE_LARGER == value ||
2560 : NS_STYLE_FONT_SIZE_SMALLER == value) {
2561 0 : aCanStoreInRuleTree = false;
2562 :
2563 : // Un-zoom so we use the tables correctly. We'll then rezoom due
2564 : // to the |zoom = true| above.
2565 : // Note that relative units here use the parent's size unadjusted
2566 : // for scriptlevel changes. A scriptlevel change between us and the parent
2567 : // is simply ignored.
2568 : nscoord parentSize =
2569 0 : nsStyleFont::UnZoomText(aPresContext, aParentSize);
2570 :
2571 0 : if (NS_STYLE_FONT_SIZE_LARGER == value) {
2572 : *aSize = nsStyleUtil::FindNextLargerFontSize(parentSize,
2573 0 : baseSize, aPresContext, eFontSize_CSS);
2574 :
2575 0 : NS_ASSERTION(*aSize >= parentSize,
2576 : "FindNextLargerFontSize failed");
2577 : }
2578 : else {
2579 : *aSize = nsStyleUtil::FindNextSmallerFontSize(parentSize,
2580 0 : baseSize, aPresContext, eFontSize_CSS);
2581 0 : NS_ASSERTION(*aSize < parentSize ||
2582 : parentSize <= nsPresContext::CSSPixelsToAppUnits(1),
2583 : "FindNextSmallerFontSize failed");
2584 0 : }
2585 : } else {
2586 0 : NS_NOTREACHED("unexpected value");
2587 : }
2588 : }
2589 0 : else if (sizeValue->IsLengthUnit() ||
2590 0 : sizeValue->GetUnit() == eCSSUnit_Percent ||
2591 0 : sizeValue->IsCalcUnit()) {
2592 : SetFontSizeCalcOps ops(aParentSize, aParentFont,
2593 0 : aPresContext, aAtRoot, aCanStoreInRuleTree);
2594 0 : *aSize = css::ComputeCalc(*sizeValue, ops);
2595 0 : if (*aSize < 0) {
2596 0 : NS_ABORT_IF_FALSE(sizeValue->IsCalcUnit(),
2597 : "negative lengths and percents should be rejected "
2598 : "by parser");
2599 0 : *aSize = 0;
2600 : }
2601 : // Zoom is handled inside the calc ops when needed.
2602 0 : zoom = false;
2603 : }
2604 0 : else if (eCSSUnit_System_Font == sizeValue->GetUnit()) {
2605 : // this becomes our cascading size
2606 0 : *aSize = aSystemFont.size;
2607 0 : zoom = true;
2608 : }
2609 0 : else if (eCSSUnit_Inherit == sizeValue->GetUnit()) {
2610 0 : aCanStoreInRuleTree = false;
2611 : // We apply scriptlevel change for this case, because the default is
2612 : // to inherit and we don't want explicit "inherit" to differ from the
2613 : // default.
2614 0 : *aSize = aScriptLevelAdjustedParentSize;
2615 0 : zoom = false;
2616 : }
2617 0 : else if (eCSSUnit_Initial == sizeValue->GetUnit()) {
2618 : // The initial value is 'medium', which has magical sizing based on
2619 : // the generic font family, so do that here too.
2620 0 : *aSize = baseSize;
2621 0 : zoom = true;
2622 : } else {
2623 0 : NS_ASSERTION(eCSSUnit_Null == sizeValue->GetUnit(),
2624 : "What kind of font-size value is this?");
2625 : // if aUsedStartStruct is true, then every single property in the
2626 : // font struct is being set all at once. This means scriptlevel is not
2627 : // going to have any influence on the font size; there is no need to
2628 : // do anything here.
2629 0 : if (!aUsedStartStruct && aParentSize != aScriptLevelAdjustedParentSize) {
2630 : // There was no rule affecting the size but the size has been
2631 : // affected by the parent's size via scriptlevel change. So we cannot
2632 : // store the data in the rule tree.
2633 0 : aCanStoreInRuleTree = false;
2634 0 : *aSize = aScriptLevelAdjustedParentSize;
2635 : }
2636 : }
2637 :
2638 : // We want to zoom the cascaded size so that em-based measurements,
2639 : // line-heights, etc., work.
2640 0 : if (zoom) {
2641 0 : *aSize = nsStyleFont::ZoomText(aPresContext, *aSize);
2642 : }
2643 0 : }
2644 :
2645 0 : static PRInt8 ClampTo8Bit(PRInt32 aValue) {
2646 0 : if (aValue < -128)
2647 0 : return -128;
2648 0 : if (aValue > 127)
2649 0 : return 127;
2650 0 : return PRInt8(aValue);
2651 : }
2652 :
2653 : /* static */ void
2654 0 : nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
2655 : PRUint8 aGenericFontID, const nsRuleData* aRuleData,
2656 : const nsStyleFont* aParentFont,
2657 : nsStyleFont* aFont, bool aUsedStartStruct,
2658 : bool& aCanStoreInRuleTree)
2659 : {
2660 0 : bool atRoot = !aContext->GetParent();
2661 :
2662 : // mLanguage must be set before before any of the CalcLengthWith calls
2663 : // (direct calls or calls via SetFontSize) for the cases where |aParentFont|
2664 : // is the same as |aFont|.
2665 : //
2666 : // -x-lang: string, inherit
2667 : // This is not a real CSS property, it is an HTML attribute mapped to CSS.
2668 0 : const nsCSSValue* langValue = aRuleData->ValueForLang();
2669 0 : if (eCSSUnit_Ident == langValue->GetUnit()) {
2670 0 : nsAutoString lang;
2671 0 : langValue->GetStringValue(lang);
2672 :
2673 0 : nsContentUtils::ASCIIToLower(lang);
2674 0 : aFont->mLanguage = do_GetAtom(lang);
2675 : }
2676 :
2677 : const nsFont* defaultVariableFont =
2678 : aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
2679 0 : aFont->mLanguage);
2680 :
2681 : // -moz-system-font: enum (never inherit!)
2682 : MOZ_STATIC_ASSERT(
2683 : NS_STYLE_FONT_CAPTION == LookAndFeel::eFont_Caption &&
2684 : NS_STYLE_FONT_ICON == LookAndFeel::eFont_Icon &&
2685 : NS_STYLE_FONT_MENU == LookAndFeel::eFont_Menu &&
2686 : NS_STYLE_FONT_MESSAGE_BOX == LookAndFeel::eFont_MessageBox &&
2687 : NS_STYLE_FONT_SMALL_CAPTION == LookAndFeel::eFont_SmallCaption &&
2688 : NS_STYLE_FONT_STATUS_BAR == LookAndFeel::eFont_StatusBar &&
2689 : NS_STYLE_FONT_WINDOW == LookAndFeel::eFont_Window &&
2690 : NS_STYLE_FONT_DOCUMENT == LookAndFeel::eFont_Document &&
2691 : NS_STYLE_FONT_WORKSPACE == LookAndFeel::eFont_Workspace &&
2692 : NS_STYLE_FONT_DESKTOP == LookAndFeel::eFont_Desktop &&
2693 : NS_STYLE_FONT_INFO == LookAndFeel::eFont_Info &&
2694 : NS_STYLE_FONT_DIALOG == LookAndFeel::eFont_Dialog &&
2695 : NS_STYLE_FONT_BUTTON == LookAndFeel::eFont_Button &&
2696 : NS_STYLE_FONT_PULL_DOWN_MENU == LookAndFeel::eFont_PullDownMenu &&
2697 : NS_STYLE_FONT_LIST == LookAndFeel::eFont_List &&
2698 : NS_STYLE_FONT_FIELD == LookAndFeel::eFont_Field,
2699 : "LookAndFeel.h system-font constants out of sync with nsStyleConsts.h");
2700 :
2701 : // Fall back to defaultVariableFont.
2702 0 : nsFont systemFont = *defaultVariableFont;
2703 0 : const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
2704 0 : if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
2705 0 : gfxFontStyle fontStyle;
2706 : LookAndFeel::FontID fontID =
2707 0 : (LookAndFeel::FontID)systemFontValue->GetIntValue();
2708 0 : if (LookAndFeel::GetFont(fontID, systemFont.name, fontStyle)) {
2709 0 : systemFont.style = fontStyle.style;
2710 0 : systemFont.systemFont = fontStyle.systemFont;
2711 0 : systemFont.variant = NS_FONT_VARIANT_NORMAL;
2712 0 : systemFont.weight = fontStyle.weight;
2713 0 : systemFont.stretch = fontStyle.stretch;
2714 0 : systemFont.decorations = NS_FONT_DECORATION_NONE;
2715 : systemFont.size = NSFloatPixelsToAppUnits(fontStyle.size,
2716 : aPresContext->DeviceContext()->
2717 0 : UnscaledAppUnitsPerDevPixel());
2718 : //systemFont.langGroup = fontStyle.langGroup;
2719 0 : systemFont.sizeAdjust = fontStyle.sizeAdjust;
2720 :
2721 : #ifdef XP_WIN
2722 : // XXXldb This platform-specific stuff should be in the
2723 : // LookAndFeel implementation, not here.
2724 : // XXXzw Should we even still *have* this code? It looks to be making
2725 : // old, probably obsolete assumptions.
2726 :
2727 : // As far as I can tell the system default fonts and sizes
2728 : // on MS-Windows for Buttons, Listboxes/Comboxes and Text Fields are
2729 : // all pre-determined and cannot be changed by either the control panel
2730 : // or programmtically.
2731 : switch (fontID) {
2732 : // Fields (text fields)
2733 : // Button and Selects (listboxes/comboboxes)
2734 : // We use whatever font is defined by the system. Which it appears
2735 : // (and the assumption is) it is always a proportional font. Then we
2736 : // always use 2 points smaller than what the browser has defined as
2737 : // the default proportional font.
2738 : case LookAndFeel::eFont_Field:
2739 : case LookAndFeel::eFont_Button:
2740 : case LookAndFeel::eFont_List:
2741 : // Assumption: system defined font is proportional
2742 : systemFont.size =
2743 : NS_MAX(defaultVariableFont->size -
2744 : nsPresContext::CSSPointsToAppUnits(2), 0);
2745 : break;
2746 : }
2747 : #endif
2748 : }
2749 : }
2750 :
2751 : // font-family: string list, enum, inherit
2752 0 : const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
2753 0 : NS_ASSERTION(eCSSUnit_Enumerated != familyValue->GetUnit(),
2754 : "system fonts should not be in mFamily anymore");
2755 0 : if (eCSSUnit_Families == familyValue->GetUnit()) {
2756 : // set the correct font if we are using DocumentFonts OR we are overriding for XUL
2757 : // MJA: bug 31816
2758 0 : if (aGenericFontID == kGenericFont_NONE) {
2759 : // only bother appending fallback fonts if this isn't a fallback generic font itself
2760 0 : if (!aFont->mFont.name.IsEmpty())
2761 0 : aFont->mFont.name.Append((PRUnichar)',');
2762 : // defaultVariableFont.name should always be "serif" or "sans-serif".
2763 0 : aFont->mFont.name.Append(defaultVariableFont->name);
2764 : }
2765 0 : aFont->mFont.systemFont = false;
2766 : // Technically this is redundant with the code below, but it's good
2767 : // to have since we'll still want it once we get rid of
2768 : // SetGenericFont (bug 380915).
2769 0 : aFont->mGenericID = aGenericFontID;
2770 : }
2771 0 : else if (eCSSUnit_System_Font == familyValue->GetUnit()) {
2772 0 : aFont->mFont.name = systemFont.name;
2773 0 : aFont->mFont.systemFont = true;
2774 0 : aFont->mGenericID = kGenericFont_NONE;
2775 : }
2776 0 : else if (eCSSUnit_Inherit == familyValue->GetUnit()) {
2777 0 : aCanStoreInRuleTree = false;
2778 0 : aFont->mFont.name = aParentFont->mFont.name;
2779 0 : aFont->mFont.systemFont = aParentFont->mFont.systemFont;
2780 0 : aFont->mGenericID = aParentFont->mGenericID;
2781 : }
2782 0 : else if (eCSSUnit_Initial == familyValue->GetUnit()) {
2783 0 : aFont->mFont.name = defaultVariableFont->name;
2784 0 : aFont->mFont.systemFont = defaultVariableFont->systemFont;
2785 0 : aFont->mGenericID = kGenericFont_NONE;
2786 : }
2787 :
2788 : // When we're in the loop in SetGenericFont, we must ensure that we
2789 : // always keep aFont->mFlags set to the correct generic. But we have
2790 : // to be careful not to touch it when we're called directly from
2791 : // ComputeFontData, because we could have a start struct.
2792 0 : if (aGenericFontID != kGenericFont_NONE) {
2793 0 : aFont->mGenericID = aGenericFontID;
2794 : }
2795 :
2796 : // font-style: enum, inherit, initial, -moz-system-font
2797 0 : SetDiscrete(*aRuleData->ValueForFontStyle(),
2798 : aFont->mFont.style, aCanStoreInRuleTree,
2799 : SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT,
2800 : aParentFont->mFont.style,
2801 : defaultVariableFont->style,
2802 0 : 0, 0, 0, systemFont.style);
2803 :
2804 : // font-variant: enum, inherit, initial, -moz-system-font
2805 0 : SetDiscrete(*aRuleData->ValueForFontVariant(),
2806 : aFont->mFont.variant, aCanStoreInRuleTree,
2807 : SETDSC_ENUMERATED | SETDSC_SYSTEM_FONT,
2808 : aParentFont->mFont.variant,
2809 : defaultVariableFont->variant,
2810 0 : 0, 0, 0, systemFont.variant);
2811 :
2812 : // font-weight: int, enum, inherit, initial, -moz-system-font
2813 : // special handling for enum
2814 0 : const nsCSSValue* weightValue = aRuleData->ValueForFontWeight();
2815 0 : if (eCSSUnit_Enumerated == weightValue->GetUnit()) {
2816 0 : PRInt32 value = weightValue->GetIntValue();
2817 0 : switch (value) {
2818 : case NS_STYLE_FONT_WEIGHT_NORMAL:
2819 : case NS_STYLE_FONT_WEIGHT_BOLD:
2820 0 : aFont->mFont.weight = value;
2821 0 : break;
2822 : case NS_STYLE_FONT_WEIGHT_BOLDER: {
2823 0 : aCanStoreInRuleTree = false;
2824 0 : PRInt32 inheritedValue = aParentFont->mFont.weight;
2825 0 : if (inheritedValue <= 300) {
2826 0 : aFont->mFont.weight = 400;
2827 0 : } else if (inheritedValue <= 500) {
2828 0 : aFont->mFont.weight = 700;
2829 : } else {
2830 0 : aFont->mFont.weight = 900;
2831 : }
2832 0 : break;
2833 : }
2834 : case NS_STYLE_FONT_WEIGHT_LIGHTER: {
2835 0 : aCanStoreInRuleTree = false;
2836 0 : PRInt32 inheritedValue = aParentFont->mFont.weight;
2837 0 : if (inheritedValue < 600) {
2838 0 : aFont->mFont.weight = 100;
2839 0 : } else if (inheritedValue < 800) {
2840 0 : aFont->mFont.weight = 400;
2841 : } else {
2842 0 : aFont->mFont.weight = 700;
2843 : }
2844 0 : break;
2845 : }
2846 : }
2847 : } else
2848 : SetDiscrete(*weightValue, aFont->mFont.weight, aCanStoreInRuleTree,
2849 : SETDSC_INTEGER | SETDSC_SYSTEM_FONT,
2850 : aParentFont->mFont.weight,
2851 : defaultVariableFont->weight,
2852 0 : 0, 0, 0, systemFont.weight);
2853 :
2854 : // font-stretch: enum, inherit, initial, -moz-system-font
2855 0 : SetDiscrete(*aRuleData->ValueForFontStretch(),
2856 : aFont->mFont.stretch, aCanStoreInRuleTree,
2857 : SETDSC_SYSTEM_FONT | SETDSC_ENUMERATED,
2858 : aParentFont->mFont.stretch,
2859 : defaultVariableFont->stretch,
2860 0 : 0, 0, 0, systemFont.stretch);
2861 :
2862 : // Compute scriptlevel, scriptminsize and scriptsizemultiplier now so
2863 : // they're available for font-size computation.
2864 :
2865 : // -moz-script-min-size: length
2866 0 : const nsCSSValue* scriptMinSizeValue = aRuleData->ValueForScriptMinSize();
2867 0 : if (scriptMinSizeValue->IsLengthUnit()) {
2868 : // scriptminsize in font units (em, ex) has to be interpreted relative
2869 : // to the parent font, or the size definitions are circular and we
2870 : //
2871 : aFont->mScriptMinSize =
2872 : CalcLengthWith(*scriptMinSizeValue, aParentFont->mSize,
2873 : aParentFont,
2874 : nsnull, aPresContext, atRoot, true,
2875 0 : aCanStoreInRuleTree);
2876 : }
2877 :
2878 : // -moz-script-size-multiplier: factor, inherit, initial
2879 0 : SetFactor(*aRuleData->ValueForScriptSizeMultiplier(),
2880 : aFont->mScriptSizeMultiplier,
2881 : aCanStoreInRuleTree, aParentFont->mScriptSizeMultiplier,
2882 : NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER,
2883 0 : SETFCT_POSITIVE);
2884 :
2885 : // -moz-script-level: integer, number, inherit
2886 0 : const nsCSSValue* scriptLevelValue = aRuleData->ValueForScriptLevel();
2887 0 : if (eCSSUnit_Integer == scriptLevelValue->GetUnit()) {
2888 : // "relative"
2889 0 : aFont->mScriptLevel = ClampTo8Bit(aParentFont->mScriptLevel + scriptLevelValue->GetIntValue());
2890 : }
2891 0 : else if (eCSSUnit_Number == scriptLevelValue->GetUnit()) {
2892 : // "absolute"
2893 0 : aFont->mScriptLevel = ClampTo8Bit(PRInt32(scriptLevelValue->GetFloatValue()));
2894 : }
2895 0 : else if (eCSSUnit_Inherit == scriptLevelValue->GetUnit()) {
2896 0 : aCanStoreInRuleTree = false;
2897 0 : aFont->mScriptLevel = aParentFont->mScriptLevel;
2898 : }
2899 0 : else if (eCSSUnit_Initial == scriptLevelValue->GetUnit()) {
2900 0 : aFont->mScriptLevel = 0;
2901 : }
2902 :
2903 : // font-feature-settings
2904 : const nsCSSValue* featureSettingsValue =
2905 0 : aRuleData->ValueForFontFeatureSettings();
2906 0 : if (eCSSUnit_Inherit == featureSettingsValue->GetUnit()) {
2907 0 : aCanStoreInRuleTree = false;
2908 0 : aFont->mFont.featureSettings = aParentFont->mFont.featureSettings;
2909 0 : } else if (eCSSUnit_Normal == featureSettingsValue->GetUnit() ||
2910 0 : eCSSUnit_Initial == featureSettingsValue->GetUnit()) {
2911 0 : aFont->mFont.featureSettings.Truncate();
2912 0 : } else if (eCSSUnit_System_Font == featureSettingsValue->GetUnit()) {
2913 0 : aFont->mFont.featureSettings = systemFont.featureSettings;
2914 0 : } else if (eCSSUnit_String == featureSettingsValue->GetUnit()) {
2915 0 : featureSettingsValue->GetStringValue(aFont->mFont.featureSettings);
2916 : }
2917 :
2918 : // font-language-override
2919 : const nsCSSValue* languageOverrideValue =
2920 0 : aRuleData->ValueForFontLanguageOverride();
2921 0 : if (eCSSUnit_Inherit == languageOverrideValue->GetUnit()) {
2922 0 : aCanStoreInRuleTree = false;
2923 0 : aFont->mFont.languageOverride = aParentFont->mFont.languageOverride;
2924 0 : } else if (eCSSUnit_Normal == languageOverrideValue->GetUnit() ||
2925 0 : eCSSUnit_Initial == languageOverrideValue->GetUnit()) {
2926 0 : aFont->mFont.languageOverride.Truncate();
2927 0 : } else if (eCSSUnit_System_Font == languageOverrideValue->GetUnit()) {
2928 0 : aFont->mFont.languageOverride = systemFont.languageOverride;
2929 0 : } else if (eCSSUnit_String == languageOverrideValue->GetUnit()) {
2930 0 : languageOverrideValue->GetStringValue(aFont->mFont.languageOverride);
2931 : }
2932 :
2933 : // font-size: enum, length, percent, inherit
2934 0 : nscoord scriptLevelAdjustedParentSize = aParentFont->mSize;
2935 : nscoord scriptLevelAdjustedUnconstrainedParentSize;
2936 : scriptLevelAdjustedParentSize =
2937 : ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
2938 0 : &scriptLevelAdjustedUnconstrainedParentSize);
2939 0 : NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
2940 : "If we have a start struct, we should have reset everything coming in here");
2941 : SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
2942 : &aFont->mSize,
2943 : systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
2944 0 : aUsedStartStruct, atRoot, aCanStoreInRuleTree);
2945 0 : if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize &&
2946 : scriptLevelAdjustedParentSize == scriptLevelAdjustedUnconstrainedParentSize) {
2947 : // Fast path: we have not been affected by scriptminsize so we don't
2948 : // need to call SetFontSize again to compute the
2949 : // scriptminsize-unconstrained size. This is OK even if we have a
2950 : // start struct, because if we have a start struct then 'font-size'
2951 : // was specified and so scriptminsize has no effect.
2952 0 : aFont->mScriptUnconstrainedSize = aFont->mSize;
2953 : } else {
2954 : SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
2955 : &aFont->mScriptUnconstrainedSize,
2956 : systemFont, aParentFont->mScriptUnconstrainedSize,
2957 : scriptLevelAdjustedUnconstrainedParentSize,
2958 0 : aUsedStartStruct, atRoot, aCanStoreInRuleTree);
2959 : }
2960 0 : NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
2961 : "scriptminsize should never be making things bigger");
2962 :
2963 0 : nscoord fontSize = aFont->mSize;
2964 :
2965 : // enforce the user' specified minimum font-size on the value that we expose
2966 : // (but don't change font-size:0, since that would unhide hidden text)
2967 0 : if (fontSize > 0) {
2968 0 : nscoord minFontSize = aPresContext->MinFontSize(aFont->mLanguage);
2969 0 : if (minFontSize < 0) {
2970 0 : minFontSize = 0;
2971 : }
2972 0 : if (fontSize < minFontSize && !aPresContext->IsChrome()) {
2973 : // override the minimum font-size constraint
2974 0 : fontSize = minFontSize;
2975 : }
2976 : }
2977 0 : aFont->mFont.size = fontSize;
2978 :
2979 : // font-size-adjust: number, none, inherit, initial, -moz-system-font
2980 0 : const nsCSSValue* sizeAdjustValue = aRuleData->ValueForFontSizeAdjust();
2981 0 : if (eCSSUnit_System_Font == sizeAdjustValue->GetUnit()) {
2982 0 : aFont->mFont.sizeAdjust = systemFont.sizeAdjust;
2983 : } else
2984 : SetFactor(*sizeAdjustValue, aFont->mFont.sizeAdjust,
2985 : aCanStoreInRuleTree, aParentFont->mFont.sizeAdjust, 0.0f,
2986 0 : SETFCT_NONE);
2987 0 : }
2988 :
2989 : // This should die (bug 380915).
2990 : //
2991 : // SetGenericFont:
2992 : // - backtrack to an ancestor with the same generic font name (possibly
2993 : // up to the root where default values come from the presentation context)
2994 : // - re-apply cascading rules from there without caching intermediate values
2995 : /* static */ void
2996 0 : nsRuleNode::SetGenericFont(nsPresContext* aPresContext,
2997 : nsStyleContext* aContext,
2998 : PRUint8 aGenericFontID,
2999 : nsStyleFont* aFont)
3000 : {
3001 : // walk up the contexts until a context with the desired generic font
3002 0 : nsAutoTArray<nsStyleContext*, 8> contextPath;
3003 0 : contextPath.AppendElement(aContext);
3004 0 : nsStyleContext* higherContext = aContext->GetParent();
3005 0 : while (higherContext) {
3006 0 : if (higherContext->GetStyleFont()->mGenericID == aGenericFontID) {
3007 : // done walking up the higher contexts
3008 0 : break;
3009 : }
3010 0 : contextPath.AppendElement(higherContext);
3011 0 : higherContext = higherContext->GetParent();
3012 : }
3013 :
3014 : // re-apply the cascading rules, starting from the higher context
3015 :
3016 : // If we stopped earlier because we reached the root of the style tree,
3017 : // we will start with the default generic font from the presentation
3018 : // context. Otherwise we start with the higher context.
3019 : const nsFont* defaultFont =
3020 0 : aPresContext->GetDefaultFont(aGenericFontID, aFont->mLanguage);
3021 0 : nsStyleFont parentFont(*defaultFont, aPresContext);
3022 0 : if (higherContext) {
3023 0 : const nsStyleFont* tmpFont = higherContext->GetStyleFont();
3024 0 : parentFont = *tmpFont;
3025 : }
3026 0 : *aFont = parentFont;
3027 :
3028 : bool dummy;
3029 0 : PRUint32 fontBit = nsCachedStyleData::GetBitForSID(eStyleStruct_Font);
3030 :
3031 : // use placement new[] on the result of alloca() to allocate a
3032 : // variable-sized stack array, including execution of constructors,
3033 : // and use an RAII class to run the destructors too.
3034 0 : size_t nprops = nsCSSProps::PropertyCountInStruct(eStyleStruct_Font);
3035 0 : void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
3036 :
3037 0 : for (PRInt32 i = contextPath.Length() - 1; i >= 0; --i) {
3038 0 : nsStyleContext* context = contextPath[i];
3039 0 : AutoCSSValueArray dataArray(dataStorage, nprops);
3040 :
3041 : nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Font), dataArray.get(),
3042 0 : aPresContext, context);
3043 0 : ruleData.mValueOffsets[eStyleStruct_Font] = 0;
3044 :
3045 : // Trimmed down version of ::WalkRuleTree() to re-apply the style rules
3046 : // Note that we *do* need to do this for our own data, since what is
3047 : // in |fontData| in ComputeFontData is only for the rules below
3048 : // aStartStruct.
3049 0 : for (nsRuleNode* ruleNode = context->GetRuleNode(); ruleNode;
3050 : ruleNode = ruleNode->GetParent()) {
3051 0 : if (ruleNode->mNoneBits & fontBit)
3052 : // no more font rules on this branch, get out
3053 0 : break;
3054 :
3055 0 : nsIStyleRule *rule = ruleNode->GetRule();
3056 0 : if (rule) {
3057 0 : ruleData.mLevel = ruleNode->GetLevel();
3058 0 : ruleData.mIsImportantRule = ruleNode->IsImportantRule();
3059 0 : rule->MapRuleInfoInto(&ruleData);
3060 : }
3061 : }
3062 :
3063 : // Compute the delta from the information that the rules specified
3064 :
3065 : // Avoid unnecessary operations in SetFont(). But we care if it's
3066 : // the final value that we're computing.
3067 0 : if (i != 0)
3068 0 : ruleData.ValueForFontFamily()->Reset();
3069 :
3070 : nsRuleNode::SetFont(aPresContext, context,
3071 : aGenericFontID, &ruleData, &parentFont, aFont,
3072 0 : false, dummy);
3073 :
3074 : // XXX Not sure if we need to do this here
3075 : // If we have a post-resolve callback, handle that now.
3076 0 : if (ruleData.mPostResolveCallback)
3077 0 : (ruleData.mPostResolveCallback)(aFont, &ruleData);
3078 :
3079 0 : parentFont = *aFont;
3080 : }
3081 0 : }
3082 :
3083 0 : static bool ExtractGeneric(const nsString& aFamily, bool aGeneric,
3084 : void *aData)
3085 : {
3086 0 : nsAutoString *data = static_cast<nsAutoString*>(aData);
3087 :
3088 0 : if (aGeneric) {
3089 0 : *data = aFamily;
3090 0 : return false; // stop enumeration
3091 : }
3092 0 : return true;
3093 : }
3094 :
3095 : const void*
3096 0 : nsRuleNode::ComputeFontData(void* aStartStruct,
3097 : const nsRuleData* aRuleData,
3098 : nsStyleContext* aContext,
3099 : nsRuleNode* aHighestNode,
3100 : const RuleDetail aRuleDetail,
3101 : const bool aCanStoreInRuleTree)
3102 : {
3103 0 : COMPUTE_START_INHERITED(Font, (mPresContext), font, parentFont)
3104 :
3105 : // NOTE: The |aRuleDetail| passed in is a little bit conservative due
3106 : // to the -moz-system-font property. We really don't need to consider
3107 : // it here in determining whether to cache in the rule tree. However,
3108 : // we do need to consider it in WalkRuleTree when deciding whether to
3109 : // walk further up the tree. So this means that when the font struct
3110 : // is fully specified using *longhand* properties (excluding
3111 : // -moz-system-font), we won't cache in the rule tree even though we
3112 : // could. However, it's pretty unlikely authors will do that
3113 : // (although there is a pretty good chance they'll fully specify it
3114 : // using the 'font' shorthand).
3115 :
3116 : bool useDocumentFonts =
3117 0 : mPresContext->GetCachedBoolPref(kPresContext_UseDocumentFonts);
3118 :
3119 : // See if we are in the chrome
3120 : // We only need to know this to determine if we have to use the
3121 : // document fonts (overriding the useDocumentFonts flag).
3122 0 : if (!useDocumentFonts && mPresContext->IsChrome()) {
3123 : // if we are not using document fonts, but this is a XUL document,
3124 : // then we use the document fonts anyway
3125 0 : useDocumentFonts = true;
3126 : }
3127 :
3128 : // Figure out if we are a generic font
3129 0 : PRUint8 generic = kGenericFont_NONE;
3130 : // XXXldb What if we would have had a string if we hadn't been doing
3131 : // the optimization with a non-null aStartStruct?
3132 0 : const nsCSSValue* familyValue = aRuleData->ValueForFontFamily();
3133 0 : if (eCSSUnit_Families == familyValue->GetUnit()) {
3134 0 : familyValue->GetStringValue(font->mFont.name);
3135 : // XXXldb Do we want to extract the generic for this if it's not only a
3136 : // generic?
3137 0 : nsFont::GetGenericID(font->mFont.name, &generic);
3138 :
3139 : // If we aren't allowed to use document fonts, then we are only entitled
3140 : // to use the user's default variable-width font and fixed-width font
3141 0 : if (!useDocumentFonts) {
3142 : // Extract the generic from the specified font family...
3143 0 : nsAutoString genericName;
3144 0 : if (!font->mFont.EnumerateFamilies(ExtractGeneric, &genericName)) {
3145 : // The specified font had a generic family.
3146 0 : font->mFont.name = genericName;
3147 0 : nsFont::GetGenericID(genericName, &generic);
3148 :
3149 : // ... and only use it if it's -moz-fixed or monospace
3150 0 : if (generic != kGenericFont_moz_fixed &&
3151 : generic != kGenericFont_monospace) {
3152 0 : font->mFont.name.Truncate();
3153 0 : generic = kGenericFont_NONE;
3154 : }
3155 : } else {
3156 : // The specified font did not have a generic family.
3157 0 : font->mFont.name.Truncate();
3158 0 : generic = kGenericFont_NONE;
3159 : }
3160 : }
3161 : }
3162 :
3163 : // Now compute our font struct
3164 0 : if (generic == kGenericFont_NONE) {
3165 : // continue the normal processing
3166 : nsRuleNode::SetFont(mPresContext, aContext, generic,
3167 : aRuleData, parentFont, font,
3168 0 : aStartStruct != nsnull, canStoreInRuleTree);
3169 : }
3170 : else {
3171 : // re-calculate the font as a generic font
3172 0 : canStoreInRuleTree = false;
3173 : nsRuleNode::SetGenericFont(mPresContext, aContext, generic,
3174 0 : font);
3175 : }
3176 :
3177 0 : COMPUTE_END_INHERITED(Font, font)
3178 : }
3179 :
3180 : template <typename T>
3181 0 : inline PRUint32 ListLength(const T* aList)
3182 : {
3183 0 : PRUint32 len = 0;
3184 0 : while (aList) {
3185 0 : len++;
3186 0 : aList = aList->mNext;
3187 : }
3188 0 : return len;
3189 : }
3190 :
3191 :
3192 :
3193 : already_AddRefed<nsCSSShadowArray>
3194 0 : nsRuleNode::GetShadowData(const nsCSSValueList* aList,
3195 : nsStyleContext* aContext,
3196 : bool aIsBoxShadow,
3197 : bool& canStoreInRuleTree)
3198 : {
3199 0 : PRUint32 arrayLength = ListLength(aList);
3200 :
3201 0 : NS_ABORT_IF_FALSE(arrayLength > 0,
3202 : "Non-null text-shadow list, yet we counted 0 items.");
3203 0 : nsCSSShadowArray* shadowList = new(arrayLength) nsCSSShadowArray(arrayLength);
3204 :
3205 0 : if (!shadowList)
3206 0 : return nsnull;
3207 :
3208 0 : nsStyleCoord tempCoord;
3209 : bool unitOK;
3210 0 : for (nsCSSShadowItem* item = shadowList->ShadowAt(0);
3211 : aList;
3212 : aList = aList->mNext, ++item) {
3213 0 : NS_ABORT_IF_FALSE(aList->mValue.GetUnit() == eCSSUnit_Array,
3214 : "expecting a plain array value");
3215 0 : nsCSSValue::Array *arr = aList->mValue.GetArrayValue();
3216 : // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
3217 0 : unitOK = SetCoord(arr->Item(0), tempCoord, nsStyleCoord(),
3218 : SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
3219 0 : aContext, mPresContext, canStoreInRuleTree);
3220 0 : NS_ASSERTION(unitOK, "unexpected unit");
3221 0 : item->mXOffset = tempCoord.GetCoordValue();
3222 :
3223 0 : unitOK = SetCoord(arr->Item(1), tempCoord, nsStyleCoord(),
3224 : SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
3225 0 : aContext, mPresContext, canStoreInRuleTree);
3226 0 : NS_ASSERTION(unitOK, "unexpected unit");
3227 0 : item->mYOffset = tempCoord.GetCoordValue();
3228 :
3229 : // Blur radius is optional in the current box-shadow spec
3230 0 : if (arr->Item(2).GetUnit() != eCSSUnit_Null) {
3231 0 : unitOK = SetCoord(arr->Item(2), tempCoord, nsStyleCoord(),
3232 : SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY |
3233 : SETCOORD_CALC_CLAMP_NONNEGATIVE,
3234 0 : aContext, mPresContext, canStoreInRuleTree);
3235 0 : NS_ASSERTION(unitOK, "unexpected unit");
3236 0 : item->mRadius = tempCoord.GetCoordValue();
3237 : } else {
3238 0 : item->mRadius = 0;
3239 : }
3240 :
3241 : // Find the spread radius
3242 0 : if (aIsBoxShadow && arr->Item(3).GetUnit() != eCSSUnit_Null) {
3243 0 : unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(),
3244 : SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
3245 0 : aContext, mPresContext, canStoreInRuleTree);
3246 0 : NS_ASSERTION(unitOK, "unexpected unit");
3247 0 : item->mSpread = tempCoord.GetCoordValue();
3248 : } else {
3249 0 : item->mSpread = 0;
3250 : }
3251 :
3252 0 : if (arr->Item(4).GetUnit() != eCSSUnit_Null) {
3253 0 : item->mHasColor = true;
3254 : // 2nd argument can be bogus since inherit is not a valid color
3255 0 : unitOK = SetColor(arr->Item(4), 0, mPresContext, aContext, item->mColor,
3256 0 : canStoreInRuleTree);
3257 0 : NS_ASSERTION(unitOK, "unexpected unit");
3258 : }
3259 :
3260 0 : if (aIsBoxShadow && arr->Item(5).GetUnit() == eCSSUnit_Enumerated) {
3261 0 : NS_ASSERTION(arr->Item(5).GetIntValue() == NS_STYLE_BOX_SHADOW_INSET,
3262 : "invalid keyword type for box shadow");
3263 0 : item->mInset = true;
3264 : } else {
3265 0 : item->mInset = false;
3266 : }
3267 : }
3268 :
3269 0 : NS_ADDREF(shadowList);
3270 0 : return shadowList;
3271 : }
3272 :
3273 : const void*
3274 0 : nsRuleNode::ComputeTextData(void* aStartStruct,
3275 : const nsRuleData* aRuleData,
3276 : nsStyleContext* aContext,
3277 : nsRuleNode* aHighestNode,
3278 : const RuleDetail aRuleDetail,
3279 : const bool aCanStoreInRuleTree)
3280 : {
3281 0 : COMPUTE_START_INHERITED(Text, (), text, parentText)
3282 :
3283 : // tab-size: integer, inherit
3284 0 : SetDiscrete(*aRuleData->ValueForTabSize(),
3285 : text->mTabSize, canStoreInRuleTree,
3286 : SETDSC_INTEGER, parentText->mTabSize,
3287 0 : NS_STYLE_TABSIZE_INITIAL, 0, 0, 0, 0);
3288 :
3289 : // letter-spacing: normal, length, inherit
3290 0 : SetCoord(*aRuleData->ValueForLetterSpacing(),
3291 : text->mLetterSpacing, parentText->mLetterSpacing,
3292 : SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
3293 : SETCOORD_CALC_LENGTH_ONLY,
3294 0 : aContext, mPresContext, canStoreInRuleTree);
3295 :
3296 : // text-shadow: none, list, inherit, initial
3297 0 : const nsCSSValue* textShadowValue = aRuleData->ValueForTextShadow();
3298 0 : if (textShadowValue->GetUnit() != eCSSUnit_Null) {
3299 0 : text->mTextShadow = nsnull;
3300 :
3301 : // Don't need to handle none/initial explicitly: The above assignment
3302 : // takes care of that
3303 0 : if (textShadowValue->GetUnit() == eCSSUnit_Inherit) {
3304 0 : canStoreInRuleTree = false;
3305 0 : text->mTextShadow = parentText->mTextShadow;
3306 0 : } else if (textShadowValue->GetUnit() == eCSSUnit_List ||
3307 0 : textShadowValue->GetUnit() == eCSSUnit_ListDep) {
3308 : // List of arrays
3309 : text->mTextShadow = GetShadowData(textShadowValue->GetListValue(),
3310 0 : aContext, false, canStoreInRuleTree);
3311 : }
3312 : }
3313 :
3314 : // line-height: normal, number, length, percent, inherit
3315 0 : const nsCSSValue* lineHeightValue = aRuleData->ValueForLineHeight();
3316 0 : if (eCSSUnit_Percent == lineHeightValue->GetUnit()) {
3317 0 : canStoreInRuleTree = false;
3318 : // Use |mFont.size| to pick up minimum font size.
3319 : text->mLineHeight.SetCoordValue(
3320 0 : nscoord(float(aContext->GetStyleFont()->mFont.size) *
3321 0 : lineHeightValue->GetPercentValue()));
3322 : }
3323 0 : else if (eCSSUnit_Initial == lineHeightValue->GetUnit() ||
3324 0 : eCSSUnit_System_Font == lineHeightValue->GetUnit()) {
3325 0 : text->mLineHeight.SetNormalValue();
3326 : }
3327 : else {
3328 : SetCoord(*lineHeightValue, text->mLineHeight, parentText->mLineHeight,
3329 : SETCOORD_LEH | SETCOORD_FACTOR | SETCOORD_NORMAL,
3330 0 : aContext, mPresContext, canStoreInRuleTree);
3331 0 : if (lineHeightValue->IsLengthUnit() &&
3332 0 : !lineHeightValue->IsRelativeLengthUnit()) {
3333 : nscoord lh = nsStyleFont::ZoomText(mPresContext,
3334 0 : text->mLineHeight.GetCoordValue());
3335 :
3336 0 : canStoreInRuleTree = false;
3337 0 : const nsStyleFont *font = aContext->GetStyleFont();
3338 0 : nscoord minimumFontSize = mPresContext->MinFontSize(font->mLanguage);
3339 :
3340 0 : if (minimumFontSize > 0 && !mPresContext->IsChrome()) {
3341 0 : if (font->mSize != 0) {
3342 0 : lh = nscoord(float(lh) * float(font->mFont.size) / float(font->mSize));
3343 : } else {
3344 0 : lh = minimumFontSize;
3345 : }
3346 : }
3347 0 : text->mLineHeight.SetCoordValue(lh);
3348 : }
3349 : }
3350 :
3351 :
3352 : // text-align: enum, string, inherit, initial
3353 0 : const nsCSSValue* textAlignValue = aRuleData->ValueForTextAlign();
3354 0 : if (eCSSUnit_String == textAlignValue->GetUnit()) {
3355 0 : NS_NOTYETIMPLEMENTED("align string");
3356 0 : } else if (eCSSUnit_Enumerated == textAlignValue->GetUnit() &&
3357 : NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT ==
3358 0 : textAlignValue->GetIntValue()) {
3359 0 : canStoreInRuleTree = false;
3360 0 : PRUint8 parentAlign = parentText->mTextAlign;
3361 : text->mTextAlign = (NS_STYLE_TEXT_ALIGN_DEFAULT == parentAlign) ?
3362 0 : NS_STYLE_TEXT_ALIGN_CENTER : parentAlign;
3363 : } else
3364 : SetDiscrete(*textAlignValue, text->mTextAlign, canStoreInRuleTree,
3365 : SETDSC_ENUMERATED, parentText->mTextAlign,
3366 : NS_STYLE_TEXT_ALIGN_DEFAULT,
3367 0 : 0, 0, 0, 0);
3368 :
3369 : // text-align-last: enum, inherit, initial
3370 0 : SetDiscrete(*aRuleData->ValueForTextAlignLast(), text->mTextAlignLast,
3371 : canStoreInRuleTree, SETDSC_ENUMERATED, parentText->mTextAlignLast,
3372 0 : NS_STYLE_TEXT_ALIGN_AUTO, 0, 0, 0, 0);
3373 :
3374 : // text-indent: length, percent, calc, inherit, initial
3375 0 : SetCoord(*aRuleData->ValueForTextIndent(), text->mTextIndent, parentText->mTextIndent,
3376 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC,
3377 0 : aContext, mPresContext, canStoreInRuleTree);
3378 :
3379 : // text-transform: enum, inherit, initial
3380 0 : SetDiscrete(*aRuleData->ValueForTextTransform(), text->mTextTransform, canStoreInRuleTree,
3381 : SETDSC_ENUMERATED, parentText->mTextTransform,
3382 0 : NS_STYLE_TEXT_TRANSFORM_NONE, 0, 0, 0, 0);
3383 :
3384 : // white-space: enum, inherit, initial
3385 0 : SetDiscrete(*aRuleData->ValueForWhiteSpace(), text->mWhiteSpace, canStoreInRuleTree,
3386 : SETDSC_ENUMERATED, parentText->mWhiteSpace,
3387 0 : NS_STYLE_WHITESPACE_NORMAL, 0, 0, 0, 0);
3388 :
3389 : // word-spacing: normal, length, inherit
3390 0 : nsStyleCoord tempCoord;
3391 0 : const nsCSSValue* wordSpacingValue = aRuleData->ValueForWordSpacing();
3392 0 : if (SetCoord(*wordSpacingValue, tempCoord,
3393 : nsStyleCoord(parentText->mWordSpacing,
3394 : nsStyleCoord::CoordConstructor),
3395 : SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
3396 : SETCOORD_CALC_LENGTH_ONLY,
3397 0 : aContext, mPresContext, canStoreInRuleTree)) {
3398 0 : if (tempCoord.GetUnit() == eStyleUnit_Coord) {
3399 0 : text->mWordSpacing = tempCoord.GetCoordValue();
3400 0 : } else if (tempCoord.GetUnit() == eStyleUnit_Normal) {
3401 0 : text->mWordSpacing = 0;
3402 : } else {
3403 0 : NS_NOTREACHED("unexpected unit");
3404 : }
3405 : } else {
3406 0 : NS_ASSERTION(wordSpacingValue->GetUnit() == eCSSUnit_Null,
3407 : "unexpected unit");
3408 : }
3409 :
3410 : // word-wrap: enum, inherit, initial
3411 0 : SetDiscrete(*aRuleData->ValueForWordWrap(), text->mWordWrap, canStoreInRuleTree,
3412 : SETDSC_ENUMERATED, parentText->mWordWrap,
3413 0 : NS_STYLE_WORDWRAP_NORMAL, 0, 0, 0, 0);
3414 :
3415 : // hyphens: enum, inherit, initial
3416 0 : SetDiscrete(*aRuleData->ValueForHyphens(), text->mHyphens, canStoreInRuleTree,
3417 : SETDSC_ENUMERATED, parentText->mHyphens,
3418 0 : NS_STYLE_HYPHENS_MANUAL, 0, 0, 0, 0);
3419 :
3420 : // text-size-adjust: none, auto, inherit, initial
3421 0 : SetDiscrete(*aRuleData->ValueForTextSizeAdjust(), text->mTextSizeAdjust,
3422 : canStoreInRuleTree, SETDSC_NONE | SETDSC_AUTO,
3423 : parentText->mTextSizeAdjust,
3424 : NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // initial value
3425 : NS_STYLE_TEXT_SIZE_ADJUST_AUTO, // auto value
3426 : NS_STYLE_TEXT_SIZE_ADJUST_NONE, // none value
3427 0 : 0, 0);
3428 :
3429 0 : COMPUTE_END_INHERITED(Text, text)
3430 : }
3431 :
3432 : const void*
3433 0 : nsRuleNode::ComputeTextResetData(void* aStartStruct,
3434 : const nsRuleData* aRuleData,
3435 : nsStyleContext* aContext,
3436 : nsRuleNode* aHighestNode,
3437 : const RuleDetail aRuleDetail,
3438 : const bool aCanStoreInRuleTree)
3439 : {
3440 0 : COMPUTE_START_RESET(TextReset, (), text, parentText)
3441 :
3442 : // vertical-align: enum, length, percent, calc, inherit
3443 0 : const nsCSSValue* verticalAlignValue = aRuleData->ValueForVerticalAlign();
3444 0 : if (!SetCoord(*verticalAlignValue, text->mVerticalAlign,
3445 : parentText->mVerticalAlign,
3446 : SETCOORD_LPH | SETCOORD_ENUMERATED | SETCOORD_STORE_CALC,
3447 0 : aContext, mPresContext, canStoreInRuleTree)) {
3448 0 : if (eCSSUnit_Initial == verticalAlignValue->GetUnit()) {
3449 : text->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE,
3450 0 : eStyleUnit_Enumerated);
3451 : }
3452 : }
3453 :
3454 : // text-blink: enum, inherit, initial
3455 0 : SetDiscrete(*aRuleData->ValueForTextBlink(), text->mTextBlink,
3456 : canStoreInRuleTree, SETDSC_ENUMERATED, parentText->mTextBlink,
3457 0 : NS_STYLE_TEXT_BLINK_NONE, 0, 0, 0, 0);
3458 :
3459 : // text-decoration-line: enum (bit field), inherit, initial
3460 : const nsCSSValue* decorationLineValue =
3461 0 : aRuleData->ValueForTextDecorationLine();
3462 0 : if (eCSSUnit_Enumerated == decorationLineValue->GetUnit()) {
3463 0 : PRInt32 td = decorationLineValue->GetIntValue();
3464 0 : text->mTextDecorationLine = td;
3465 0 : if (td & NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS) {
3466 : bool underlineLinks =
3467 0 : mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks);
3468 0 : if (underlineLinks) {
3469 0 : text->mTextDecorationLine |= NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
3470 : }
3471 : else {
3472 0 : text->mTextDecorationLine &= ~NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
3473 : }
3474 : }
3475 0 : } else if (eCSSUnit_Inherit == decorationLineValue->GetUnit()) {
3476 0 : canStoreInRuleTree = false;
3477 0 : text->mTextDecorationLine = parentText->mTextDecorationLine;
3478 0 : } else if (eCSSUnit_Initial == decorationLineValue->GetUnit()) {
3479 0 : text->mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
3480 : }
3481 :
3482 : // text-decoration-color: color, string, enum, inherit, initial
3483 : const nsCSSValue* decorationColorValue =
3484 0 : aRuleData->ValueForTextDecorationColor();
3485 : nscolor decorationColor;
3486 0 : if (eCSSUnit_Inherit == decorationColorValue->GetUnit()) {
3487 0 : canStoreInRuleTree = false;
3488 0 : if (parentContext) {
3489 : bool isForeground;
3490 0 : parentText->GetDecorationColor(decorationColor, isForeground);
3491 0 : if (isForeground) {
3492 0 : text->SetDecorationColor(parentContext->GetStyleColor()->mColor);
3493 : } else {
3494 0 : text->SetDecorationColor(decorationColor);
3495 : }
3496 : } else {
3497 0 : text->SetDecorationColorToForeground();
3498 : }
3499 : }
3500 0 : else if (eCSSUnit_EnumColor == decorationColorValue->GetUnit() &&
3501 0 : decorationColorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
3502 0 : text->SetDecorationColorToForeground();
3503 : }
3504 0 : else if (SetColor(*decorationColorValue, 0, mPresContext, aContext,
3505 0 : decorationColor, canStoreInRuleTree)) {
3506 0 : text->SetDecorationColor(decorationColor);
3507 : }
3508 0 : else if (eCSSUnit_Initial == decorationColorValue->GetUnit() ||
3509 0 : eCSSUnit_Enumerated == decorationColorValue->GetUnit()) {
3510 0 : NS_ABORT_IF_FALSE(eCSSUnit_Enumerated != decorationColorValue->GetUnit() ||
3511 : decorationColorValue->GetIntValue() ==
3512 : NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,
3513 : "unexpected enumerated value");
3514 0 : text->SetDecorationColorToForeground();
3515 : }
3516 :
3517 : // text-decoration-style: enum, inherit, initial
3518 : const nsCSSValue* decorationStyleValue =
3519 0 : aRuleData->ValueForTextDecorationStyle();
3520 0 : if (eCSSUnit_Enumerated == decorationStyleValue->GetUnit()) {
3521 0 : text->SetDecorationStyle(decorationStyleValue->GetIntValue());
3522 0 : } else if (eCSSUnit_Inherit == decorationStyleValue->GetUnit()) {
3523 0 : text->SetDecorationStyle(parentText->GetDecorationStyle());
3524 0 : canStoreInRuleTree = false;
3525 0 : } else if (eCSSUnit_Initial == decorationStyleValue->GetUnit()) {
3526 0 : text->SetDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID);
3527 : }
3528 :
3529 : // text-overflow: enum, string, pair(enum|string), inherit, initial
3530 : const nsCSSValue* textOverflowValue =
3531 0 : aRuleData->ValueForTextOverflow();
3532 0 : if (eCSSUnit_Initial == textOverflowValue->GetUnit()) {
3533 0 : text->mTextOverflow = nsStyleTextOverflow();
3534 0 : } else if (eCSSUnit_Inherit == textOverflowValue->GetUnit()) {
3535 0 : canStoreInRuleTree = false;
3536 0 : text->mTextOverflow = parentText->mTextOverflow;
3537 0 : } else if (eCSSUnit_Enumerated == textOverflowValue->GetUnit()) {
3538 : // A single enumerated value.
3539 : SetDiscrete(*textOverflowValue, text->mTextOverflow.mRight.mType,
3540 : canStoreInRuleTree,
3541 : SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
3542 0 : NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
3543 0 : text->mTextOverflow.mRight.mString.Truncate();
3544 0 : text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
3545 0 : text->mTextOverflow.mLeft.mString.Truncate();
3546 0 : text->mTextOverflow.mLogicalDirections = true;
3547 0 : } else if (eCSSUnit_String == textOverflowValue->GetUnit()) {
3548 : // A single string value.
3549 0 : text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
3550 0 : textOverflowValue->GetStringValue(text->mTextOverflow.mRight.mString);
3551 0 : text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
3552 0 : text->mTextOverflow.mLeft.mString.Truncate();
3553 0 : text->mTextOverflow.mLogicalDirections = true;
3554 0 : } else if (eCSSUnit_Pair == textOverflowValue->GetUnit()) {
3555 : // Two values were specified.
3556 0 : text->mTextOverflow.mLogicalDirections = false;
3557 : const nsCSSValuePair& textOverflowValue =
3558 0 : aRuleData->ValueForTextOverflow()->GetPairValue();
3559 :
3560 0 : const nsCSSValue *textOverflowLeftValue = &textOverflowValue.mXValue;
3561 0 : if (eCSSUnit_Enumerated == textOverflowLeftValue->GetUnit()) {
3562 : SetDiscrete(*textOverflowLeftValue, text->mTextOverflow.mLeft.mType,
3563 : canStoreInRuleTree,
3564 : SETDSC_ENUMERATED, parentText->mTextOverflow.mLeft.mType,
3565 0 : NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
3566 0 : text->mTextOverflow.mLeft.mString.Truncate();
3567 0 : } else if (eCSSUnit_String == textOverflowLeftValue->GetUnit()) {
3568 0 : textOverflowLeftValue->GetStringValue(text->mTextOverflow.mLeft.mString);
3569 0 : text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
3570 : }
3571 :
3572 0 : const nsCSSValue *textOverflowRightValue = &textOverflowValue.mYValue;
3573 0 : if (eCSSUnit_Enumerated == textOverflowRightValue->GetUnit()) {
3574 : SetDiscrete(*textOverflowRightValue, text->mTextOverflow.mRight.mType,
3575 : canStoreInRuleTree,
3576 : SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
3577 0 : NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
3578 0 : text->mTextOverflow.mRight.mString.Truncate();
3579 0 : } else if (eCSSUnit_String == textOverflowRightValue->GetUnit()) {
3580 0 : textOverflowRightValue->GetStringValue(text->mTextOverflow.mRight.mString);
3581 0 : text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
3582 : }
3583 : }
3584 :
3585 : // unicode-bidi: enum, inherit, initial
3586 0 : SetDiscrete(*aRuleData->ValueForUnicodeBidi(), text->mUnicodeBidi, canStoreInRuleTree,
3587 : SETDSC_ENUMERATED, parentText->mUnicodeBidi,
3588 0 : NS_STYLE_UNICODE_BIDI_NORMAL, 0, 0, 0, 0);
3589 :
3590 0 : COMPUTE_END_RESET(TextReset, text)
3591 : }
3592 :
3593 : const void*
3594 0 : nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
3595 : const nsRuleData* aRuleData,
3596 : nsStyleContext* aContext,
3597 : nsRuleNode* aHighestNode,
3598 : const RuleDetail aRuleDetail,
3599 : const bool aCanStoreInRuleTree)
3600 : {
3601 0 : COMPUTE_START_INHERITED(UserInterface, (), ui, parentUI)
3602 :
3603 : // cursor: enum, url, inherit
3604 0 : const nsCSSValue* cursorValue = aRuleData->ValueForCursor();
3605 0 : nsCSSUnit cursorUnit = cursorValue->GetUnit();
3606 0 : if (cursorUnit != eCSSUnit_Null) {
3607 0 : delete [] ui->mCursorArray;
3608 0 : ui->mCursorArray = nsnull;
3609 0 : ui->mCursorArrayLength = 0;
3610 :
3611 0 : if (cursorUnit == eCSSUnit_Inherit) {
3612 0 : canStoreInRuleTree = false;
3613 0 : ui->mCursor = parentUI->mCursor;
3614 0 : ui->CopyCursorArrayFrom(*parentUI);
3615 : }
3616 0 : else if (cursorUnit == eCSSUnit_Initial) {
3617 0 : ui->mCursor = NS_STYLE_CURSOR_AUTO;
3618 : }
3619 : else {
3620 : // The parser will never create a list that is *all* URL values --
3621 : // that's invalid.
3622 0 : NS_ABORT_IF_FALSE(cursorUnit == eCSSUnit_List ||
3623 : cursorUnit == eCSSUnit_ListDep,
3624 : nsPrintfCString(64, "unrecognized cursor unit %d",
3625 : cursorUnit).get());
3626 0 : const nsCSSValueList* list = cursorValue->GetListValue();
3627 0 : const nsCSSValueList* list2 = list;
3628 0 : PRUint32 arrayLength = 0;
3629 0 : for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext)
3630 0 : if (list->mValue.GetArrayValue()->Item(0).GetImageValue())
3631 0 : ++arrayLength;
3632 :
3633 0 : if (arrayLength != 0) {
3634 0 : ui->mCursorArray = new nsCursorImage[arrayLength];
3635 0 : if (ui->mCursorArray) {
3636 0 : ui->mCursorArrayLength = arrayLength;
3637 :
3638 0 : for (nsCursorImage *item = ui->mCursorArray;
3639 0 : list2->mValue.GetUnit() == eCSSUnit_Array;
3640 : list2 = list2->mNext) {
3641 0 : nsCSSValue::Array *arr = list2->mValue.GetArrayValue();
3642 0 : imgIRequest *req = arr->Item(0).GetImageValue();
3643 0 : if (req) {
3644 0 : item->SetImage(req);
3645 0 : if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
3646 0 : item->mHaveHotspot = true;
3647 0 : item->mHotspotX = arr->Item(1).GetFloatValue(),
3648 0 : item->mHotspotY = arr->Item(2).GetFloatValue();
3649 : }
3650 0 : ++item;
3651 : }
3652 : }
3653 : }
3654 : }
3655 :
3656 0 : NS_ASSERTION(list, "Must have non-array value at the end");
3657 0 : NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated,
3658 : "Unexpected fallback value at end of cursor list");
3659 0 : ui->mCursor = list->mValue.GetIntValue();
3660 : }
3661 : }
3662 :
3663 : // user-input: enum, inherit, initial
3664 0 : SetDiscrete(*aRuleData->ValueForUserInput(),
3665 : ui->mUserInput, canStoreInRuleTree,
3666 : SETDSC_ENUMERATED, parentUI->mUserInput,
3667 0 : NS_STYLE_USER_INPUT_AUTO, 0, 0, 0, 0);
3668 :
3669 : // user-modify: enum, inherit, initial
3670 0 : SetDiscrete(*aRuleData->ValueForUserModify(),
3671 : ui->mUserModify, canStoreInRuleTree,
3672 : SETDSC_ENUMERATED, parentUI->mUserModify,
3673 : NS_STYLE_USER_MODIFY_READ_ONLY,
3674 0 : 0, 0, 0, 0);
3675 :
3676 : // user-focus: enum, inherit, initial
3677 0 : SetDiscrete(*aRuleData->ValueForUserFocus(),
3678 : ui->mUserFocus, canStoreInRuleTree,
3679 : SETDSC_ENUMERATED, parentUI->mUserFocus,
3680 0 : NS_STYLE_USER_FOCUS_NONE, 0, 0, 0, 0);
3681 :
3682 0 : COMPUTE_END_INHERITED(UserInterface, ui)
3683 : }
3684 :
3685 : const void*
3686 0 : nsRuleNode::ComputeUIResetData(void* aStartStruct,
3687 : const nsRuleData* aRuleData,
3688 : nsStyleContext* aContext,
3689 : nsRuleNode* aHighestNode,
3690 : const RuleDetail aRuleDetail,
3691 : const bool aCanStoreInRuleTree)
3692 : {
3693 0 : COMPUTE_START_RESET(UIReset, (), ui, parentUI)
3694 :
3695 : // user-select: enum, inherit, initial
3696 0 : SetDiscrete(*aRuleData->ValueForUserSelect(),
3697 : ui->mUserSelect, canStoreInRuleTree,
3698 : SETDSC_ENUMERATED, parentUI->mUserSelect,
3699 0 : NS_STYLE_USER_SELECT_AUTO, 0, 0, 0, 0);
3700 :
3701 : // ime-mode: enum, inherit, initial
3702 0 : SetDiscrete(*aRuleData->ValueForImeMode(),
3703 : ui->mIMEMode, canStoreInRuleTree,
3704 : SETDSC_ENUMERATED, parentUI->mIMEMode,
3705 0 : NS_STYLE_IME_MODE_AUTO, 0, 0, 0, 0);
3706 :
3707 : // force-broken-image-icons: integer, inherit, initial
3708 0 : SetDiscrete(*aRuleData->ValueForForceBrokenImageIcon(),
3709 : ui->mForceBrokenImageIcon,
3710 : canStoreInRuleTree,
3711 : SETDSC_INTEGER,
3712 : parentUI->mForceBrokenImageIcon,
3713 0 : 0, 0, 0, 0, 0);
3714 :
3715 : // -moz-window-shadow: enum, inherit, initial
3716 0 : SetDiscrete(*aRuleData->ValueForWindowShadow(),
3717 : ui->mWindowShadow, canStoreInRuleTree,
3718 : SETDSC_ENUMERATED, parentUI->mWindowShadow,
3719 0 : NS_STYLE_WINDOW_SHADOW_DEFAULT, 0, 0, 0, 0);
3720 :
3721 0 : COMPUTE_END_RESET(UIReset, ui)
3722 : }
3723 :
3724 : // Information about each transition or animation property that is
3725 : // constant.
3726 : struct TransitionPropInfo {
3727 : nsCSSProperty property;
3728 : // Location of the count of the property's computed value.
3729 : PRUint32 nsStyleDisplay::* sdCount;
3730 : };
3731 :
3732 : // Each property's index in this array must match its index in the
3733 : // mutable array |transitionPropData| below.
3734 : static const TransitionPropInfo transitionPropInfo[4] = {
3735 : { eCSSProperty_transition_delay,
3736 : &nsStyleDisplay::mTransitionDelayCount },
3737 : { eCSSProperty_transition_duration,
3738 : &nsStyleDisplay::mTransitionDurationCount },
3739 : { eCSSProperty_transition_property,
3740 : &nsStyleDisplay::mTransitionPropertyCount },
3741 : { eCSSProperty_transition_timing_function,
3742 : &nsStyleDisplay::mTransitionTimingFunctionCount },
3743 : };
3744 :
3745 : // Each property's index in this array must match its index in the
3746 : // mutable array |animationPropData| below.
3747 : static const TransitionPropInfo animationPropInfo[8] = {
3748 : { eCSSProperty_animation_delay,
3749 : &nsStyleDisplay::mAnimationDelayCount },
3750 : { eCSSProperty_animation_duration,
3751 : &nsStyleDisplay::mAnimationDurationCount },
3752 : { eCSSProperty_animation_name,
3753 : &nsStyleDisplay::mAnimationNameCount },
3754 : { eCSSProperty_animation_timing_function,
3755 : &nsStyleDisplay::mAnimationTimingFunctionCount },
3756 : { eCSSProperty_animation_direction,
3757 : &nsStyleDisplay::mAnimationDirectionCount },
3758 : { eCSSProperty_animation_fill_mode,
3759 : &nsStyleDisplay::mAnimationFillModeCount },
3760 : { eCSSProperty_animation_play_state,
3761 : &nsStyleDisplay::mAnimationPlayStateCount },
3762 : { eCSSProperty_animation_iteration_count,
3763 : &nsStyleDisplay::mAnimationIterationCountCount },
3764 : };
3765 :
3766 : // Information about each transition or animation property that changes
3767 : // during ComputeDisplayData.
3768 : struct TransitionPropData {
3769 : const nsCSSValueList *list;
3770 : nsCSSUnit unit;
3771 : PRUint32 num;
3772 : };
3773 :
3774 : static PRUint32
3775 0 : CountTransitionProps(const TransitionPropInfo* aInfo,
3776 : TransitionPropData* aData,
3777 : size_t aLength,
3778 : nsStyleDisplay* aDisplay,
3779 : const nsStyleDisplay* aParentDisplay,
3780 : const nsRuleData* aRuleData,
3781 : bool& aCanStoreInRuleTree)
3782 : {
3783 : // The four transition properties or eight animation properties are
3784 : // stored in nsCSSDisplay in a single array for all properties. The
3785 : // number of transitions is equal to the number of items in the
3786 : // longest property's value. Properties that have fewer values than
3787 : // the longest are filled in by repeating the list. However, this
3788 : // repetition does not extend the computed value of that particular
3789 : // property (for purposes of inheritance, or, in our code, for when
3790 : // other properties are overridden by a more specific rule).
3791 :
3792 : // But actually, since the spec isn't clear yet, we'll fully compute
3793 : // all of them (so we can switch easily later), but only care about
3794 : // the ones up to the number of items for 'transition-property', per
3795 : // http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html .
3796 :
3797 : // Transitions are difficult to handle correctly because of this. For
3798 : // example, we need to handle scenarios such as:
3799 : // * a more general rule specifies transition-property: a, b, c;
3800 : // * a more specific rule overrides as transition-property: d;
3801 : //
3802 : // If only the general rule applied, we would fill in the extra
3803 : // properties (duration, delay, etc) with initial values to create 3
3804 : // fully-specified transitions. But when the more specific rule
3805 : // applies, we should only create a single transition. In order to do
3806 : // this we need to remember which properties were explicitly specified
3807 : // and which ones were just filled in with initial values to get a
3808 : // fully-specified transition, which we do by remembering the number
3809 : // of values for each property.
3810 :
3811 0 : PRUint32 numTransitions = 0;
3812 0 : for (size_t i = 0; i < aLength; ++i) {
3813 0 : const TransitionPropInfo& info = aInfo[i];
3814 0 : TransitionPropData& data = aData[i];
3815 :
3816 : // cache whether any of the properties are specified as 'inherit' so
3817 : // we can use it below
3818 :
3819 0 : const nsCSSValue& value = *aRuleData->ValueFor(info.property);
3820 0 : data.unit = value.GetUnit();
3821 0 : data.list = (value.GetUnit() == eCSSUnit_List ||
3822 0 : value.GetUnit() == eCSSUnit_ListDep)
3823 0 : ? value.GetListValue() : nsnull;
3824 :
3825 : // General algorithm to determine how many total transitions we need
3826 : // to build. For each property:
3827 : // - if there is no value specified in for the property in
3828 : // displayData, use the values from the start struct, but only if
3829 : // they were explicitly specified
3830 : // - if there is a value specified for the property in displayData:
3831 : // - if the value is 'inherit', count the number of values for
3832 : // that property are specified by the parent, but only those
3833 : // that were explicitly specified
3834 : // - otherwise, count the number of values specified in displayData
3835 :
3836 :
3837 : // calculate number of elements
3838 0 : if (data.unit == eCSSUnit_Inherit) {
3839 0 : data.num = aParentDisplay->*(info.sdCount);
3840 0 : aCanStoreInRuleTree = false;
3841 0 : } else if (data.list) {
3842 0 : data.num = ListLength(data.list);
3843 : } else {
3844 0 : data.num = aDisplay->*(info.sdCount);
3845 : }
3846 0 : if (data.num > numTransitions)
3847 0 : numTransitions = data.num;
3848 : }
3849 :
3850 0 : return numTransitions;
3851 : }
3852 :
3853 : static void
3854 0 : ComputeTimingFunction(const nsCSSValue& aValue, nsTimingFunction& aResult)
3855 : {
3856 0 : switch (aValue.GetUnit()) {
3857 : case eCSSUnit_Enumerated:
3858 0 : aResult = nsTimingFunction(aValue.GetIntValue());
3859 0 : break;
3860 : case eCSSUnit_Cubic_Bezier:
3861 : {
3862 0 : nsCSSValue::Array* array = aValue.GetArrayValue();
3863 0 : NS_ASSERTION(array && array->Count() == 4,
3864 : "Need 4 control points");
3865 0 : aResult = nsTimingFunction(array->Item(0).GetFloatValue(),
3866 0 : array->Item(1).GetFloatValue(),
3867 0 : array->Item(2).GetFloatValue(),
3868 0 : array->Item(3).GetFloatValue());
3869 : }
3870 0 : break;
3871 : case eCSSUnit_Steps:
3872 : {
3873 0 : nsCSSValue::Array* array = aValue.GetArrayValue();
3874 0 : NS_ASSERTION(array && array->Count() == 2,
3875 : "Need 2 items");
3876 0 : NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
3877 : "unexpected first value");
3878 0 : NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
3879 : (array->Item(1).GetIntValue() ==
3880 : NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START ||
3881 : array->Item(1).GetIntValue() ==
3882 : NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END),
3883 : "unexpected second value");
3884 : nsTimingFunction::Type type =
3885 0 : (array->Item(1).GetIntValue() ==
3886 : NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END)
3887 0 : ? nsTimingFunction::StepEnd : nsTimingFunction::StepStart;
3888 0 : aResult = nsTimingFunction(type, array->Item(0).GetIntValue());
3889 : }
3890 0 : break;
3891 : default:
3892 0 : NS_NOTREACHED("Invalid transition property unit");
3893 : }
3894 0 : }
3895 :
3896 : const void*
3897 0 : nsRuleNode::ComputeDisplayData(void* aStartStruct,
3898 : const nsRuleData* aRuleData,
3899 : nsStyleContext* aContext,
3900 : nsRuleNode* aHighestNode,
3901 : const RuleDetail aRuleDetail,
3902 : const bool aCanStoreInRuleTree)
3903 : {
3904 0 : COMPUTE_START_RESET(Display, (), display, parentDisplay)
3905 :
3906 : // We may have ended up with aStartStruct's values of mDisplay and
3907 : // mFloats, but those may not be correct if our style data overrides
3908 : // its position or float properties. Reset to mOriginalDisplay and
3909 : // mOriginalFloats; it if turns out we still need the display/floats
3910 : // adjustments we'll do them below.
3911 0 : display->mDisplay = display->mOriginalDisplay;
3912 0 : display->mFloats = display->mOriginalFloats;
3913 :
3914 : // Each property's index in this array must match its index in the
3915 : // const array |transitionPropInfo| above.
3916 : TransitionPropData transitionPropData[4];
3917 0 : TransitionPropData& delay = transitionPropData[0];
3918 0 : TransitionPropData& duration = transitionPropData[1];
3919 0 : TransitionPropData& property = transitionPropData[2];
3920 0 : TransitionPropData& timingFunction = transitionPropData[3];
3921 :
3922 : #define FOR_ALL_TRANSITION_PROPS(var_) \
3923 : for (PRUint32 var_ = 0; var_ < 4; ++var_)
3924 :
3925 : // CSS Transitions
3926 : PRUint32 numTransitions =
3927 : CountTransitionProps(transitionPropInfo, transitionPropData,
3928 : ArrayLength(transitionPropData),
3929 : display, parentDisplay, aRuleData,
3930 0 : canStoreInRuleTree);
3931 :
3932 0 : if (!display->mTransitions.SetLength(numTransitions)) {
3933 0 : NS_WARNING("failed to allocate transitions array");
3934 0 : display->mTransitions.SetLength(1);
3935 0 : NS_ABORT_IF_FALSE(display->mTransitions.Length() == 1,
3936 : "could not allocate using auto array buffer");
3937 0 : numTransitions = 1;
3938 0 : FOR_ALL_TRANSITION_PROPS(p) {
3939 0 : TransitionPropData& d = transitionPropData[p];
3940 :
3941 0 : d.num = 1;
3942 : }
3943 : }
3944 :
3945 0 : FOR_ALL_TRANSITION_PROPS(p) {
3946 0 : const TransitionPropInfo& i = transitionPropInfo[p];
3947 0 : TransitionPropData& d = transitionPropData[p];
3948 :
3949 0 : display->*(i.sdCount) = d.num;
3950 : }
3951 :
3952 : // Fill in the transitions we just allocated with the appropriate values.
3953 0 : for (PRUint32 i = 0; i < numTransitions; ++i) {
3954 0 : nsTransition *transition = &display->mTransitions[i];
3955 :
3956 0 : if (i >= delay.num) {
3957 0 : transition->SetDelay(display->mTransitions[i % delay.num].GetDelay());
3958 0 : } else if (delay.unit == eCSSUnit_Inherit) {
3959 : // FIXME (Bug 522599) (for all transition properties): write a test that
3960 : // detects when this was wrong for i >= delay.num if parent had
3961 : // count for this property not equal to length
3962 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionDelayCount,
3963 : "delay.num computed incorrectly");
3964 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
3965 : "should have made canStoreInRuleTree false above");
3966 0 : transition->SetDelay(parentDisplay->mTransitions[i].GetDelay());
3967 0 : } else if (delay.unit == eCSSUnit_Initial) {
3968 0 : transition->SetDelay(0.0);
3969 0 : } else if (delay.list) {
3970 0 : switch (delay.list->mValue.GetUnit()) {
3971 : case eCSSUnit_Seconds:
3972 : transition->SetDelay(PR_MSEC_PER_SEC *
3973 0 : delay.list->mValue.GetFloatValue());
3974 0 : break;
3975 : case eCSSUnit_Milliseconds:
3976 0 : transition->SetDelay(delay.list->mValue.GetFloatValue());
3977 0 : break;
3978 : default:
3979 0 : NS_NOTREACHED("Invalid delay unit");
3980 : }
3981 : }
3982 :
3983 0 : if (i >= duration.num) {
3984 : transition->SetDuration(
3985 0 : display->mTransitions[i % duration.num].GetDuration());
3986 0 : } else if (duration.unit == eCSSUnit_Inherit) {
3987 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionDurationCount,
3988 : "duration.num computed incorrectly");
3989 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
3990 : "should have made canStoreInRuleTree false above");
3991 0 : transition->SetDuration(parentDisplay->mTransitions[i].GetDuration());
3992 0 : } else if (duration.unit == eCSSUnit_Initial) {
3993 0 : transition->SetDuration(0.0);
3994 0 : } else if (duration.list) {
3995 0 : switch (duration.list->mValue.GetUnit()) {
3996 : case eCSSUnit_Seconds:
3997 : transition->SetDuration(PR_MSEC_PER_SEC *
3998 0 : duration.list->mValue.GetFloatValue());
3999 0 : break;
4000 : case eCSSUnit_Milliseconds:
4001 0 : transition->SetDuration(duration.list->mValue.GetFloatValue());
4002 0 : break;
4003 : default:
4004 0 : NS_NOTREACHED("Invalid duration unit");
4005 : }
4006 : }
4007 :
4008 0 : if (i >= property.num) {
4009 0 : transition->CopyPropertyFrom(display->mTransitions[i % property.num]);
4010 0 : } else if (property.unit == eCSSUnit_Inherit) {
4011 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionPropertyCount,
4012 : "property.num computed incorrectly");
4013 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4014 : "should have made canStoreInRuleTree false above");
4015 0 : transition->CopyPropertyFrom(parentDisplay->mTransitions[i]);
4016 0 : } else if (property.unit == eCSSUnit_Initial ||
4017 : property.unit == eCSSUnit_All) {
4018 0 : transition->SetProperty(eCSSPropertyExtra_all_properties);
4019 0 : } else if (property.unit == eCSSUnit_None) {
4020 0 : transition->SetProperty(eCSSPropertyExtra_no_properties);
4021 0 : } else if (property.list) {
4022 0 : NS_ABORT_IF_FALSE(property.list->mValue.GetUnit() == eCSSUnit_Ident,
4023 : nsPrintfCString(64,
4024 : "Invalid transition property unit %d",
4025 : property.list->mValue.GetUnit()).get());
4026 :
4027 : nsDependentString
4028 0 : propertyStr(property.list->mValue.GetStringBufferValue());
4029 0 : nsCSSProperty prop = nsCSSProps::LookupProperty(propertyStr);
4030 0 : if (prop == eCSSProperty_UNKNOWN) {
4031 0 : transition->SetUnknownProperty(propertyStr);
4032 : } else {
4033 0 : transition->SetProperty(prop);
4034 : }
4035 : }
4036 :
4037 0 : if (i >= timingFunction.num) {
4038 : transition->SetTimingFunction(
4039 0 : display->mTransitions[i % timingFunction.num].GetTimingFunction());
4040 0 : } else if (timingFunction.unit == eCSSUnit_Inherit) {
4041 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mTransitionTimingFunctionCount,
4042 : "timingFunction.num computed incorrectly");
4043 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4044 : "should have made canStoreInRuleTree false above");
4045 : transition->SetTimingFunction(
4046 0 : parentDisplay->mTransitions[i].GetTimingFunction());
4047 0 : } else if (timingFunction.unit == eCSSUnit_Initial) {
4048 : transition->SetTimingFunction(
4049 0 : nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
4050 0 : } else if (timingFunction.list) {
4051 : ComputeTimingFunction(timingFunction.list->mValue,
4052 0 : transition->TimingFunctionSlot());
4053 : }
4054 :
4055 0 : FOR_ALL_TRANSITION_PROPS(p) {
4056 0 : const TransitionPropInfo& info = transitionPropInfo[p];
4057 0 : TransitionPropData& d = transitionPropData[p];
4058 :
4059 : // if we're at the end of the list, start at the beginning and repeat
4060 : // until we're out of transitions to populate
4061 0 : if (d.list) {
4062 : d.list = d.list->mNext ? d.list->mNext :
4063 0 : aRuleData->ValueFor(info.property)->GetListValue();
4064 : }
4065 : }
4066 : }
4067 :
4068 : // Each property's index in this array must match its index in the
4069 : // const array |animationPropInfo| above.
4070 : TransitionPropData animationPropData[8];
4071 0 : TransitionPropData& animDelay = animationPropData[0];
4072 0 : TransitionPropData& animDuration = animationPropData[1];
4073 0 : TransitionPropData& animName = animationPropData[2];
4074 0 : TransitionPropData& animTimingFunction = animationPropData[3];
4075 0 : TransitionPropData& animDirection = animationPropData[4];
4076 0 : TransitionPropData& animFillMode = animationPropData[5];
4077 0 : TransitionPropData& animPlayState = animationPropData[6];
4078 0 : TransitionPropData& animIterationCount = animationPropData[7];
4079 :
4080 : #define FOR_ALL_ANIMATION_PROPS(var_) \
4081 : for (PRUint32 var_ = 0; var_ < 8; ++var_)
4082 :
4083 : // CSS Animations.
4084 :
4085 : PRUint32 numAnimations =
4086 : CountTransitionProps(animationPropInfo, animationPropData,
4087 : ArrayLength(animationPropData),
4088 : display, parentDisplay, aRuleData,
4089 0 : canStoreInRuleTree);
4090 :
4091 0 : if (!display->mAnimations.SetLength(numAnimations)) {
4092 0 : NS_WARNING("failed to allocate animations array");
4093 0 : display->mAnimations.SetLength(1);
4094 0 : NS_ABORT_IF_FALSE(display->mAnimations.Length() == 1,
4095 : "could not allocate using auto array buffer");
4096 0 : numAnimations = 1;
4097 0 : FOR_ALL_ANIMATION_PROPS(p) {
4098 0 : TransitionPropData& d = animationPropData[p];
4099 :
4100 0 : d.num = 1;
4101 : }
4102 : }
4103 :
4104 0 : FOR_ALL_ANIMATION_PROPS(p) {
4105 0 : const TransitionPropInfo& i = animationPropInfo[p];
4106 0 : TransitionPropData& d = animationPropData[p];
4107 :
4108 0 : display->*(i.sdCount) = d.num;
4109 : }
4110 :
4111 : // Fill in the animations we just allocated with the appropriate values.
4112 0 : for (PRUint32 i = 0; i < numAnimations; ++i) {
4113 0 : nsAnimation *animation = &display->mAnimations[i];
4114 :
4115 0 : if (i >= animDelay.num) {
4116 0 : animation->SetDelay(display->mAnimations[i % animDelay.num].GetDelay());
4117 0 : } else if (animDelay.unit == eCSSUnit_Inherit) {
4118 : // FIXME (Bug 522599) (for all animation properties): write a test that
4119 : // detects when this was wrong for i >= animDelay.num if parent had
4120 : // count for this property not equal to length
4121 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDelayCount,
4122 : "animDelay.num computed incorrectly");
4123 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4124 : "should have made canStoreInRuleTree false above");
4125 0 : animation->SetDelay(parentDisplay->mAnimations[i].GetDelay());
4126 0 : } else if (animDelay.unit == eCSSUnit_Initial) {
4127 0 : animation->SetDelay(0.0);
4128 0 : } else if (animDelay.list) {
4129 0 : switch (animDelay.list->mValue.GetUnit()) {
4130 : case eCSSUnit_Seconds:
4131 : animation->SetDelay(PR_MSEC_PER_SEC *
4132 0 : animDelay.list->mValue.GetFloatValue());
4133 0 : break;
4134 : case eCSSUnit_Milliseconds:
4135 0 : animation->SetDelay(animDelay.list->mValue.GetFloatValue());
4136 0 : break;
4137 : default:
4138 0 : NS_NOTREACHED("Invalid delay unit");
4139 : }
4140 : }
4141 :
4142 0 : if (i >= animDuration.num) {
4143 : animation->SetDuration(
4144 0 : display->mAnimations[i % animDuration.num].GetDuration());
4145 0 : } else if (animDuration.unit == eCSSUnit_Inherit) {
4146 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDurationCount,
4147 : "animDuration.num computed incorrectly");
4148 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4149 : "should have made canStoreInRuleTree false above");
4150 0 : animation->SetDuration(parentDisplay->mAnimations[i].GetDuration());
4151 0 : } else if (animDuration.unit == eCSSUnit_Initial) {
4152 0 : animation->SetDuration(0.0);
4153 0 : } else if (animDuration.list) {
4154 0 : switch (animDuration.list->mValue.GetUnit()) {
4155 : case eCSSUnit_Seconds:
4156 : animation->SetDuration(PR_MSEC_PER_SEC *
4157 0 : animDuration.list->mValue.GetFloatValue());
4158 0 : break;
4159 : case eCSSUnit_Milliseconds:
4160 0 : animation->SetDuration(animDuration.list->mValue.GetFloatValue());
4161 0 : break;
4162 : default:
4163 0 : NS_NOTREACHED("Invalid duration unit");
4164 : }
4165 : }
4166 :
4167 0 : if (i >= animName.num) {
4168 0 : animation->SetName(display->mAnimations[i % animName.num].GetName());
4169 0 : } else if (animName.unit == eCSSUnit_Inherit) {
4170 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationNameCount,
4171 : "animName.num computed incorrectly");
4172 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4173 : "should have made canStoreInRuleTree false above");
4174 0 : animation->SetName(parentDisplay->mAnimations[i].GetName());
4175 0 : } else if (animName.unit == eCSSUnit_Initial) {
4176 0 : animation->SetName(EmptyString());
4177 0 : } else if (animName.list) {
4178 0 : switch (animName.list->mValue.GetUnit()) {
4179 : case eCSSUnit_Ident: {
4180 : nsDependentString
4181 0 : nameStr(animName.list->mValue.GetStringBufferValue());
4182 0 : animation->SetName(nameStr);
4183 : break;
4184 : }
4185 : case eCSSUnit_None: {
4186 0 : animation->SetName(EmptyString());
4187 0 : break;
4188 : }
4189 : default:
4190 0 : NS_ABORT_IF_FALSE(false,
4191 : nsPrintfCString(64, "Invalid animation-name unit %d",
4192 : animName.list->mValue.GetUnit()).get());
4193 : }
4194 : }
4195 :
4196 0 : if (i >= animTimingFunction.num) {
4197 : animation->SetTimingFunction(
4198 0 : display->mAnimations[i % animTimingFunction.num].GetTimingFunction());
4199 0 : } else if (animTimingFunction.unit == eCSSUnit_Inherit) {
4200 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationTimingFunctionCount,
4201 : "animTimingFunction.num computed incorrectly");
4202 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4203 : "should have made canStoreInRuleTree false above");
4204 : animation->SetTimingFunction(
4205 0 : parentDisplay->mAnimations[i].GetTimingFunction());
4206 0 : } else if (animTimingFunction.unit == eCSSUnit_Initial) {
4207 : animation->SetTimingFunction(
4208 0 : nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
4209 0 : } else if (animTimingFunction.list) {
4210 : ComputeTimingFunction(animTimingFunction.list->mValue,
4211 0 : animation->TimingFunctionSlot());
4212 : }
4213 :
4214 0 : if (i >= animDirection.num) {
4215 0 : animation->SetDirection(display->mAnimations[i % animDirection.num].GetDirection());
4216 0 : } else if (animDirection.unit == eCSSUnit_Inherit) {
4217 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationDirectionCount,
4218 : "animDirection.num computed incorrectly");
4219 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4220 : "should have made canStoreInRuleTree false above");
4221 0 : animation->SetDirection(parentDisplay->mAnimations[i].GetDirection());
4222 0 : } else if (animDirection.unit == eCSSUnit_Initial) {
4223 0 : animation->SetDirection(NS_STYLE_ANIMATION_DIRECTION_NORMAL);
4224 0 : } else if (animDirection.list) {
4225 0 : NS_ABORT_IF_FALSE(animDirection.list->mValue.GetUnit() == eCSSUnit_Enumerated,
4226 : nsPrintfCString(64,
4227 : "Invalid animation-direction unit %d",
4228 : animDirection.list->mValue.GetUnit()).get());
4229 :
4230 0 : animation->SetDirection(animDirection.list->mValue.GetIntValue());
4231 : }
4232 :
4233 0 : if (i >= animFillMode.num) {
4234 0 : animation->SetFillMode(display->mAnimations[i % animFillMode.num].GetFillMode());
4235 0 : } else if (animFillMode.unit == eCSSUnit_Inherit) {
4236 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationFillModeCount,
4237 : "animFillMode.num computed incorrectly");
4238 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4239 : "should have made canStoreInRuleTree false above");
4240 0 : animation->SetFillMode(parentDisplay->mAnimations[i].GetFillMode());
4241 0 : } else if (animFillMode.unit == eCSSUnit_Initial) {
4242 0 : animation->SetFillMode(NS_STYLE_ANIMATION_FILL_MODE_NONE);
4243 0 : } else if (animFillMode.list) {
4244 0 : NS_ABORT_IF_FALSE(animFillMode.list->mValue.GetUnit() == eCSSUnit_Enumerated,
4245 : nsPrintfCString(64,
4246 : "Invalid animation-fill-mode unit %d",
4247 : animFillMode.list->mValue.GetUnit()).get());
4248 :
4249 0 : animation->SetFillMode(animFillMode.list->mValue.GetIntValue());
4250 : }
4251 :
4252 0 : if (i >= animPlayState.num) {
4253 0 : animation->SetPlayState(display->mAnimations[i % animPlayState.num].GetPlayState());
4254 0 : } else if (animPlayState.unit == eCSSUnit_Inherit) {
4255 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationPlayStateCount,
4256 : "animPlayState.num computed incorrectly");
4257 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4258 : "should have made canStoreInRuleTree false above");
4259 0 : animation->SetPlayState(parentDisplay->mAnimations[i].GetPlayState());
4260 0 : } else if (animPlayState.unit == eCSSUnit_Initial) {
4261 0 : animation->SetPlayState(NS_STYLE_ANIMATION_PLAY_STATE_RUNNING);
4262 0 : } else if (animPlayState.list) {
4263 0 : NS_ABORT_IF_FALSE(animPlayState.list->mValue.GetUnit() == eCSSUnit_Enumerated,
4264 : nsPrintfCString(64,
4265 : "Invalid animation-play-state unit %d",
4266 : animPlayState.list->mValue.GetUnit()).get());
4267 :
4268 0 : animation->SetPlayState(animPlayState.list->mValue.GetIntValue());
4269 : }
4270 :
4271 0 : if (i >= animIterationCount.num) {
4272 0 : animation->SetIterationCount(display->mAnimations[i % animIterationCount.num].GetIterationCount());
4273 0 : } else if (animIterationCount.unit == eCSSUnit_Inherit) {
4274 0 : NS_ABORT_IF_FALSE(i < parentDisplay->mAnimationIterationCountCount,
4275 : "animIterationCount.num computed incorrectly");
4276 0 : NS_ABORT_IF_FALSE(!canStoreInRuleTree,
4277 : "should have made canStoreInRuleTree false above");
4278 0 : animation->SetIterationCount(parentDisplay->mAnimations[i].GetIterationCount());
4279 0 : } else if (animIterationCount.unit == eCSSUnit_Initial) {
4280 0 : animation->SetIterationCount(1.0f);
4281 0 : } else if (animIterationCount.list) {
4282 0 : switch(animIterationCount.list->mValue.GetUnit()) {
4283 : case eCSSUnit_Enumerated:
4284 0 : NS_ABORT_IF_FALSE(animIterationCount.list->mValue.GetIntValue() ==
4285 : NS_STYLE_ANIMATION_ITERATION_COUNT_INFINITE,
4286 : "unexpected value");
4287 0 : animation->SetIterationCount(NS_IEEEPositiveInfinity());
4288 0 : break;
4289 : case eCSSUnit_Number:
4290 : animation->SetIterationCount(
4291 0 : animIterationCount.list->mValue.GetFloatValue());
4292 0 : break;
4293 : default:
4294 0 : NS_ABORT_IF_FALSE(false,
4295 : "unexpected animation-iteration-count unit");
4296 : }
4297 : }
4298 :
4299 0 : FOR_ALL_ANIMATION_PROPS(p) {
4300 0 : const TransitionPropInfo& info = animationPropInfo[p];
4301 0 : TransitionPropData& d = animationPropData[p];
4302 :
4303 : // if we're at the end of the list, start at the beginning and repeat
4304 : // until we're out of animations to populate
4305 0 : if (d.list) {
4306 : d.list = d.list->mNext ? d.list->mNext :
4307 0 : aRuleData->ValueFor(info.property)->GetListValue();
4308 : }
4309 : }
4310 : }
4311 :
4312 : // opacity: factor, inherit, initial
4313 0 : SetFactor(*aRuleData->ValueForOpacity(), display->mOpacity, canStoreInRuleTree,
4314 0 : parentDisplay->mOpacity, 1.0f, SETFCT_OPACITY);
4315 :
4316 : // display: enum, inherit, initial
4317 0 : SetDiscrete(*aRuleData->ValueForDisplay(), display->mDisplay, canStoreInRuleTree,
4318 : SETDSC_ENUMERATED, parentDisplay->mDisplay,
4319 0 : NS_STYLE_DISPLAY_INLINE, 0, 0, 0, 0);
4320 : // Backup original display value for calculation of a hypothetical
4321 : // box (CSS2 10.6.4/10.6.5), in addition to getting our style data right later.
4322 : // See nsHTMLReflowState::CalculateHypotheticalBox
4323 0 : display->mOriginalDisplay = display->mDisplay;
4324 :
4325 : // appearance: enum, inherit, initial
4326 0 : SetDiscrete(*aRuleData->ValueForAppearance(),
4327 : display->mAppearance, canStoreInRuleTree,
4328 : SETDSC_ENUMERATED, parentDisplay->mAppearance,
4329 0 : NS_THEME_NONE, 0, 0, 0, 0);
4330 :
4331 : // binding: url, none, inherit
4332 0 : const nsCSSValue* bindingValue = aRuleData->ValueForBinding();
4333 0 : if (eCSSUnit_URL == bindingValue->GetUnit()) {
4334 0 : nsCSSValue::URL* url = bindingValue->GetURLStructValue();
4335 0 : NS_ASSERTION(url, "What's going on here?");
4336 :
4337 0 : if (NS_LIKELY(url->GetURI())) {
4338 0 : display->mBinding = url;
4339 : } else {
4340 0 : display->mBinding = nsnull;
4341 : }
4342 : }
4343 0 : else if (eCSSUnit_None == bindingValue->GetUnit() ||
4344 0 : eCSSUnit_Initial == bindingValue->GetUnit()) {
4345 0 : display->mBinding = nsnull;
4346 : }
4347 0 : else if (eCSSUnit_Inherit == bindingValue->GetUnit()) {
4348 0 : canStoreInRuleTree = false;
4349 0 : display->mBinding = parentDisplay->mBinding;
4350 : }
4351 :
4352 : // position: enum, inherit, initial
4353 0 : SetDiscrete(*aRuleData->ValueForPosition(), display->mPosition, canStoreInRuleTree,
4354 : SETDSC_ENUMERATED, parentDisplay->mPosition,
4355 0 : NS_STYLE_POSITION_STATIC, 0, 0, 0, 0);
4356 :
4357 : // clear: enum, inherit, initial
4358 0 : SetDiscrete(*aRuleData->ValueForClear(), display->mBreakType, canStoreInRuleTree,
4359 : SETDSC_ENUMERATED, parentDisplay->mBreakType,
4360 0 : NS_STYLE_CLEAR_NONE, 0, 0, 0, 0);
4361 :
4362 : // temp fix for bug 24000
4363 : // Map 'auto' and 'avoid' to false, and 'always', 'left', and
4364 : // 'right' to true.
4365 : // "A conforming user agent may interpret the values 'left' and
4366 : // 'right' as 'always'." - CSS2.1, section 13.3.1
4367 0 : const nsCSSValue* breakBeforeValue = aRuleData->ValueForPageBreakBefore();
4368 0 : if (eCSSUnit_Enumerated == breakBeforeValue->GetUnit()) {
4369 : display->mBreakBefore =
4370 0 : (NS_STYLE_PAGE_BREAK_AVOID != breakBeforeValue->GetIntValue() &&
4371 0 : NS_STYLE_PAGE_BREAK_AUTO != breakBeforeValue->GetIntValue());
4372 : }
4373 0 : else if (eCSSUnit_Initial == breakBeforeValue->GetUnit()) {
4374 0 : display->mBreakBefore = false;
4375 : }
4376 0 : else if (eCSSUnit_Inherit == breakBeforeValue->GetUnit()) {
4377 0 : canStoreInRuleTree = false;
4378 0 : display->mBreakBefore = parentDisplay->mBreakBefore;
4379 : }
4380 :
4381 0 : const nsCSSValue* breakAfterValue = aRuleData->ValueForPageBreakAfter();
4382 0 : if (eCSSUnit_Enumerated == breakAfterValue->GetUnit()) {
4383 : display->mBreakAfter =
4384 0 : (NS_STYLE_PAGE_BREAK_AVOID != breakAfterValue->GetIntValue() &&
4385 0 : NS_STYLE_PAGE_BREAK_AUTO != breakAfterValue->GetIntValue());
4386 : }
4387 0 : else if (eCSSUnit_Initial == breakAfterValue->GetUnit()) {
4388 0 : display->mBreakAfter = false;
4389 : }
4390 0 : else if (eCSSUnit_Inherit == breakAfterValue->GetUnit()) {
4391 0 : canStoreInRuleTree = false;
4392 0 : display->mBreakAfter = parentDisplay->mBreakAfter;
4393 : }
4394 : // end temp fix
4395 :
4396 : // float: enum, inherit, initial
4397 0 : SetDiscrete(*aRuleData->ValueForCssFloat(),
4398 : display->mFloats, canStoreInRuleTree,
4399 : SETDSC_ENUMERATED, parentDisplay->mFloats,
4400 0 : NS_STYLE_FLOAT_NONE, 0, 0, 0, 0);
4401 : // Save mFloats in mOriginalFloats in case we need it later
4402 0 : display->mOriginalFloats = display->mFloats;
4403 :
4404 : // overflow-x: enum, inherit, initial
4405 0 : SetDiscrete(*aRuleData->ValueForOverflowX(),
4406 : display->mOverflowX, canStoreInRuleTree,
4407 : SETDSC_ENUMERATED, parentDisplay->mOverflowX,
4408 0 : NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
4409 :
4410 : // overflow-y: enum, inherit, initial
4411 0 : SetDiscrete(*aRuleData->ValueForOverflowY(),
4412 : display->mOverflowY, canStoreInRuleTree,
4413 : SETDSC_ENUMERATED, parentDisplay->mOverflowY,
4414 0 : NS_STYLE_OVERFLOW_VISIBLE, 0, 0, 0, 0);
4415 :
4416 : // CSS3 overflow-x and overflow-y require some fixup as well in some
4417 : // cases. NS_STYLE_OVERFLOW_VISIBLE and NS_STYLE_OVERFLOW_CLIP are
4418 : // meaningful only when used in both dimensions.
4419 0 : if (display->mOverflowX != display->mOverflowY &&
4420 : (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE ||
4421 : display->mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
4422 : display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE ||
4423 : display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)) {
4424 : // We can't store in the rule tree since a more specific rule might
4425 : // change these conditions.
4426 0 : canStoreInRuleTree = false;
4427 :
4428 : // NS_STYLE_OVERFLOW_CLIP is a deprecated value, so if it's specified
4429 : // in only one dimension, convert it to NS_STYLE_OVERFLOW_HIDDEN.
4430 0 : if (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP)
4431 0 : display->mOverflowX = NS_STYLE_OVERFLOW_HIDDEN;
4432 0 : if (display->mOverflowY == NS_STYLE_OVERFLOW_CLIP)
4433 0 : display->mOverflowY = NS_STYLE_OVERFLOW_HIDDEN;
4434 :
4435 : // If 'visible' is specified but doesn't match the other dimension, it
4436 : // turns into 'auto'.
4437 0 : if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
4438 0 : display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
4439 0 : if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
4440 0 : display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
4441 : }
4442 :
4443 0 : SetDiscrete(*aRuleData->ValueForResize(), display->mResize, canStoreInRuleTree,
4444 : SETDSC_ENUMERATED, parentDisplay->mResize,
4445 0 : NS_STYLE_RESIZE_NONE, 0, 0, 0, 0);
4446 :
4447 : // clip property: length, auto, inherit
4448 0 : const nsCSSValue* clipValue = aRuleData->ValueForClip();
4449 0 : switch (clipValue->GetUnit()) {
4450 : case eCSSUnit_Inherit:
4451 0 : canStoreInRuleTree = false;
4452 0 : display->mClipFlags = parentDisplay->mClipFlags;
4453 0 : display->mClip = parentDisplay->mClip;
4454 0 : break;
4455 :
4456 : case eCSSUnit_Initial:
4457 : case eCSSUnit_Auto:
4458 0 : display->mClipFlags = NS_STYLE_CLIP_AUTO;
4459 0 : display->mClip.SetRect(0,0,0,0);
4460 0 : break;
4461 :
4462 : case eCSSUnit_Null:
4463 0 : break;
4464 :
4465 : case eCSSUnit_Rect: {
4466 0 : const nsCSSRect& clipRect = clipValue->GetRectValue();
4467 :
4468 0 : display->mClipFlags = NS_STYLE_CLIP_RECT;
4469 :
4470 0 : if (clipRect.mTop.GetUnit() == eCSSUnit_Auto) {
4471 0 : display->mClip.y = 0;
4472 0 : display->mClipFlags |= NS_STYLE_CLIP_TOP_AUTO;
4473 : }
4474 0 : else if (clipRect.mTop.IsLengthUnit()) {
4475 : display->mClip.y = CalcLength(clipRect.mTop, aContext,
4476 0 : mPresContext, canStoreInRuleTree);
4477 : }
4478 :
4479 0 : if (clipRect.mBottom.GetUnit() == eCSSUnit_Auto) {
4480 : // Setting to NS_MAXSIZE for the 'auto' case ensures that
4481 : // the clip rect is nonempty. It is important that mClip be
4482 : // nonempty if the actual clip rect could be nonempty.
4483 0 : display->mClip.height = NS_MAXSIZE;
4484 0 : display->mClipFlags |= NS_STYLE_CLIP_BOTTOM_AUTO;
4485 : }
4486 0 : else if (clipRect.mBottom.IsLengthUnit()) {
4487 : display->mClip.height = CalcLength(clipRect.mBottom, aContext,
4488 0 : mPresContext, canStoreInRuleTree) -
4489 0 : display->mClip.y;
4490 : }
4491 :
4492 0 : if (clipRect.mLeft.GetUnit() == eCSSUnit_Auto) {
4493 0 : display->mClip.x = 0;
4494 0 : display->mClipFlags |= NS_STYLE_CLIP_LEFT_AUTO;
4495 : }
4496 0 : else if (clipRect.mLeft.IsLengthUnit()) {
4497 : display->mClip.x = CalcLength(clipRect.mLeft, aContext,
4498 0 : mPresContext, canStoreInRuleTree);
4499 : }
4500 :
4501 0 : if (clipRect.mRight.GetUnit() == eCSSUnit_Auto) {
4502 : // Setting to NS_MAXSIZE for the 'auto' case ensures that
4503 : // the clip rect is nonempty. It is important that mClip be
4504 : // nonempty if the actual clip rect could be nonempty.
4505 0 : display->mClip.width = NS_MAXSIZE;
4506 0 : display->mClipFlags |= NS_STYLE_CLIP_RIGHT_AUTO;
4507 : }
4508 0 : else if (clipRect.mRight.IsLengthUnit()) {
4509 : display->mClip.width = CalcLength(clipRect.mRight, aContext,
4510 0 : mPresContext, canStoreInRuleTree) -
4511 0 : display->mClip.x;
4512 : }
4513 0 : break;
4514 : }
4515 :
4516 : default:
4517 0 : NS_ABORT_IF_FALSE(false, "unrecognized clip unit");
4518 : }
4519 :
4520 0 : if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
4521 : // CSS2 9.7 specifies display type corrections dealing with 'float'
4522 : // and 'position'. Since generated content can't be floated or
4523 : // positioned, we can deal with it here.
4524 :
4525 0 : if (nsCSSPseudoElements::firstLetter == aContext->GetPseudo()) {
4526 : // a non-floating first-letter must be inline
4527 : // XXX this fix can go away once bug 103189 is fixed correctly
4528 : // Note that we reset mOriginalDisplay to enforce the invariant that it equals mDisplay if we're not positioned or floating.
4529 0 : display->mOriginalDisplay = display->mDisplay = NS_STYLE_DISPLAY_INLINE;
4530 :
4531 : // We can't cache the data in the rule tree since if a more specific
4532 : // rule has 'float: left' we'll end up with the wrong 'display'
4533 : // property.
4534 0 : canStoreInRuleTree = false;
4535 : }
4536 :
4537 0 : if (display->IsAbsolutelyPositioned()) {
4538 : // 1) if position is 'absolute' or 'fixed' then display must be
4539 : // block-level and float must be 'none'
4540 0 : EnsureBlockDisplay(display->mDisplay);
4541 0 : display->mFloats = NS_STYLE_FLOAT_NONE;
4542 :
4543 : // Note that it's OK to cache this struct in the ruletree
4544 : // because it's fine as-is for any style context that points to
4545 : // it directly, and any use of it as aStartStruct (e.g. if a
4546 : // more specific rule sets "position: static") will use
4547 : // mOriginalDisplay and mOriginalFloats, which we have carefully
4548 : // not changed.
4549 0 : } else if (display->mFloats != NS_STYLE_FLOAT_NONE) {
4550 : // 2) if float is not none, and display is not none, then we must
4551 : // set a block-level 'display' type per CSS2.1 section 9.7.
4552 0 : EnsureBlockDisplay(display->mDisplay);
4553 :
4554 : // Note that it's OK to cache this struct in the ruletree
4555 : // because it's fine as-is for any style context that points to
4556 : // it directly, and any use of it as aStartStruct (e.g. if a
4557 : // more specific rule sets "float: none") will use
4558 : // mOriginalDisplay, which we have carefully not changed.
4559 : }
4560 :
4561 : }
4562 :
4563 : /* Convert the nsCSSValueList into an nsTArray<nsTransformFunction *>. */
4564 0 : const nsCSSValue* transformValue = aRuleData->ValueForTransform();
4565 0 : switch (transformValue->GetUnit()) {
4566 : case eCSSUnit_Null:
4567 0 : break;
4568 :
4569 : case eCSSUnit_Initial:
4570 : case eCSSUnit_None:
4571 0 : display->mSpecifiedTransform = nsnull;
4572 0 : break;
4573 :
4574 : case eCSSUnit_Inherit:
4575 0 : display->mSpecifiedTransform = parentDisplay->mSpecifiedTransform;
4576 0 : canStoreInRuleTree = false;
4577 0 : break;
4578 :
4579 : case eCSSUnit_List:
4580 : case eCSSUnit_ListDep: {
4581 0 : const nsCSSValueList* head = transformValue->GetListValue();
4582 : // can get a _None in here from transform animation
4583 0 : if (head->mValue.GetUnit() == eCSSUnit_None) {
4584 0 : NS_ABORT_IF_FALSE(head->mNext == nsnull, "none must be alone");
4585 0 : display->mSpecifiedTransform = nsnull;
4586 : } else {
4587 0 : display->mSpecifiedTransform = head; // weak pointer, owned by rule
4588 : }
4589 0 : break;
4590 : }
4591 :
4592 : default:
4593 0 : NS_ABORT_IF_FALSE(false, "unrecognized transform unit");
4594 : }
4595 :
4596 : /* Convert -moz-transform-origin. */
4597 : const nsCSSValue* transformOriginValue =
4598 0 : aRuleData->ValueForTransformOrigin();
4599 0 : if (transformOriginValue->GetUnit() != eCSSUnit_Null) {
4600 : const nsCSSValue& valX =
4601 0 : transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
4602 0 : transformOriginValue->GetTripletValue().mXValue : *transformOriginValue;
4603 : const nsCSSValue& valY =
4604 0 : transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
4605 0 : transformOriginValue->GetTripletValue().mYValue : *transformOriginValue;
4606 : const nsCSSValue& valZ =
4607 0 : transformOriginValue->GetUnit() == eCSSUnit_Triplet ?
4608 0 : transformOriginValue->GetTripletValue().mZValue : *transformOriginValue;
4609 :
4610 : mozilla::DebugOnly<bool> cX =
4611 : SetCoord(valX, display->mTransformOrigin[0],
4612 : parentDisplay->mTransformOrigin[0],
4613 : SETCOORD_LPH | SETCOORD_INITIAL_HALF |
4614 : SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC,
4615 0 : aContext, mPresContext, canStoreInRuleTree);
4616 :
4617 : mozilla::DebugOnly<bool> cY =
4618 : SetCoord(valY, display->mTransformOrigin[1],
4619 : parentDisplay->mTransformOrigin[1],
4620 : SETCOORD_LPH | SETCOORD_INITIAL_HALF |
4621 : SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC,
4622 0 : aContext, mPresContext, canStoreInRuleTree);
4623 :
4624 0 : if (valZ.GetUnit() == eCSSUnit_Null) {
4625 : // Null for the z component means a 0 translation, not
4626 : // unspecified, as we have already checked the triplet
4627 : // value for Null.
4628 0 : display->mTransformOrigin[2].SetCoordValue(0);
4629 : } else {
4630 : mozilla::DebugOnly<bool> cZ =
4631 : SetCoord(valZ, display->mTransformOrigin[2],
4632 : parentDisplay->mTransformOrigin[2],
4633 : SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC,
4634 0 : aContext, mPresContext, canStoreInRuleTree);
4635 0 : NS_ABORT_IF_FALSE(cY == cZ, "changed one but not the other");
4636 : }
4637 0 : NS_ABORT_IF_FALSE(cX == cY, "changed one but not the other");
4638 0 : NS_ASSERTION(cX, "Malformed -moz-transform-origin parse!");
4639 : }
4640 :
4641 : const nsCSSValue* perspectiveOriginValue =
4642 0 : aRuleData->ValueForPerspectiveOrigin();
4643 0 : if (perspectiveOriginValue->GetUnit() != eCSSUnit_Null) {
4644 : mozilla::DebugOnly<bool> result =
4645 : SetPairCoords(*perspectiveOriginValue,
4646 : display->mPerspectiveOrigin[0],
4647 : display->mPerspectiveOrigin[1],
4648 : parentDisplay->mPerspectiveOrigin[0],
4649 : parentDisplay->mPerspectiveOrigin[1],
4650 : SETCOORD_LPH | SETCOORD_INITIAL_HALF |
4651 : SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC,
4652 0 : aContext, mPresContext, canStoreInRuleTree);
4653 0 : NS_ASSERTION(result, "Malformed -moz-perspective-origin parse!");
4654 : }
4655 :
4656 0 : SetCoord(*aRuleData->ValueForPerspective(),
4657 : display->mChildPerspective, parentDisplay->mChildPerspective,
4658 : SETCOORD_LAH | SETCOORD_INITIAL_ZERO | SETCOORD_NONE,
4659 0 : aContext, mPresContext, canStoreInRuleTree);
4660 :
4661 0 : SetDiscrete(*aRuleData->ValueForBackfaceVisibility(),
4662 : display->mBackfaceVisibility, canStoreInRuleTree,
4663 : SETDSC_ENUMERATED, parentDisplay->mBackfaceVisibility,
4664 0 : NS_STYLE_BACKFACE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
4665 :
4666 : // transform-style: enum, inherit, initial
4667 0 : SetDiscrete(*aRuleData->ValueForTransformStyle(),
4668 : display->mTransformStyle, canStoreInRuleTree,
4669 : SETDSC_ENUMERATED, parentDisplay->mTransformStyle,
4670 0 : NS_STYLE_TRANSFORM_STYLE_FLAT, 0, 0, 0, 0);
4671 :
4672 : // orient: enum, inherit, initial
4673 0 : SetDiscrete(*aRuleData->ValueForOrient(),
4674 : display->mOrient, canStoreInRuleTree,
4675 : SETDSC_ENUMERATED, parentDisplay->mOrient,
4676 0 : NS_STYLE_ORIENT_HORIZONTAL, 0, 0, 0, 0);
4677 :
4678 0 : COMPUTE_END_RESET(Display, display)
4679 : }
4680 :
4681 : const void*
4682 0 : nsRuleNode::ComputeVisibilityData(void* aStartStruct,
4683 : const nsRuleData* aRuleData,
4684 : nsStyleContext* aContext,
4685 : nsRuleNode* aHighestNode,
4686 : const RuleDetail aRuleDetail,
4687 : const bool aCanStoreInRuleTree)
4688 : {
4689 0 : COMPUTE_START_INHERITED(Visibility, (mPresContext),
4690 : visibility, parentVisibility)
4691 :
4692 : // IMPORTANT: No properties in this struct have lengths in them. We
4693 : // depend on this since CalcLengthWith can call GetStyleVisibility()
4694 : // to get the language for resolving fonts!
4695 :
4696 : // direction: enum, inherit, initial
4697 0 : SetDiscrete(*aRuleData->ValueForDirection(), visibility->mDirection,
4698 : canStoreInRuleTree,
4699 : SETDSC_ENUMERATED, parentVisibility->mDirection,
4700 0 : (GET_BIDI_OPTION_DIRECTION(mPresContext->GetBidi())
4701 : == IBMBIDI_TEXTDIRECTION_RTL)
4702 : ? NS_STYLE_DIRECTION_RTL : NS_STYLE_DIRECTION_LTR,
4703 0 : 0, 0, 0, 0);
4704 :
4705 : // visibility: enum, inherit, initial
4706 0 : SetDiscrete(*aRuleData->ValueForVisibility(), visibility->mVisible,
4707 : canStoreInRuleTree,
4708 : SETDSC_ENUMERATED, parentVisibility->mVisible,
4709 0 : NS_STYLE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
4710 :
4711 : // pointer-events: enum, inherit, initial
4712 0 : SetDiscrete(*aRuleData->ValueForPointerEvents(), visibility->mPointerEvents,
4713 : canStoreInRuleTree,
4714 : SETDSC_ENUMERATED, parentVisibility->mPointerEvents,
4715 0 : NS_STYLE_POINTER_EVENTS_AUTO, 0, 0, 0, 0);
4716 :
4717 0 : COMPUTE_END_INHERITED(Visibility, visibility)
4718 : }
4719 :
4720 : const void*
4721 0 : nsRuleNode::ComputeColorData(void* aStartStruct,
4722 : const nsRuleData* aRuleData,
4723 : nsStyleContext* aContext,
4724 : nsRuleNode* aHighestNode,
4725 : const RuleDetail aRuleDetail,
4726 : const bool aCanStoreInRuleTree)
4727 : {
4728 0 : COMPUTE_START_INHERITED(Color, (mPresContext), color, parentColor)
4729 :
4730 : // color: color, string, inherit
4731 : // Special case for currentColor. According to CSS3, setting color to 'currentColor'
4732 : // should behave as if it is inherited
4733 0 : const nsCSSValue* colorValue = aRuleData->ValueForColor();
4734 0 : if (colorValue->GetUnit() == eCSSUnit_EnumColor &&
4735 0 : colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
4736 0 : color->mColor = parentColor->mColor;
4737 0 : canStoreInRuleTree = false;
4738 : }
4739 0 : else if (colorValue->GetUnit() == eCSSUnit_Initial) {
4740 0 : color->mColor = mPresContext->DefaultColor();
4741 : }
4742 : else {
4743 : SetColor(*colorValue, parentColor->mColor, mPresContext, aContext,
4744 0 : color->mColor, canStoreInRuleTree);
4745 : }
4746 :
4747 0 : COMPUTE_END_INHERITED(Color, color)
4748 : }
4749 :
4750 : // information about how to compute values for background-* properties
4751 : template <class SpecifiedValueItem>
4752 : struct InitialInheritLocationFor {
4753 : };
4754 :
4755 : template <>
4756 : struct InitialInheritLocationFor<nsCSSValueList> {
4757 : static nsCSSValue nsCSSValueList::* Location() {
4758 : return &nsCSSValueList::mValue;
4759 : }
4760 : };
4761 :
4762 : template <>
4763 : struct InitialInheritLocationFor<nsCSSValuePairList> {
4764 : static nsCSSValue nsCSSValuePairList::* Location() {
4765 : return &nsCSSValuePairList::mXValue;
4766 : }
4767 : };
4768 :
4769 : template <class SpecifiedValueItem, class ComputedValueItem>
4770 : struct BackgroundItemComputer {
4771 : };
4772 :
4773 : template <>
4774 : struct BackgroundItemComputer<nsCSSValueList, PRUint8>
4775 : {
4776 0 : static void ComputeValue(nsStyleContext* aStyleContext,
4777 : const nsCSSValueList* aSpecifiedValue,
4778 : PRUint8& aComputedValue,
4779 : bool& aCanStoreInRuleTree)
4780 : {
4781 : SetDiscrete(aSpecifiedValue->mValue, aComputedValue, aCanStoreInRuleTree,
4782 0 : SETDSC_ENUMERATED, PRUint8(0), 0, 0, 0, 0, 0);
4783 0 : }
4784 : };
4785 :
4786 : template <>
4787 : struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Repeat>
4788 : {
4789 0 : static void ComputeValue(nsStyleContext* aStyleContext,
4790 : const nsCSSValuePairList* aSpecifiedValue,
4791 : nsStyleBackground::Repeat& aComputedValue,
4792 : bool& aCanStoreInRuleTree)
4793 : {
4794 0 : NS_ASSERTION(aSpecifiedValue->mXValue.GetUnit() == eCSSUnit_Enumerated &&
4795 : (aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Enumerated ||
4796 : aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null),
4797 : "Invalid unit");
4798 :
4799 0 : bool hasContraction = true;
4800 0 : PRUint8 value = aSpecifiedValue->mXValue.GetIntValue();
4801 0 : switch (value) {
4802 : case NS_STYLE_BG_REPEAT_REPEAT_X:
4803 0 : aComputedValue.mXRepeat = NS_STYLE_BG_REPEAT_REPEAT;
4804 0 : aComputedValue.mYRepeat = NS_STYLE_BG_REPEAT_NO_REPEAT;
4805 0 : break;
4806 : case NS_STYLE_BG_REPEAT_REPEAT_Y:
4807 0 : aComputedValue.mXRepeat = NS_STYLE_BG_REPEAT_NO_REPEAT;
4808 0 : aComputedValue.mYRepeat = NS_STYLE_BG_REPEAT_REPEAT;
4809 0 : break;
4810 : default:
4811 0 : aComputedValue.mXRepeat = value;
4812 0 : hasContraction = false;
4813 0 : break;
4814 : }
4815 :
4816 0 : if (hasContraction) {
4817 0 : NS_ASSERTION(aSpecifiedValue->mYValue.GetUnit() == eCSSUnit_Null,
4818 : "Invalid unit.");
4819 0 : return;
4820 : }
4821 :
4822 0 : switch (aSpecifiedValue->mYValue.GetUnit()) {
4823 : case eCSSUnit_Null:
4824 0 : aComputedValue.mYRepeat = aComputedValue.mXRepeat;
4825 0 : break;
4826 : case eCSSUnit_Enumerated:
4827 0 : value = aSpecifiedValue->mYValue.GetIntValue();
4828 0 : NS_ASSERTION(value == NS_STYLE_BG_REPEAT_NO_REPEAT ||
4829 : value == NS_STYLE_BG_REPEAT_REPEAT, "Unexpected value");
4830 0 : aComputedValue.mYRepeat = value;
4831 0 : break;
4832 : default:
4833 0 : NS_NOTREACHED("Unexpected CSS value");
4834 0 : break;
4835 : }
4836 : }
4837 : };
4838 :
4839 : template <>
4840 : struct BackgroundItemComputer<nsCSSValueList, nsStyleImage>
4841 : {
4842 0 : static void ComputeValue(nsStyleContext* aStyleContext,
4843 : const nsCSSValueList* aSpecifiedValue,
4844 : nsStyleImage& aComputedValue,
4845 : bool& aCanStoreInRuleTree)
4846 : {
4847 : SetStyleImage(aStyleContext, aSpecifiedValue->mValue, aComputedValue,
4848 0 : aCanStoreInRuleTree);
4849 0 : }
4850 : };
4851 :
4852 : /* Helper function for
4853 : * BackgroundItemComputer<nsCSSValue, nsStyleBackground::Position>
4854 : * It computes a single PositionCoord from an nsCSSValue object
4855 : * (contained in a list).
4856 : */
4857 : typedef nsStyleBackground::Position::PositionCoord PositionCoord;
4858 : static void
4859 0 : ComputeBackgroundPositionCoord(nsStyleContext* aStyleContext,
4860 : const nsCSSValue& aEdge,
4861 : const nsCSSValue& aOffset,
4862 : PositionCoord* aResult,
4863 : bool& aCanStoreInRuleTree)
4864 : {
4865 0 : if (eCSSUnit_Percent == aOffset.GetUnit()) {
4866 0 : aResult->mLength = 0;
4867 0 : aResult->mPercent = aOffset.GetPercentValue();
4868 0 : aResult->mHasPercent = true;
4869 0 : } else if (aOffset.IsLengthUnit()) {
4870 : aResult->mLength = CalcLength(aOffset, aStyleContext,
4871 : aStyleContext->PresContext(),
4872 0 : aCanStoreInRuleTree);
4873 0 : aResult->mPercent = 0.0f;
4874 0 : aResult->mHasPercent = false;
4875 0 : } else if (aOffset.IsCalcUnit()) {
4876 : LengthPercentPairCalcOps ops(aStyleContext,
4877 : aStyleContext->PresContext(),
4878 0 : aCanStoreInRuleTree);
4879 0 : nsRuleNode::ComputedCalc vals = ComputeCalc(aOffset, ops);
4880 0 : aResult->mLength = vals.mLength;
4881 0 : aResult->mPercent = vals.mPercent;
4882 0 : aResult->mHasPercent = ops.mHasPercent;
4883 : } else {
4884 0 : aResult->mLength = 0;
4885 0 : aResult->mPercent = 0.0f;
4886 0 : aResult->mHasPercent = false;
4887 0 : NS_ASSERTION(aOffset.GetUnit() == eCSSUnit_Null, "unexpected unit");
4888 : }
4889 :
4890 0 : if (eCSSUnit_Enumerated == aEdge.GetUnit()) {
4891 : int sign;
4892 0 : if (aEdge.GetIntValue() & (NS_STYLE_BG_POSITION_BOTTOM |
4893 : NS_STYLE_BG_POSITION_RIGHT)) {
4894 0 : sign = -1;
4895 : } else {
4896 0 : sign = 1;
4897 : }
4898 0 : aResult->mPercent = GetFloatFromBoxPosition(aEdge.GetIntValue()) +
4899 0 : sign * aResult->mPercent;
4900 0 : aResult->mLength = sign * aResult->mLength;
4901 0 : aResult->mHasPercent = true;
4902 : } else {
4903 0 : NS_ASSERTION(eCSSUnit_Null == aEdge.GetUnit(), "unexpected unit");
4904 : }
4905 0 : }
4906 :
4907 : template <>
4908 : struct BackgroundItemComputer<nsCSSValueList, nsStyleBackground::Position>
4909 : {
4910 0 : static void ComputeValue(nsStyleContext* aStyleContext,
4911 : const nsCSSValueList* aSpecifiedValue,
4912 : nsStyleBackground::Position& aComputedValue,
4913 : bool& aCanStoreInRuleTree)
4914 : {
4915 0 : NS_ASSERTION(aSpecifiedValue->mValue.GetUnit() == eCSSUnit_Array, "bg-position not an array");
4916 :
4917 : nsRefPtr<nsCSSValue::Array> bgPositionArray =
4918 0 : aSpecifiedValue->mValue.GetArrayValue();
4919 0 : const nsCSSValue &xEdge = bgPositionArray->Item(0);
4920 0 : const nsCSSValue &xOffset = bgPositionArray->Item(1);
4921 0 : const nsCSSValue &yEdge = bgPositionArray->Item(2);
4922 0 : const nsCSSValue &yOffset = bgPositionArray->Item(3);
4923 :
4924 0 : NS_ASSERTION((eCSSUnit_Enumerated == xEdge.GetUnit() ||
4925 : eCSSUnit_Null == xEdge.GetUnit()) &&
4926 : (eCSSUnit_Enumerated == yEdge.GetUnit() ||
4927 : eCSSUnit_Null == yEdge.GetUnit()) &&
4928 : eCSSUnit_Enumerated != xOffset.GetUnit() &&
4929 : eCSSUnit_Enumerated != yOffset.GetUnit(),
4930 : "Invalid background position");
4931 :
4932 : ComputeBackgroundPositionCoord(aStyleContext, xEdge, xOffset,
4933 : &aComputedValue.mXPosition,
4934 0 : aCanStoreInRuleTree);
4935 :
4936 : ComputeBackgroundPositionCoord(aStyleContext, yEdge, yOffset,
4937 : &aComputedValue.mYPosition,
4938 0 : aCanStoreInRuleTree);
4939 0 : }
4940 : };
4941 :
4942 :
4943 : struct BackgroundSizeAxis {
4944 : nsCSSValue nsCSSValuePairList::* specified;
4945 : nsStyleBackground::Size::Dimension nsStyleBackground::Size::* result;
4946 : PRUint8 nsStyleBackground::Size::* type;
4947 : };
4948 :
4949 : static const BackgroundSizeAxis gBGSizeAxes[] = {
4950 : { &nsCSSValuePairList::mXValue,
4951 : &nsStyleBackground::Size::mWidth,
4952 : &nsStyleBackground::Size::mWidthType },
4953 : { &nsCSSValuePairList::mYValue,
4954 : &nsStyleBackground::Size::mHeight,
4955 : &nsStyleBackground::Size::mHeightType }
4956 : };
4957 :
4958 : template <>
4959 : struct BackgroundItemComputer<nsCSSValuePairList, nsStyleBackground::Size>
4960 : {
4961 0 : static void ComputeValue(nsStyleContext* aStyleContext,
4962 : const nsCSSValuePairList* aSpecifiedValue,
4963 : nsStyleBackground::Size& aComputedValue,
4964 : bool& aCanStoreInRuleTree)
4965 : {
4966 0 : nsStyleBackground::Size &size = aComputedValue;
4967 0 : for (const BackgroundSizeAxis *axis = gBGSizeAxes,
4968 0 : *axis_end = ArrayEnd(gBGSizeAxes);
4969 : axis < axis_end; ++axis) {
4970 0 : const nsCSSValue &specified = aSpecifiedValue->*(axis->specified);
4971 0 : if (eCSSUnit_Auto == specified.GetUnit()) {
4972 0 : size.*(axis->type) = nsStyleBackground::Size::eAuto;
4973 : }
4974 0 : else if (eCSSUnit_Enumerated == specified.GetUnit()) {
4975 : MOZ_STATIC_ASSERT(nsStyleBackground::Size::eContain ==
4976 : NS_STYLE_BG_SIZE_CONTAIN &&
4977 : nsStyleBackground::Size::eCover ==
4978 : NS_STYLE_BG_SIZE_COVER,
4979 : "background size constants out of sync");
4980 0 : NS_ABORT_IF_FALSE(specified.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
4981 : specified.GetIntValue() == NS_STYLE_BG_SIZE_COVER,
4982 : "invalid enumerated value for size coordinate");
4983 0 : size.*(axis->type) = specified.GetIntValue();
4984 : }
4985 0 : else if (eCSSUnit_Null == specified.GetUnit()) {
4986 0 : NS_ABORT_IF_FALSE(axis == gBGSizeAxes + 1,
4987 : "null allowed only as height value, and only "
4988 : "for contain/cover/initial/inherit");
4989 : #ifdef DEBUG
4990 : {
4991 0 : const nsCSSValue &widthValue = aSpecifiedValue->mXValue;
4992 0 : NS_ABORT_IF_FALSE(widthValue.GetUnit() != eCSSUnit_Inherit &&
4993 : widthValue.GetUnit() != eCSSUnit_Initial,
4994 : "initial/inherit should already have been handled");
4995 0 : NS_ABORT_IF_FALSE(widthValue.GetUnit() == eCSSUnit_Enumerated &&
4996 : (widthValue.GetIntValue() == NS_STYLE_BG_SIZE_CONTAIN ||
4997 : widthValue.GetIntValue() == NS_STYLE_BG_SIZE_COVER),
4998 : "null height value not corresponding to allowable "
4999 : "non-null width value");
5000 : }
5001 : #endif
5002 0 : size.*(axis->type) = size.mWidthType;
5003 : }
5004 0 : else if (eCSSUnit_Percent == specified.GetUnit()) {
5005 0 : (size.*(axis->result)).mLength = 0;
5006 0 : (size.*(axis->result)).mPercent = specified.GetPercentValue();
5007 0 : (size.*(axis->result)).mHasPercent = true;
5008 0 : size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
5009 : }
5010 0 : else if (specified.IsLengthUnit()) {
5011 : (size.*(axis->result)).mLength =
5012 : CalcLength(specified, aStyleContext, aStyleContext->PresContext(),
5013 0 : aCanStoreInRuleTree);
5014 0 : (size.*(axis->result)).mPercent = 0.0f;
5015 0 : (size.*(axis->result)).mHasPercent = false;
5016 0 : size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
5017 : } else {
5018 0 : NS_ABORT_IF_FALSE(specified.IsCalcUnit(), "unexpected unit");
5019 : LengthPercentPairCalcOps ops(aStyleContext,
5020 : aStyleContext->PresContext(),
5021 0 : aCanStoreInRuleTree);
5022 0 : nsRuleNode::ComputedCalc vals = ComputeCalc(specified, ops);
5023 0 : (size.*(axis->result)).mLength = vals.mLength;
5024 0 : (size.*(axis->result)).mPercent = vals.mPercent;
5025 0 : (size.*(axis->result)).mHasPercent = ops.mHasPercent;
5026 0 : size.*(axis->type) = nsStyleBackground::Size::eLengthPercentage;
5027 : }
5028 : }
5029 :
5030 0 : NS_ABORT_IF_FALSE(size.mWidthType < nsStyleBackground::Size::eDimensionType_COUNT,
5031 : "bad width type");
5032 0 : NS_ABORT_IF_FALSE(size.mHeightType < nsStyleBackground::Size::eDimensionType_COUNT,
5033 : "bad height type");
5034 0 : NS_ABORT_IF_FALSE((size.mWidthType != nsStyleBackground::Size::eContain &&
5035 : size.mWidthType != nsStyleBackground::Size::eCover) ||
5036 : size.mWidthType == size.mHeightType,
5037 : "contain/cover apply to both dimensions or to neither");
5038 0 : }
5039 : };
5040 :
5041 : template <class ComputedValueItem>
5042 : static void
5043 0 : SetBackgroundList(nsStyleContext* aStyleContext,
5044 : const nsCSSValue& aValue,
5045 : nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
5046 : const nsAutoTArray<nsStyleBackground::Layer, 1> &aParentLayers,
5047 : ComputedValueItem nsStyleBackground::Layer::* aResultLocation,
5048 : ComputedValueItem aInitialValue,
5049 : PRUint32 aParentItemCount,
5050 : PRUint32& aItemCount,
5051 : PRUint32& aMaxItemCount,
5052 : bool& aRebuild,
5053 : bool& aCanStoreInRuleTree)
5054 : {
5055 0 : switch (aValue.GetUnit()) {
5056 : case eCSSUnit_Null:
5057 0 : break;
5058 :
5059 : case eCSSUnit_Inherit:
5060 0 : aRebuild = true;
5061 0 : aCanStoreInRuleTree = false;
5062 0 : if (!aLayers.EnsureLengthAtLeast(aParentItemCount)) {
5063 0 : NS_WARNING("out of memory");
5064 0 : aParentItemCount = aLayers.Length();
5065 : }
5066 0 : aItemCount = aParentItemCount;
5067 0 : for (PRUint32 i = 0; i < aParentItemCount; ++i) {
5068 0 : aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
5069 : }
5070 0 : break;
5071 :
5072 : case eCSSUnit_Initial:
5073 0 : aRebuild = true;
5074 0 : aItemCount = 1;
5075 0 : aLayers[0].*aResultLocation = aInitialValue;
5076 0 : break;
5077 :
5078 : case eCSSUnit_List:
5079 : case eCSSUnit_ListDep: {
5080 0 : aRebuild = true;
5081 0 : aItemCount = 0;
5082 0 : const nsCSSValueList* item = aValue.GetListValue();
5083 0 : do {
5084 0 : NS_ASSERTION(item->mValue.GetUnit() != eCSSUnit_Null &&
5085 : item->mValue.GetUnit() != eCSSUnit_Inherit &&
5086 : item->mValue.GetUnit() != eCSSUnit_Initial,
5087 : "unexpected unit");
5088 0 : ++aItemCount;
5089 0 : if (!aLayers.EnsureLengthAtLeast(aItemCount)) {
5090 0 : NS_WARNING("out of memory");
5091 0 : --aItemCount;
5092 0 : break;
5093 : }
5094 0 : BackgroundItemComputer<nsCSSValueList, ComputedValueItem>
5095 : ::ComputeValue(aStyleContext, item,
5096 : aLayers[aItemCount-1].*aResultLocation,
5097 : aCanStoreInRuleTree);
5098 0 : item = item->mNext;
5099 : } while (item);
5100 0 : break;
5101 : }
5102 :
5103 : default:
5104 0 : NS_ABORT_IF_FALSE(false,
5105 : nsPrintfCString(32, "unexpected unit %d",
5106 : aValue.GetUnit()).get());
5107 : }
5108 :
5109 0 : if (aItemCount > aMaxItemCount)
5110 0 : aMaxItemCount = aItemCount;
5111 0 : }
5112 :
5113 : template <class ComputedValueItem>
5114 : static void
5115 0 : SetBackgroundPairList(nsStyleContext* aStyleContext,
5116 : const nsCSSValue& aValue,
5117 : nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
5118 : const nsAutoTArray<nsStyleBackground::Layer, 1>
5119 : &aParentLayers,
5120 : ComputedValueItem nsStyleBackground::Layer::*
5121 : aResultLocation,
5122 : ComputedValueItem aInitialValue,
5123 : PRUint32 aParentItemCount,
5124 : PRUint32& aItemCount,
5125 : PRUint32& aMaxItemCount,
5126 : bool& aRebuild,
5127 : bool& aCanStoreInRuleTree)
5128 : {
5129 0 : switch (aValue.GetUnit()) {
5130 : case eCSSUnit_Null:
5131 0 : break;
5132 :
5133 : case eCSSUnit_Inherit:
5134 0 : aRebuild = true;
5135 0 : aCanStoreInRuleTree = false;
5136 0 : if (!aLayers.EnsureLengthAtLeast(aParentItemCount)) {
5137 0 : NS_WARNING("out of memory");
5138 0 : aParentItemCount = aLayers.Length();
5139 : }
5140 0 : aItemCount = aParentItemCount;
5141 0 : for (PRUint32 i = 0; i < aParentItemCount; ++i) {
5142 0 : aLayers[i].*aResultLocation = aParentLayers[i].*aResultLocation;
5143 : }
5144 0 : break;
5145 :
5146 : case eCSSUnit_Initial:
5147 0 : aRebuild = true;
5148 0 : aItemCount = 1;
5149 0 : aLayers[0].*aResultLocation = aInitialValue;
5150 0 : break;
5151 :
5152 : case eCSSUnit_PairList:
5153 : case eCSSUnit_PairListDep: {
5154 0 : aRebuild = true;
5155 0 : aItemCount = 0;
5156 0 : const nsCSSValuePairList* item = aValue.GetPairListValue();
5157 0 : do {
5158 0 : NS_ASSERTION(item->mXValue.GetUnit() != eCSSUnit_Inherit &&
5159 : item->mXValue.GetUnit() != eCSSUnit_Initial &&
5160 : item->mYValue.GetUnit() != eCSSUnit_Inherit &&
5161 : item->mYValue.GetUnit() != eCSSUnit_Initial,
5162 : "unexpected unit");
5163 0 : ++aItemCount;
5164 0 : if (!aLayers.EnsureLengthAtLeast(aItemCount)) {
5165 0 : NS_WARNING("out of memory");
5166 0 : --aItemCount;
5167 0 : break;
5168 : }
5169 0 : BackgroundItemComputer<nsCSSValuePairList, ComputedValueItem>
5170 : ::ComputeValue(aStyleContext, item,
5171 : aLayers[aItemCount-1].*aResultLocation,
5172 : aCanStoreInRuleTree);
5173 0 : item = item->mNext;
5174 : } while (item);
5175 0 : break;
5176 : }
5177 :
5178 : default:
5179 0 : NS_ABORT_IF_FALSE(false,
5180 : nsPrintfCString(32, "unexpected unit %d",
5181 : aValue.GetUnit()).get());
5182 : }
5183 :
5184 0 : if (aItemCount > aMaxItemCount)
5185 0 : aMaxItemCount = aItemCount;
5186 0 : }
5187 :
5188 : template <class ComputedValueItem>
5189 : static void
5190 0 : FillBackgroundList(nsAutoTArray< nsStyleBackground::Layer, 1> &aLayers,
5191 : ComputedValueItem nsStyleBackground::Layer::* aResultLocation,
5192 : PRUint32 aItemCount, PRUint32 aFillCount)
5193 : {
5194 0 : NS_PRECONDITION(aFillCount <= aLayers.Length(), "unexpected array length");
5195 0 : for (PRUint32 sourceLayer = 0, destLayer = aItemCount;
5196 : destLayer < aFillCount;
5197 : ++sourceLayer, ++destLayer) {
5198 0 : aLayers[destLayer].*aResultLocation =
5199 : aLayers[sourceLayer].*aResultLocation;
5200 : }
5201 0 : }
5202 :
5203 : const void*
5204 0 : nsRuleNode::ComputeBackgroundData(void* aStartStruct,
5205 : const nsRuleData* aRuleData,
5206 : nsStyleContext* aContext,
5207 : nsRuleNode* aHighestNode,
5208 : const RuleDetail aRuleDetail,
5209 : const bool aCanStoreInRuleTree)
5210 : {
5211 0 : COMPUTE_START_RESET(Background, (), bg, parentBG)
5212 :
5213 : // background-color: color, string, inherit
5214 0 : const nsCSSValue* backColorValue = aRuleData->ValueForBackgroundColor();
5215 0 : if (eCSSUnit_Initial == backColorValue->GetUnit()) {
5216 0 : bg->mBackgroundColor = NS_RGBA(0, 0, 0, 0);
5217 0 : } else if (!SetColor(*backColorValue, parentBG->mBackgroundColor,
5218 : mPresContext, aContext, bg->mBackgroundColor,
5219 0 : canStoreInRuleTree)) {
5220 0 : NS_ASSERTION(eCSSUnit_Null == backColorValue->GetUnit(),
5221 : "unexpected color unit");
5222 : }
5223 :
5224 0 : PRUint32 maxItemCount = 1;
5225 0 : bool rebuild = false;
5226 :
5227 : // background-image: url (stored as image), none, inherit [list]
5228 0 : nsStyleImage initialImage;
5229 0 : SetBackgroundList(aContext, *aRuleData->ValueForBackgroundImage(),
5230 : bg->mLayers,
5231 : parentBG->mLayers, &nsStyleBackground::Layer::mImage,
5232 : initialImage, parentBG->mImageCount, bg->mImageCount,
5233 0 : maxItemCount, rebuild, canStoreInRuleTree);
5234 :
5235 : // background-repeat: enum, inherit, initial [pair list]
5236 0 : nsStyleBackground::Repeat initialRepeat;
5237 0 : initialRepeat.SetInitialValues();
5238 0 : SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundRepeat(),
5239 : bg->mLayers,
5240 : parentBG->mLayers, &nsStyleBackground::Layer::mRepeat,
5241 : initialRepeat, parentBG->mRepeatCount,
5242 : bg->mRepeatCount, maxItemCount, rebuild,
5243 0 : canStoreInRuleTree);
5244 :
5245 : // background-attachment: enum, inherit, initial [list]
5246 0 : SetBackgroundList(aContext, *aRuleData->ValueForBackgroundAttachment(),
5247 : bg->mLayers, parentBG->mLayers,
5248 : &nsStyleBackground::Layer::mAttachment,
5249 : PRUint8(NS_STYLE_BG_ATTACHMENT_SCROLL),
5250 : parentBG->mAttachmentCount,
5251 : bg->mAttachmentCount, maxItemCount, rebuild,
5252 0 : canStoreInRuleTree);
5253 :
5254 : // background-clip: enum, inherit, initial [list]
5255 0 : SetBackgroundList(aContext, *aRuleData->ValueForBackgroundClip(),
5256 : bg->mLayers,
5257 : parentBG->mLayers, &nsStyleBackground::Layer::mClip,
5258 : PRUint8(NS_STYLE_BG_CLIP_BORDER), parentBG->mClipCount,
5259 0 : bg->mClipCount, maxItemCount, rebuild, canStoreInRuleTree);
5260 :
5261 : // background-inline-policy: enum, inherit, initial
5262 0 : SetDiscrete(*aRuleData->ValueForBackgroundInlinePolicy(),
5263 : bg->mBackgroundInlinePolicy,
5264 : canStoreInRuleTree, SETDSC_ENUMERATED,
5265 : parentBG->mBackgroundInlinePolicy,
5266 0 : NS_STYLE_BG_INLINE_POLICY_CONTINUOUS, 0, 0, 0, 0);
5267 :
5268 : // background-origin: enum, inherit, initial [list]
5269 0 : SetBackgroundList(aContext, *aRuleData->ValueForBackgroundOrigin(),
5270 : bg->mLayers,
5271 : parentBG->mLayers, &nsStyleBackground::Layer::mOrigin,
5272 : PRUint8(NS_STYLE_BG_ORIGIN_PADDING), parentBG->mOriginCount,
5273 : bg->mOriginCount, maxItemCount, rebuild,
5274 0 : canStoreInRuleTree);
5275 :
5276 : // background-position: enum, length, percent (flags), inherit [pair list]
5277 0 : nsStyleBackground::Position initialPosition;
5278 0 : initialPosition.SetInitialValues();
5279 0 : SetBackgroundList(aContext, *aRuleData->ValueForBackgroundPosition(),
5280 : bg->mLayers,
5281 : parentBG->mLayers, &nsStyleBackground::Layer::mPosition,
5282 : initialPosition, parentBG->mPositionCount,
5283 : bg->mPositionCount, maxItemCount, rebuild,
5284 0 : canStoreInRuleTree);
5285 :
5286 : // background-size: enum, length, auto, inherit, initial [pair list]
5287 0 : nsStyleBackground::Size initialSize;
5288 0 : initialSize.SetInitialValues();
5289 0 : SetBackgroundPairList(aContext, *aRuleData->ValueForBackgroundSize(),
5290 : bg->mLayers,
5291 : parentBG->mLayers, &nsStyleBackground::Layer::mSize,
5292 : initialSize, parentBG->mSizeCount,
5293 : bg->mSizeCount, maxItemCount, rebuild,
5294 0 : canStoreInRuleTree);
5295 :
5296 0 : if (rebuild) {
5297 : // Delete any extra items. We need to keep layers in which any
5298 : // property was specified.
5299 0 : bg->mLayers.TruncateLength(maxItemCount);
5300 :
5301 0 : PRUint32 fillCount = bg->mImageCount;
5302 : FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mImage,
5303 0 : bg->mImageCount, fillCount);
5304 : FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mRepeat,
5305 0 : bg->mRepeatCount, fillCount);
5306 : FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mAttachment,
5307 0 : bg->mAttachmentCount, fillCount);
5308 : FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mClip,
5309 0 : bg->mClipCount, fillCount);
5310 : FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mOrigin,
5311 0 : bg->mOriginCount, fillCount);
5312 : FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mPosition,
5313 0 : bg->mPositionCount, fillCount);
5314 : FillBackgroundList(bg->mLayers, &nsStyleBackground::Layer::mSize,
5315 0 : bg->mSizeCount, fillCount);
5316 : }
5317 :
5318 : // Now that the dust has settled, register the images with the document
5319 0 : for (PRUint32 i = 0; i < bg->mImageCount; ++i)
5320 0 : bg->mLayers[i].TrackImages(aContext->PresContext());
5321 :
5322 0 : COMPUTE_END_RESET(Background, bg)
5323 : }
5324 :
5325 : const void*
5326 0 : nsRuleNode::ComputeMarginData(void* aStartStruct,
5327 : const nsRuleData* aRuleData,
5328 : nsStyleContext* aContext,
5329 : nsRuleNode* aHighestNode,
5330 : const RuleDetail aRuleDetail,
5331 : const bool aCanStoreInRuleTree)
5332 : {
5333 0 : COMPUTE_START_RESET(Margin, (), margin, parentMargin)
5334 :
5335 : // margin: length, percent, auto, inherit
5336 0 : nsStyleCoord coord;
5337 0 : nsCSSRect ourMargin;
5338 0 : ourMargin.mTop = *aRuleData->ValueForMarginTop();
5339 0 : ourMargin.mRight = *aRuleData->ValueForMarginRightValue();
5340 0 : ourMargin.mBottom = *aRuleData->ValueForMarginBottom();
5341 0 : ourMargin.mLeft = *aRuleData->ValueForMarginLeftValue();
5342 : AdjustLogicalBoxProp(aContext,
5343 0 : *aRuleData->ValueForMarginLeftLTRSource(),
5344 0 : *aRuleData->ValueForMarginLeftRTLSource(),
5345 0 : *aRuleData->ValueForMarginStartValue(),
5346 0 : *aRuleData->ValueForMarginEndValue(),
5347 0 : NS_SIDE_LEFT, ourMargin, canStoreInRuleTree);
5348 : AdjustLogicalBoxProp(aContext,
5349 0 : *aRuleData->ValueForMarginRightLTRSource(),
5350 0 : *aRuleData->ValueForMarginRightRTLSource(),
5351 0 : *aRuleData->ValueForMarginEndValue(),
5352 0 : *aRuleData->ValueForMarginStartValue(),
5353 0 : NS_SIDE_RIGHT, ourMargin, canStoreInRuleTree);
5354 0 : NS_FOR_CSS_SIDES(side) {
5355 0 : nsStyleCoord parentCoord = parentMargin->mMargin.Get(side);
5356 0 : if (SetCoord(ourMargin.*(nsCSSRect::sides[side]),
5357 : coord, parentCoord,
5358 : SETCOORD_LPAH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC,
5359 0 : aContext, mPresContext, canStoreInRuleTree)) {
5360 0 : margin->mMargin.Set(side, coord);
5361 : }
5362 : }
5363 :
5364 0 : margin->RecalcData();
5365 0 : COMPUTE_END_RESET(Margin, margin)
5366 : }
5367 :
5368 : static void
5369 0 : SetBorderImageRect(const nsCSSValue& aValue,
5370 : /** outparam */ nsCSSRect& aRect)
5371 : {
5372 0 : switch (aValue.GetUnit()) {
5373 : case eCSSUnit_Null:
5374 0 : aRect.Reset();
5375 0 : break;
5376 : case eCSSUnit_Rect:
5377 0 : aRect = aValue.GetRectValue();
5378 0 : break;
5379 : case eCSSUnit_Inherit:
5380 : case eCSSUnit_Initial:
5381 0 : aRect.SetAllSidesTo(aValue);
5382 0 : break;
5383 : default:
5384 0 : NS_ASSERTION(false, "Unexpected border image value for rect.");
5385 : }
5386 0 : }
5387 :
5388 : static void
5389 0 : SetBorderImagePair(const nsCSSValue& aValue,
5390 : /** outparam */ nsCSSValuePair& aPair)
5391 : {
5392 0 : switch (aValue.GetUnit()) {
5393 : case eCSSUnit_Null:
5394 0 : aPair.Reset();
5395 0 : break;
5396 : case eCSSUnit_Pair:
5397 0 : aPair = aValue.GetPairValue();
5398 0 : break;
5399 : case eCSSUnit_Inherit:
5400 : case eCSSUnit_Initial:
5401 0 : aPair.SetBothValuesTo(aValue);
5402 0 : break;
5403 : default:
5404 0 : NS_ASSERTION(false, "Unexpected border image value for pair.");
5405 : }
5406 0 : }
5407 :
5408 : static void
5409 0 : SetBorderImageSlice(const nsCSSValue& aValue,
5410 : /** outparam */ nsCSSValue& aSlice,
5411 : /** outparam */ nsCSSValue& aFill)
5412 : {
5413 : const nsCSSValueList* valueList;
5414 0 : switch (aValue.GetUnit()) {
5415 : case eCSSUnit_Null:
5416 0 : aSlice.Reset();
5417 0 : aFill.Reset();
5418 0 : break;
5419 : case eCSSUnit_List:
5420 : // Get slice dimensions.
5421 0 : valueList = aValue.GetListValue();
5422 0 : aSlice = valueList->mValue;
5423 :
5424 : // Get "fill" keyword.
5425 0 : valueList = valueList->mNext;
5426 0 : if (valueList) {
5427 0 : aFill = valueList->mValue;
5428 : } else {
5429 0 : aFill.SetInitialValue();
5430 : }
5431 0 : break;
5432 : case eCSSUnit_Inherit:
5433 : case eCSSUnit_Initial:
5434 0 : aSlice = aValue;
5435 0 : aFill = aValue;
5436 0 : break;
5437 : default:
5438 0 : NS_ASSERTION(false, "Unexpected border image value for pair.");
5439 : }
5440 0 : }
5441 :
5442 : const void*
5443 0 : nsRuleNode::ComputeBorderData(void* aStartStruct,
5444 : const nsRuleData* aRuleData,
5445 : nsStyleContext* aContext,
5446 : nsRuleNode* aHighestNode,
5447 : const RuleDetail aRuleDetail,
5448 : const bool aCanStoreInRuleTree)
5449 : {
5450 0 : COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder)
5451 :
5452 : // box-shadow: none, list, inherit, initial
5453 0 : const nsCSSValue* boxShadowValue = aRuleData->ValueForBoxShadow();
5454 0 : switch (boxShadowValue->GetUnit()) {
5455 : case eCSSUnit_Null:
5456 0 : break;
5457 :
5458 : case eCSSUnit_Initial:
5459 : case eCSSUnit_None:
5460 0 : border->mBoxShadow = nsnull;
5461 0 : break;
5462 :
5463 : case eCSSUnit_Inherit:
5464 0 : border->mBoxShadow = parentBorder->mBoxShadow;
5465 0 : canStoreInRuleTree = false;
5466 0 : break;
5467 :
5468 : case eCSSUnit_List:
5469 : case eCSSUnit_ListDep:
5470 : border->mBoxShadow = GetShadowData(boxShadowValue->GetListValue(),
5471 0 : aContext, true, canStoreInRuleTree);
5472 0 : break;
5473 :
5474 : default:
5475 0 : NS_ABORT_IF_FALSE(false,
5476 : nsPrintfCString(64, "unrecognized shadow unit %d",
5477 : boxShadowValue->GetUnit()).get());
5478 : }
5479 :
5480 : // border-width, border-*-width: length, enum, inherit
5481 0 : nsStyleCoord coord;
5482 0 : nsCSSRect ourBorderWidth;
5483 0 : ourBorderWidth.mTop = *aRuleData->ValueForBorderTopWidth();
5484 0 : ourBorderWidth.mRight = *aRuleData->ValueForBorderRightWidthValue();
5485 0 : ourBorderWidth.mBottom = *aRuleData->ValueForBorderBottomWidth();
5486 0 : ourBorderWidth.mLeft = *aRuleData->ValueForBorderLeftWidthValue();
5487 : AdjustLogicalBoxProp(aContext,
5488 0 : *aRuleData->ValueForBorderLeftWidthLTRSource(),
5489 0 : *aRuleData->ValueForBorderLeftWidthRTLSource(),
5490 0 : *aRuleData->ValueForBorderStartWidthValue(),
5491 0 : *aRuleData->ValueForBorderEndWidthValue(),
5492 0 : NS_SIDE_LEFT, ourBorderWidth, canStoreInRuleTree);
5493 : AdjustLogicalBoxProp(aContext,
5494 0 : *aRuleData->ValueForBorderRightWidthLTRSource(),
5495 0 : *aRuleData->ValueForBorderRightWidthRTLSource(),
5496 0 : *aRuleData->ValueForBorderEndWidthValue(),
5497 0 : *aRuleData->ValueForBorderStartWidthValue(),
5498 0 : NS_SIDE_RIGHT, ourBorderWidth, canStoreInRuleTree);
5499 : { // scope for compilers with broken |for| loop scoping
5500 0 : NS_FOR_CSS_SIDES(side) {
5501 0 : const nsCSSValue &value = ourBorderWidth.*(nsCSSRect::sides[side]);
5502 0 : NS_ASSERTION(eCSSUnit_Percent != value.GetUnit(),
5503 : "Percentage borders not implemented yet "
5504 : "If implementing, make sure to fix all consumers of "
5505 : "nsStyleBorder, the IsPercentageAwareChild method, "
5506 : "the nsAbsoluteContainingBlock::FrameDependsOnContainer "
5507 : "method, the "
5508 : "nsLineLayout::IsPercentageAwareReplacedElement method "
5509 : "and probably some other places");
5510 0 : if (eCSSUnit_Enumerated == value.GetUnit()) {
5511 0 : NS_ASSERTION(value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
5512 : value.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
5513 : value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
5514 : "Unexpected enum value");
5515 : border->SetBorderWidth(side,
5516 0 : (mPresContext->GetBorderWidthTable())[value.GetIntValue()]);
5517 : }
5518 : // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
5519 0 : else if (SetCoord(value, coord, nsStyleCoord(),
5520 : SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
5521 0 : aContext, mPresContext, canStoreInRuleTree)) {
5522 0 : NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
5523 : // clamp negative calc() to 0.
5524 0 : border->SetBorderWidth(side, NS_MAX(coord.GetCoordValue(), 0));
5525 : }
5526 0 : else if (eCSSUnit_Inherit == value.GetUnit()) {
5527 0 : canStoreInRuleTree = false;
5528 : border->SetBorderWidth(side,
5529 0 : parentBorder->GetComputedBorder().Side(side));
5530 : }
5531 0 : else if (eCSSUnit_Initial == value.GetUnit()) {
5532 : border->SetBorderWidth(side,
5533 0 : (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
5534 : }
5535 : else {
5536 0 : NS_ASSERTION(eCSSUnit_Null == value.GetUnit(),
5537 : "missing case handling border width");
5538 : }
5539 : }
5540 : }
5541 :
5542 : // border-style, border-*-style: enum, inherit
5543 0 : nsCSSRect ourBorderStyle;
5544 0 : ourBorderStyle.mTop = *aRuleData->ValueForBorderTopStyle();
5545 0 : ourBorderStyle.mRight = *aRuleData->ValueForBorderRightStyleValue();
5546 0 : ourBorderStyle.mBottom = *aRuleData->ValueForBorderBottomStyle();
5547 0 : ourBorderStyle.mLeft = *aRuleData->ValueForBorderLeftStyleValue();
5548 : AdjustLogicalBoxProp(aContext,
5549 0 : *aRuleData->ValueForBorderLeftStyleLTRSource(),
5550 0 : *aRuleData->ValueForBorderLeftStyleRTLSource(),
5551 0 : *aRuleData->ValueForBorderStartStyleValue(),
5552 0 : *aRuleData->ValueForBorderEndStyleValue(),
5553 0 : NS_SIDE_LEFT, ourBorderStyle, canStoreInRuleTree);
5554 : AdjustLogicalBoxProp(aContext,
5555 0 : *aRuleData->ValueForBorderRightStyleLTRSource(),
5556 0 : *aRuleData->ValueForBorderRightStyleRTLSource(),
5557 0 : *aRuleData->ValueForBorderEndStyleValue(),
5558 0 : *aRuleData->ValueForBorderStartStyleValue(),
5559 0 : NS_SIDE_RIGHT, ourBorderStyle, canStoreInRuleTree);
5560 : { // scope for compilers with broken |for| loop scoping
5561 0 : NS_FOR_CSS_SIDES(side) {
5562 0 : const nsCSSValue &value = ourBorderStyle.*(nsCSSRect::sides[side]);
5563 0 : nsCSSUnit unit = value.GetUnit();
5564 0 : NS_ABORT_IF_FALSE(eCSSUnit_None != unit,
5565 : "'none' should be handled as enumerated value");
5566 0 : if (eCSSUnit_Enumerated == unit) {
5567 0 : border->SetBorderStyle(side, value.GetIntValue());
5568 : }
5569 0 : else if (eCSSUnit_Initial == unit) {
5570 0 : border->SetBorderStyle(side, NS_STYLE_BORDER_STYLE_NONE);
5571 : }
5572 0 : else if (eCSSUnit_Inherit == unit) {
5573 0 : canStoreInRuleTree = false;
5574 0 : border->SetBorderStyle(side, parentBorder->GetBorderStyle(side));
5575 : }
5576 : }
5577 : }
5578 :
5579 : // -moz-border-*-colors: color, string, enum, none, inherit/initial
5580 : nscolor borderColor;
5581 0 : nscolor unused = NS_RGB(0,0,0);
5582 :
5583 : static const nsCSSProperty borderColorsProps[] = {
5584 : eCSSProperty_border_top_colors,
5585 : eCSSProperty_border_right_colors,
5586 : eCSSProperty_border_bottom_colors,
5587 : eCSSProperty_border_left_colors
5588 : };
5589 :
5590 0 : NS_FOR_CSS_SIDES(side) {
5591 0 : const nsCSSValue& value = *aRuleData->ValueFor(borderColorsProps[side]);
5592 0 : switch (value.GetUnit()) {
5593 : case eCSSUnit_Null:
5594 0 : break;
5595 :
5596 : case eCSSUnit_Initial:
5597 : case eCSSUnit_None:
5598 0 : border->ClearBorderColors(side);
5599 0 : break;
5600 :
5601 : case eCSSUnit_Inherit: {
5602 0 : canStoreInRuleTree = false;
5603 : nsBorderColors *parentColors;
5604 0 : parentBorder->GetCompositeColors(side, &parentColors);
5605 0 : if (parentColors) {
5606 0 : border->EnsureBorderColors();
5607 0 : border->ClearBorderColors(side);
5608 0 : border->mBorderColors[side] = parentColors->Clone();
5609 : } else {
5610 0 : border->ClearBorderColors(side);
5611 : }
5612 0 : break;
5613 : }
5614 :
5615 : case eCSSUnit_List:
5616 : case eCSSUnit_ListDep: {
5617 : // Some composite border color information has been specified for this
5618 : // border side.
5619 0 : border->EnsureBorderColors();
5620 0 : border->ClearBorderColors(side);
5621 0 : const nsCSSValueList* list = value.GetListValue();
5622 0 : while (list) {
5623 0 : if (SetColor(list->mValue, unused, mPresContext,
5624 0 : aContext, borderColor, canStoreInRuleTree))
5625 0 : border->AppendBorderColor(side, borderColor);
5626 : else {
5627 0 : NS_NOTREACHED("unexpected item in -moz-border-*-colors list");
5628 : }
5629 0 : list = list->mNext;
5630 : }
5631 0 : break;
5632 : }
5633 :
5634 : default:
5635 0 : NS_ABORT_IF_FALSE(false, "unrecognized border color unit");
5636 : }
5637 : }
5638 :
5639 : // border-color, border-*-color: color, string, enum, inherit
5640 : bool foreground;
5641 0 : nsCSSRect ourBorderColor;
5642 0 : ourBorderColor.mTop = *aRuleData->ValueForBorderTopColor();
5643 0 : ourBorderColor.mRight = *aRuleData->ValueForBorderRightColorValue();
5644 0 : ourBorderColor.mBottom = *aRuleData->ValueForBorderBottomColor();
5645 0 : ourBorderColor.mLeft = *aRuleData->ValueForBorderLeftColorValue();
5646 : AdjustLogicalBoxProp(aContext,
5647 0 : *aRuleData->ValueForBorderLeftColorLTRSource(),
5648 0 : *aRuleData->ValueForBorderLeftColorRTLSource(),
5649 0 : *aRuleData->ValueForBorderStartColorValue(),
5650 0 : *aRuleData->ValueForBorderEndColorValue(),
5651 0 : NS_SIDE_LEFT, ourBorderColor, canStoreInRuleTree);
5652 : AdjustLogicalBoxProp(aContext,
5653 0 : *aRuleData->ValueForBorderRightColorLTRSource(),
5654 0 : *aRuleData->ValueForBorderRightColorRTLSource(),
5655 0 : *aRuleData->ValueForBorderEndColorValue(),
5656 0 : *aRuleData->ValueForBorderStartColorValue(),
5657 0 : NS_SIDE_RIGHT, ourBorderColor, canStoreInRuleTree);
5658 : { // scope for compilers with broken |for| loop scoping
5659 0 : NS_FOR_CSS_SIDES(side) {
5660 0 : const nsCSSValue &value = ourBorderColor.*(nsCSSRect::sides[side]);
5661 0 : if (eCSSUnit_Inherit == value.GetUnit()) {
5662 0 : canStoreInRuleTree = false;
5663 0 : if (parentContext) {
5664 0 : parentBorder->GetBorderColor(side, borderColor, foreground);
5665 0 : if (foreground) {
5666 : // We want to inherit the color from the parent, not use the
5667 : // color on the element where this chunk of style data will be
5668 : // used. We can ensure that the data for the parent are fully
5669 : // computed (unlike for the element where this will be used, for
5670 : // which the color could be specified on a more specific rule).
5671 0 : border->SetBorderColor(side, parentContext->GetStyleColor()->mColor);
5672 : } else
5673 0 : border->SetBorderColor(side, borderColor);
5674 : } else {
5675 : // We're the root
5676 0 : border->SetBorderToForeground(side);
5677 : }
5678 : }
5679 0 : else if (SetColor(value, unused, mPresContext, aContext, borderColor,
5680 0 : canStoreInRuleTree)) {
5681 0 : border->SetBorderColor(side, borderColor);
5682 : }
5683 0 : else if (eCSSUnit_Enumerated == value.GetUnit()) {
5684 0 : switch (value.GetIntValue()) {
5685 : case NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR:
5686 0 : border->SetBorderToForeground(side);
5687 0 : break;
5688 : default:
5689 0 : NS_NOTREACHED("Unexpected enumerated color");
5690 0 : break;
5691 : }
5692 : }
5693 0 : else if (eCSSUnit_Initial == value.GetUnit()) {
5694 0 : border->SetBorderToForeground(side);
5695 : }
5696 : }
5697 : }
5698 :
5699 : // border-radius: length, percent, inherit
5700 : {
5701 : const nsCSSProperty* subprops =
5702 0 : nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius);
5703 0 : NS_FOR_CSS_FULL_CORNERS(corner) {
5704 0 : int cx = NS_FULL_TO_HALF_CORNER(corner, false);
5705 0 : int cy = NS_FULL_TO_HALF_CORNER(corner, true);
5706 0 : const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
5707 0 : nsStyleCoord parentX = parentBorder->mBorderRadius.Get(cx);
5708 0 : nsStyleCoord parentY = parentBorder->mBorderRadius.Get(cy);
5709 0 : nsStyleCoord coordX, coordY;
5710 :
5711 0 : if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
5712 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
5713 : SETCOORD_STORE_CALC,
5714 0 : aContext, mPresContext, canStoreInRuleTree)) {
5715 0 : border->mBorderRadius.Set(cx, coordX);
5716 0 : border->mBorderRadius.Set(cy, coordY);
5717 : }
5718 : }
5719 : }
5720 :
5721 : // float-edge: enum, inherit, initial
5722 0 : SetDiscrete(*aRuleData->ValueForFloatEdge(),
5723 : border->mFloatEdge, canStoreInRuleTree,
5724 : SETDSC_ENUMERATED, parentBorder->mFloatEdge,
5725 0 : NS_STYLE_FLOAT_EDGE_CONTENT, 0, 0, 0, 0);
5726 :
5727 : // border-image-source
5728 0 : const nsCSSValue* borderImageSource = aRuleData->ValueForBorderImageSource();
5729 0 : if (borderImageSource->GetUnit() == eCSSUnit_Image) {
5730 0 : NS_SET_IMAGE_REQUEST(border->SetBorderImage, aContext,
5731 : borderImageSource->GetImageValue());
5732 0 : } else if (borderImageSource->GetUnit() == eCSSUnit_Inherit) {
5733 0 : canStoreInRuleTree = false;
5734 0 : NS_SET_IMAGE_REQUEST(border->SetBorderImage, aContext,
5735 : parentBorder->GetBorderImage());
5736 0 : } else if (borderImageSource->GetUnit() == eCSSUnit_Initial ||
5737 0 : borderImageSource->GetUnit() == eCSSUnit_None) {
5738 0 : border->SetBorderImage(nsnull);
5739 : }
5740 :
5741 0 : nsCSSValue borderImageSliceValue;
5742 0 : nsCSSValue borderImageSliceFill;
5743 0 : SetBorderImageSlice(*aRuleData->ValueForBorderImageSlice(),
5744 0 : borderImageSliceValue, borderImageSliceFill);
5745 :
5746 : // border-image-slice: fill
5747 : SetDiscrete(borderImageSliceFill,
5748 : border->mBorderImageFill,
5749 : canStoreInRuleTree, SETDSC_ENUMERATED,
5750 : parentBorder->mBorderImageFill,
5751 0 : NS_STYLE_BORDER_IMAGE_SLICE_NOFILL, 0, 0, 0, 0);
5752 :
5753 0 : nsCSSRect borderImageSlice;
5754 0 : SetBorderImageRect(borderImageSliceValue, borderImageSlice);
5755 :
5756 0 : nsCSSRect borderImageWidth;
5757 0 : SetBorderImageRect(*aRuleData->ValueForBorderImageWidth(),
5758 0 : borderImageWidth);
5759 :
5760 0 : nsCSSRect borderImageOutset;
5761 0 : SetBorderImageRect(*aRuleData->ValueForBorderImageOutset(),
5762 0 : borderImageOutset);
5763 :
5764 0 : NS_FOR_CSS_SIDES (side) {
5765 : // border-image-slice
5766 0 : if (SetCoord(borderImageSlice.*(nsCSSRect::sides[side]), coord,
5767 : parentBorder->mBorderImageSlice.Get(side),
5768 : SETCOORD_FACTOR | SETCOORD_PERCENT |
5769 : SETCOORD_INHERIT | SETCOORD_INITIAL_HUNDRED_PCT,
5770 0 : aContext, mPresContext, canStoreInRuleTree)) {
5771 0 : border->mBorderImageSlice.Set(side, coord);
5772 : }
5773 :
5774 : // border-image-width
5775 : // 'auto' here means "same as slice"
5776 0 : if (SetCoord(borderImageWidth.*(nsCSSRect::sides[side]), coord,
5777 : parentBorder->mBorderImageWidth.Get(side),
5778 : SETCOORD_LPAH | SETCOORD_FACTOR | SETCOORD_INITIAL_FACTOR_ONE,
5779 0 : aContext, mPresContext, canStoreInRuleTree)) {
5780 0 : border->mBorderImageWidth.Set(side, coord);
5781 : }
5782 :
5783 : // border-image-outset
5784 0 : if (SetCoord(borderImageOutset.*(nsCSSRect::sides[side]), coord,
5785 : parentBorder->mBorderImageOutset.Get(side),
5786 : SETCOORD_LENGTH | SETCOORD_FACTOR |
5787 : SETCOORD_INHERIT | SETCOORD_INITIAL_FACTOR_ZERO,
5788 0 : aContext, mPresContext, canStoreInRuleTree)) {
5789 0 : border->mBorderImageOutset.Set(side, coord);
5790 : }
5791 : }
5792 :
5793 : // border-image-repeat
5794 0 : nsCSSValuePair borderImageRepeat;
5795 0 : SetBorderImagePair(*aRuleData->ValueForBorderImageRepeat(),
5796 0 : borderImageRepeat);
5797 :
5798 : SetDiscrete(borderImageRepeat.mXValue,
5799 : border->mBorderImageRepeatH,
5800 : canStoreInRuleTree, SETDSC_ENUMERATED,
5801 : parentBorder->mBorderImageRepeatH,
5802 0 : NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
5803 :
5804 : SetDiscrete(borderImageRepeat.mYValue,
5805 : border->mBorderImageRepeatV,
5806 : canStoreInRuleTree, SETDSC_ENUMERATED,
5807 : parentBorder->mBorderImageRepeatV,
5808 0 : NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 0, 0, 0, 0);
5809 :
5810 0 : if (border->HasBorderImage())
5811 0 : border->TrackImage(aContext->PresContext());
5812 :
5813 0 : COMPUTE_END_RESET(Border, border)
5814 : }
5815 :
5816 : const void*
5817 0 : nsRuleNode::ComputePaddingData(void* aStartStruct,
5818 : const nsRuleData* aRuleData,
5819 : nsStyleContext* aContext,
5820 : nsRuleNode* aHighestNode,
5821 : const RuleDetail aRuleDetail,
5822 : const bool aCanStoreInRuleTree)
5823 : {
5824 0 : COMPUTE_START_RESET(Padding, (), padding, parentPadding)
5825 :
5826 : // padding: length, percent, inherit
5827 0 : nsStyleCoord coord;
5828 0 : nsCSSRect ourPadding;
5829 0 : ourPadding.mTop = *aRuleData->ValueForPaddingTop();
5830 0 : ourPadding.mRight = *aRuleData->ValueForPaddingRightValue();
5831 0 : ourPadding.mBottom = *aRuleData->ValueForPaddingBottom();
5832 0 : ourPadding.mLeft = *aRuleData->ValueForPaddingLeftValue();
5833 : AdjustLogicalBoxProp(aContext,
5834 0 : *aRuleData->ValueForPaddingLeftLTRSource(),
5835 0 : *aRuleData->ValueForPaddingLeftRTLSource(),
5836 0 : *aRuleData->ValueForPaddingStartValue(),
5837 0 : *aRuleData->ValueForPaddingEndValue(),
5838 0 : NS_SIDE_LEFT, ourPadding, canStoreInRuleTree);
5839 : AdjustLogicalBoxProp(aContext,
5840 0 : *aRuleData->ValueForPaddingRightLTRSource(),
5841 0 : *aRuleData->ValueForPaddingRightRTLSource(),
5842 0 : *aRuleData->ValueForPaddingEndValue(),
5843 0 : *aRuleData->ValueForPaddingStartValue(),
5844 0 : NS_SIDE_RIGHT, ourPadding, canStoreInRuleTree);
5845 0 : NS_FOR_CSS_SIDES(side) {
5846 0 : nsStyleCoord parentCoord = parentPadding->mPadding.Get(side);
5847 0 : if (SetCoord(ourPadding.*(nsCSSRect::sides[side]),
5848 : coord, parentCoord,
5849 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC,
5850 0 : aContext, mPresContext, canStoreInRuleTree)) {
5851 0 : padding->mPadding.Set(side, coord);
5852 : }
5853 : }
5854 :
5855 0 : padding->RecalcData();
5856 0 : COMPUTE_END_RESET(Padding, padding)
5857 : }
5858 :
5859 : const void*
5860 0 : nsRuleNode::ComputeOutlineData(void* aStartStruct,
5861 : const nsRuleData* aRuleData,
5862 : nsStyleContext* aContext,
5863 : nsRuleNode* aHighestNode,
5864 : const RuleDetail aRuleDetail,
5865 : const bool aCanStoreInRuleTree)
5866 : {
5867 0 : COMPUTE_START_RESET(Outline, (mPresContext), outline, parentOutline)
5868 :
5869 : // outline-width: length, enum, inherit
5870 0 : const nsCSSValue* outlineWidthValue = aRuleData->ValueForOutlineWidth();
5871 0 : if (eCSSUnit_Initial == outlineWidthValue->GetUnit()) {
5872 : outline->mOutlineWidth =
5873 0 : nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
5874 : }
5875 : else {
5876 : SetCoord(*outlineWidthValue, outline->mOutlineWidth,
5877 : parentOutline->mOutlineWidth,
5878 : SETCOORD_LEH | SETCOORD_CALC_LENGTH_ONLY, aContext,
5879 0 : mPresContext, canStoreInRuleTree);
5880 : }
5881 :
5882 : // outline-offset: length, inherit
5883 0 : nsStyleCoord tempCoord;
5884 0 : const nsCSSValue* outlineOffsetValue = aRuleData->ValueForOutlineOffset();
5885 0 : if (SetCoord(*outlineOffsetValue, tempCoord,
5886 : nsStyleCoord(parentOutline->mOutlineOffset,
5887 : nsStyleCoord::CoordConstructor),
5888 : SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY,
5889 0 : aContext, mPresContext, canStoreInRuleTree)) {
5890 0 : outline->mOutlineOffset = tempCoord.GetCoordValue();
5891 : } else {
5892 0 : NS_ASSERTION(outlineOffsetValue->GetUnit() == eCSSUnit_Null,
5893 : "unexpected unit");
5894 : }
5895 :
5896 : // outline-color: color, string, enum, inherit
5897 : nscolor outlineColor;
5898 0 : nscolor unused = NS_RGB(0,0,0);
5899 0 : const nsCSSValue* outlineColorValue = aRuleData->ValueForOutlineColor();
5900 0 : if (eCSSUnit_Inherit == outlineColorValue->GetUnit()) {
5901 0 : canStoreInRuleTree = false;
5902 0 : if (parentContext) {
5903 0 : if (parentOutline->GetOutlineColor(outlineColor))
5904 0 : outline->SetOutlineColor(outlineColor);
5905 : else {
5906 : // We want to inherit the color from the parent, not use the
5907 : // color on the element where this chunk of style data will be
5908 : // used. We can ensure that the data for the parent are fully
5909 : // computed (unlike for the element where this will be used, for
5910 : // which the color could be specified on a more specific rule).
5911 0 : outline->SetOutlineColor(parentContext->GetStyleColor()->mColor);
5912 : }
5913 : } else {
5914 0 : outline->SetOutlineInitialColor();
5915 : }
5916 : }
5917 0 : else if (SetColor(*outlineColorValue, unused, mPresContext,
5918 0 : aContext, outlineColor, canStoreInRuleTree))
5919 0 : outline->SetOutlineColor(outlineColor);
5920 0 : else if (eCSSUnit_Enumerated == outlineColorValue->GetUnit() ||
5921 0 : eCSSUnit_Initial == outlineColorValue->GetUnit()) {
5922 0 : outline->SetOutlineInitialColor();
5923 : }
5924 :
5925 : // -moz-outline-radius: length, percent, inherit
5926 : {
5927 : const nsCSSProperty* subprops =
5928 0 : nsCSSProps::SubpropertyEntryFor(eCSSProperty__moz_outline_radius);
5929 0 : NS_FOR_CSS_FULL_CORNERS(corner) {
5930 0 : int cx = NS_FULL_TO_HALF_CORNER(corner, false);
5931 0 : int cy = NS_FULL_TO_HALF_CORNER(corner, true);
5932 0 : const nsCSSValue& radius = *aRuleData->ValueFor(subprops[corner]);
5933 0 : nsStyleCoord parentX = parentOutline->mOutlineRadius.Get(cx);
5934 0 : nsStyleCoord parentY = parentOutline->mOutlineRadius.Get(cy);
5935 0 : nsStyleCoord coordX, coordY;
5936 :
5937 0 : if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
5938 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
5939 : SETCOORD_STORE_CALC,
5940 0 : aContext, mPresContext, canStoreInRuleTree)) {
5941 0 : outline->mOutlineRadius.Set(cx, coordX);
5942 0 : outline->mOutlineRadius.Set(cy, coordY);
5943 : }
5944 : }
5945 : }
5946 :
5947 : // outline-style: enum, inherit, initial
5948 : // cannot use SetDiscrete because of SetOutlineStyle
5949 0 : const nsCSSValue* outlineStyleValue = aRuleData->ValueForOutlineStyle();
5950 0 : nsCSSUnit unit = outlineStyleValue->GetUnit();
5951 0 : NS_ABORT_IF_FALSE(eCSSUnit_None != unit && eCSSUnit_Auto != unit,
5952 : "'none' and 'auto' should be handled as enumerated values");
5953 0 : if (eCSSUnit_Enumerated == unit) {
5954 0 : outline->SetOutlineStyle(outlineStyleValue->GetIntValue());
5955 0 : } else if (eCSSUnit_Initial == unit) {
5956 0 : outline->SetOutlineStyle(NS_STYLE_BORDER_STYLE_NONE);
5957 0 : } else if (eCSSUnit_Inherit == unit) {
5958 0 : canStoreInRuleTree = false;
5959 0 : outline->SetOutlineStyle(parentOutline->GetOutlineStyle());
5960 : }
5961 :
5962 0 : outline->RecalcData(mPresContext);
5963 0 : COMPUTE_END_RESET(Outline, outline)
5964 : }
5965 :
5966 : const void*
5967 0 : nsRuleNode::ComputeListData(void* aStartStruct,
5968 : const nsRuleData* aRuleData,
5969 : nsStyleContext* aContext,
5970 : nsRuleNode* aHighestNode,
5971 : const RuleDetail aRuleDetail,
5972 : const bool aCanStoreInRuleTree)
5973 : {
5974 0 : COMPUTE_START_INHERITED(List, (), list, parentList)
5975 :
5976 : // list-style-type: enum, inherit, initial
5977 0 : SetDiscrete(*aRuleData->ValueForListStyleType(),
5978 : list->mListStyleType, canStoreInRuleTree,
5979 : SETDSC_ENUMERATED, parentList->mListStyleType,
5980 0 : NS_STYLE_LIST_STYLE_DISC, 0, 0, 0, 0);
5981 :
5982 : // list-style-image: url, none, inherit
5983 0 : const nsCSSValue* imageValue = aRuleData->ValueForListStyleImage();
5984 0 : if (eCSSUnit_Image == imageValue->GetUnit()) {
5985 0 : NS_SET_IMAGE_REQUEST(list->SetListStyleImage,
5986 : aContext,
5987 : imageValue->GetImageValue())
5988 : }
5989 0 : else if (eCSSUnit_None == imageValue->GetUnit() ||
5990 0 : eCSSUnit_Initial == imageValue->GetUnit()) {
5991 0 : list->SetListStyleImage(nsnull);
5992 : }
5993 0 : else if (eCSSUnit_Inherit == imageValue->GetUnit()) {
5994 0 : canStoreInRuleTree = false;
5995 0 : NS_SET_IMAGE_REQUEST(list->SetListStyleImage,
5996 : aContext,
5997 : parentList->GetListStyleImage())
5998 : }
5999 :
6000 : // list-style-position: enum, inherit, initial
6001 0 : SetDiscrete(*aRuleData->ValueForListStylePosition(),
6002 : list->mListStylePosition, canStoreInRuleTree,
6003 : SETDSC_ENUMERATED, parentList->mListStylePosition,
6004 0 : NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, 0, 0, 0, 0);
6005 :
6006 : // image region property: length, auto, inherit
6007 0 : const nsCSSValue* imageRegionValue = aRuleData->ValueForImageRegion();
6008 0 : switch (imageRegionValue->GetUnit()) {
6009 : case eCSSUnit_Inherit:
6010 0 : canStoreInRuleTree = false;
6011 0 : list->mImageRegion = parentList->mImageRegion;
6012 0 : break;
6013 :
6014 : case eCSSUnit_Initial:
6015 : case eCSSUnit_Auto:
6016 0 : list->mImageRegion.SetRect(0,0,0,0);
6017 0 : break;
6018 :
6019 : case eCSSUnit_Null:
6020 0 : break;
6021 :
6022 : case eCSSUnit_Rect: {
6023 0 : const nsCSSRect& rgnRect = imageRegionValue->GetRectValue();
6024 :
6025 0 : if (rgnRect.mTop.GetUnit() == eCSSUnit_Auto)
6026 0 : list->mImageRegion.y = 0;
6027 0 : else if (rgnRect.mTop.IsLengthUnit())
6028 : list->mImageRegion.y =
6029 0 : CalcLength(rgnRect.mTop, aContext, mPresContext, canStoreInRuleTree);
6030 :
6031 0 : if (rgnRect.mBottom.GetUnit() == eCSSUnit_Auto)
6032 0 : list->mImageRegion.height = 0;
6033 0 : else if (rgnRect.mBottom.IsLengthUnit())
6034 : list->mImageRegion.height =
6035 : CalcLength(rgnRect.mBottom, aContext, mPresContext,
6036 0 : canStoreInRuleTree) - list->mImageRegion.y;
6037 :
6038 0 : if (rgnRect.mLeft.GetUnit() == eCSSUnit_Auto)
6039 0 : list->mImageRegion.x = 0;
6040 0 : else if (rgnRect.mLeft.IsLengthUnit())
6041 : list->mImageRegion.x =
6042 0 : CalcLength(rgnRect.mLeft, aContext, mPresContext, canStoreInRuleTree);
6043 :
6044 0 : if (rgnRect.mRight.GetUnit() == eCSSUnit_Auto)
6045 0 : list->mImageRegion.width = 0;
6046 0 : else if (rgnRect.mRight.IsLengthUnit())
6047 : list->mImageRegion.width =
6048 : CalcLength(rgnRect.mRight, aContext, mPresContext,
6049 0 : canStoreInRuleTree) - list->mImageRegion.x;
6050 0 : break;
6051 : }
6052 :
6053 : default:
6054 0 : NS_ABORT_IF_FALSE(false, "unrecognized image-region unit");
6055 : }
6056 :
6057 0 : COMPUTE_END_INHERITED(List, list)
6058 : }
6059 :
6060 : const void*
6061 0 : nsRuleNode::ComputePositionData(void* aStartStruct,
6062 : const nsRuleData* aRuleData,
6063 : nsStyleContext* aContext,
6064 : nsRuleNode* aHighestNode,
6065 : const RuleDetail aRuleDetail,
6066 : const bool aCanStoreInRuleTree)
6067 : {
6068 0 : COMPUTE_START_RESET(Position, (), pos, parentPos)
6069 :
6070 : // box offsets: length, percent, calc, auto, inherit
6071 : static const nsCSSProperty offsetProps[] = {
6072 : eCSSProperty_top,
6073 : eCSSProperty_right,
6074 : eCSSProperty_bottom,
6075 : eCSSProperty_left
6076 : };
6077 0 : nsStyleCoord coord;
6078 0 : NS_FOR_CSS_SIDES(side) {
6079 0 : nsStyleCoord parentCoord = parentPos->mOffset.Get(side);
6080 0 : if (SetCoord(*aRuleData->ValueFor(offsetProps[side]),
6081 : coord, parentCoord,
6082 : SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC,
6083 0 : aContext, mPresContext, canStoreInRuleTree)) {
6084 0 : pos->mOffset.Set(side, coord);
6085 : }
6086 : }
6087 :
6088 0 : SetCoord(*aRuleData->ValueForWidth(), pos->mWidth, parentPos->mWidth,
6089 : SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC,
6090 0 : aContext, mPresContext, canStoreInRuleTree);
6091 0 : SetCoord(*aRuleData->ValueForMinWidth(), pos->mMinWidth, parentPos->mMinWidth,
6092 : SETCOORD_LPEH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC,
6093 0 : aContext, mPresContext, canStoreInRuleTree);
6094 0 : SetCoord(*aRuleData->ValueForMaxWidth(), pos->mMaxWidth, parentPos->mMaxWidth,
6095 : SETCOORD_LPOEH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC,
6096 0 : aContext, mPresContext, canStoreInRuleTree);
6097 :
6098 0 : SetCoord(*aRuleData->ValueForHeight(), pos->mHeight, parentPos->mHeight,
6099 : SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC,
6100 0 : aContext, mPresContext, canStoreInRuleTree);
6101 0 : SetCoord(*aRuleData->ValueForMinHeight(), pos->mMinHeight, parentPos->mMinHeight,
6102 : SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC,
6103 0 : aContext, mPresContext, canStoreInRuleTree);
6104 0 : SetCoord(*aRuleData->ValueForMaxHeight(), pos->mMaxHeight, parentPos->mMaxHeight,
6105 : SETCOORD_LPOH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC,
6106 0 : aContext, mPresContext, canStoreInRuleTree);
6107 :
6108 : // box-sizing: enum, inherit, initial
6109 0 : SetDiscrete(*aRuleData->ValueForBoxSizing(),
6110 : pos->mBoxSizing, canStoreInRuleTree,
6111 : SETDSC_ENUMERATED, parentPos->mBoxSizing,
6112 0 : NS_STYLE_BOX_SIZING_CONTENT, 0, 0, 0, 0);
6113 :
6114 : // z-index
6115 0 : const nsCSSValue* zIndexValue = aRuleData->ValueForZIndex();
6116 0 : if (! SetCoord(*zIndexValue, pos->mZIndex, parentPos->mZIndex,
6117 : SETCOORD_IA | SETCOORD_INITIAL_AUTO, aContext,
6118 0 : nsnull, canStoreInRuleTree)) {
6119 0 : if (eCSSUnit_Inherit == zIndexValue->GetUnit()) {
6120 : // handle inherit, because it's ok to inherit 'auto' here
6121 0 : canStoreInRuleTree = false;
6122 0 : pos->mZIndex = parentPos->mZIndex;
6123 : }
6124 : }
6125 :
6126 0 : COMPUTE_END_RESET(Position, pos)
6127 : }
6128 :
6129 : const void*
6130 0 : nsRuleNode::ComputeTableData(void* aStartStruct,
6131 : const nsRuleData* aRuleData,
6132 : nsStyleContext* aContext,
6133 : nsRuleNode* aHighestNode,
6134 : const RuleDetail aRuleDetail,
6135 : const bool aCanStoreInRuleTree)
6136 : {
6137 0 : COMPUTE_START_RESET(Table, (), table, parentTable)
6138 :
6139 : // table-layout: enum, inherit, initial
6140 0 : SetDiscrete(*aRuleData->ValueForTableLayout(),
6141 : table->mLayoutStrategy, canStoreInRuleTree,
6142 : SETDSC_ENUMERATED, parentTable->mLayoutStrategy,
6143 0 : NS_STYLE_TABLE_LAYOUT_AUTO, 0, 0, 0, 0);
6144 :
6145 : // cols: enum, int (not a real CSS prop)
6146 0 : const nsCSSValue* colsValue = aRuleData->ValueForCols();
6147 0 : if (eCSSUnit_Enumerated == colsValue->GetUnit() ||
6148 0 : eCSSUnit_Integer == colsValue->GetUnit())
6149 0 : table->mCols = colsValue->GetIntValue();
6150 :
6151 : // span: pixels (not a real CSS prop)
6152 0 : const nsCSSValue* spanValue = aRuleData->ValueForSpan();
6153 0 : if (eCSSUnit_Enumerated == spanValue->GetUnit() ||
6154 0 : eCSSUnit_Integer == spanValue->GetUnit())
6155 0 : table->mSpan = spanValue->GetIntValue();
6156 :
6157 0 : COMPUTE_END_RESET(Table, table)
6158 : }
6159 :
6160 : const void*
6161 0 : nsRuleNode::ComputeTableBorderData(void* aStartStruct,
6162 : const nsRuleData* aRuleData,
6163 : nsStyleContext* aContext,
6164 : nsRuleNode* aHighestNode,
6165 : const RuleDetail aRuleDetail,
6166 : const bool aCanStoreInRuleTree)
6167 : {
6168 0 : COMPUTE_START_INHERITED(TableBorder, (mPresContext), table, parentTable)
6169 :
6170 : // border-collapse: enum, inherit, initial
6171 0 : SetDiscrete(*aRuleData->ValueForBorderCollapse(), table->mBorderCollapse,
6172 : canStoreInRuleTree,
6173 : SETDSC_ENUMERATED, parentTable->mBorderCollapse,
6174 0 : NS_STYLE_BORDER_SEPARATE, 0, 0, 0, 0);
6175 :
6176 0 : const nsCSSValue* borderSpacingValue = aRuleData->ValueForBorderSpacing();
6177 0 : if (borderSpacingValue->GetUnit() != eCSSUnit_Null) {
6178 : // border-spacing-x/y: length, inherit
6179 : nsStyleCoord parentX(parentTable->mBorderSpacingX,
6180 0 : nsStyleCoord::CoordConstructor);
6181 : nsStyleCoord parentY(parentTable->mBorderSpacingY,
6182 0 : nsStyleCoord::CoordConstructor);
6183 0 : nsStyleCoord coordX, coordY;
6184 :
6185 : #ifdef DEBUG
6186 : bool result =
6187 : #endif
6188 : SetPairCoords(*borderSpacingValue,
6189 : coordX, coordY, parentX, parentY,
6190 : SETCOORD_LH | SETCOORD_INITIAL_ZERO |
6191 : SETCOORD_CALC_LENGTH_ONLY |
6192 : SETCOORD_CALC_CLAMP_NONNEGATIVE,
6193 0 : aContext, mPresContext, canStoreInRuleTree);
6194 0 : NS_ASSERTION(result, "malformed table border value");
6195 0 : table->mBorderSpacingX = coordX.GetCoordValue();
6196 0 : table->mBorderSpacingY = coordY.GetCoordValue();
6197 : }
6198 :
6199 : // caption-side: enum, inherit, initial
6200 0 : SetDiscrete(*aRuleData->ValueForCaptionSide(),
6201 : table->mCaptionSide, canStoreInRuleTree,
6202 : SETDSC_ENUMERATED, parentTable->mCaptionSide,
6203 0 : NS_STYLE_CAPTION_SIDE_TOP, 0, 0, 0, 0);
6204 :
6205 : // empty-cells: enum, inherit, initial
6206 0 : SetDiscrete(*aRuleData->ValueForEmptyCells(),
6207 : table->mEmptyCells, canStoreInRuleTree,
6208 : SETDSC_ENUMERATED, parentTable->mEmptyCells,
6209 0 : (mPresContext->CompatibilityMode() == eCompatibility_NavQuirks)
6210 : ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
6211 : : NS_STYLE_TABLE_EMPTY_CELLS_SHOW,
6212 0 : 0, 0, 0, 0);
6213 :
6214 0 : COMPUTE_END_INHERITED(TableBorder, table)
6215 : }
6216 :
6217 : const void*
6218 0 : nsRuleNode::ComputeContentData(void* aStartStruct,
6219 : const nsRuleData* aRuleData,
6220 : nsStyleContext* aContext,
6221 : nsRuleNode* aHighestNode,
6222 : const RuleDetail aRuleDetail,
6223 : const bool aCanStoreInRuleTree)
6224 : {
6225 : PRUint32 count;
6226 0 : nsAutoString buffer;
6227 :
6228 0 : COMPUTE_START_RESET(Content, (), content, parentContent)
6229 :
6230 : // content: [string, url, counter, attr, enum]+, normal, none, inherit
6231 0 : const nsCSSValue* contentValue = aRuleData->ValueForContent();
6232 0 : switch (contentValue->GetUnit()) {
6233 : case eCSSUnit_Null:
6234 0 : break;
6235 :
6236 : case eCSSUnit_Normal:
6237 : case eCSSUnit_None:
6238 : case eCSSUnit_Initial:
6239 : // "normal", "none", and "initial" all mean no content
6240 0 : content->AllocateContents(0);
6241 0 : break;
6242 :
6243 : case eCSSUnit_Inherit:
6244 0 : canStoreInRuleTree = false;
6245 0 : count = parentContent->ContentCount();
6246 0 : if (NS_SUCCEEDED(content->AllocateContents(count))) {
6247 0 : while (0 < count--) {
6248 0 : content->ContentAt(count) = parentContent->ContentAt(count);
6249 : }
6250 : }
6251 0 : break;
6252 :
6253 : case eCSSUnit_Enumerated: {
6254 0 : NS_ABORT_IF_FALSE(contentValue->GetIntValue() ==
6255 : NS_STYLE_CONTENT_ALT_CONTENT,
6256 : "unrecognized solitary content keyword");
6257 0 : content->AllocateContents(1);
6258 0 : nsStyleContentData& data = content->ContentAt(0);
6259 0 : data.mType = eStyleContentType_AltContent;
6260 0 : data.mContent.mString = nsnull;
6261 0 : break;
6262 : }
6263 :
6264 : case eCSSUnit_List:
6265 : case eCSSUnit_ListDep: {
6266 0 : const nsCSSValueList* contentValueList = contentValue->GetListValue();
6267 0 : count = 0;
6268 0 : while (contentValueList) {
6269 0 : count++;
6270 0 : contentValueList = contentValueList->mNext;
6271 : }
6272 0 : if (NS_SUCCEEDED(content->AllocateContents(count))) {
6273 0 : const nsAutoString nullStr;
6274 0 : count = 0;
6275 0 : contentValueList = contentValue->GetListValue();
6276 0 : while (contentValueList) {
6277 0 : const nsCSSValue& value = contentValueList->mValue;
6278 0 : nsCSSUnit unit = value.GetUnit();
6279 : nsStyleContentType type;
6280 0 : nsStyleContentData &data = content->ContentAt(count++);
6281 0 : switch (unit) {
6282 0 : case eCSSUnit_String: type = eStyleContentType_String; break;
6283 0 : case eCSSUnit_Image: type = eStyleContentType_Image; break;
6284 0 : case eCSSUnit_Attr: type = eStyleContentType_Attr; break;
6285 0 : case eCSSUnit_Counter: type = eStyleContentType_Counter; break;
6286 0 : case eCSSUnit_Counters: type = eStyleContentType_Counters; break;
6287 : case eCSSUnit_Enumerated:
6288 0 : switch (value.GetIntValue()) {
6289 : case NS_STYLE_CONTENT_OPEN_QUOTE:
6290 0 : type = eStyleContentType_OpenQuote; break;
6291 : case NS_STYLE_CONTENT_CLOSE_QUOTE:
6292 0 : type = eStyleContentType_CloseQuote; break;
6293 : case NS_STYLE_CONTENT_NO_OPEN_QUOTE:
6294 0 : type = eStyleContentType_NoOpenQuote; break;
6295 : case NS_STYLE_CONTENT_NO_CLOSE_QUOTE:
6296 0 : type = eStyleContentType_NoCloseQuote; break;
6297 : default:
6298 0 : NS_ERROR("bad content value");
6299 : }
6300 0 : break;
6301 : default:
6302 0 : NS_ERROR("bad content type");
6303 : }
6304 0 : data.mType = type;
6305 0 : if (type == eStyleContentType_Image) {
6306 0 : NS_SET_IMAGE_REQUEST(data.SetImage, aContext, value.GetImageValue());
6307 : }
6308 0 : else if (type <= eStyleContentType_Attr) {
6309 0 : value.GetStringValue(buffer);
6310 0 : data.mContent.mString = NS_strdup(buffer.get());
6311 : }
6312 0 : else if (type <= eStyleContentType_Counters) {
6313 0 : data.mContent.mCounters = value.GetArrayValue();
6314 0 : data.mContent.mCounters->AddRef();
6315 : }
6316 : else {
6317 0 : data.mContent.mString = nsnull;
6318 : }
6319 0 : contentValueList = contentValueList->mNext;
6320 : }
6321 : }
6322 0 : break;
6323 : }
6324 :
6325 : default:
6326 0 : NS_ABORT_IF_FALSE(false,
6327 : nsPrintfCString(64, "unrecognized content unit %d",
6328 : contentValue->GetUnit()).get());
6329 : }
6330 :
6331 : // counter-increment: [string [int]]+, none, inherit
6332 : const nsCSSValue* counterIncrementValue =
6333 0 : aRuleData->ValueForCounterIncrement();
6334 0 : switch (counterIncrementValue->GetUnit()) {
6335 : case eCSSUnit_Null:
6336 0 : break;
6337 :
6338 : case eCSSUnit_None:
6339 : case eCSSUnit_Initial:
6340 0 : content->AllocateCounterIncrements(0);
6341 0 : break;
6342 :
6343 : case eCSSUnit_Inherit:
6344 0 : canStoreInRuleTree = false;
6345 0 : count = parentContent->CounterIncrementCount();
6346 0 : if (NS_SUCCEEDED(content->AllocateCounterIncrements(count))) {
6347 0 : while (0 < count--) {
6348 : const nsStyleCounterData *data =
6349 0 : parentContent->GetCounterIncrementAt(count);
6350 0 : content->SetCounterIncrementAt(count, data->mCounter, data->mValue);
6351 : }
6352 : }
6353 0 : break;
6354 :
6355 : case eCSSUnit_PairList:
6356 : case eCSSUnit_PairListDep: {
6357 : const nsCSSValuePairList* ourIncrement =
6358 0 : counterIncrementValue->GetPairListValue();
6359 0 : NS_ABORT_IF_FALSE(ourIncrement->mXValue.GetUnit() == eCSSUnit_Ident,
6360 : "unexpected value unit");
6361 0 : count = ListLength(ourIncrement);
6362 0 : if (NS_FAILED(content->AllocateCounterIncrements(count))) {
6363 0 : break;
6364 : }
6365 :
6366 0 : count = 0;
6367 0 : for (const nsCSSValuePairList* p = ourIncrement; p; p = p->mNext, count++) {
6368 : PRInt32 increment;
6369 0 : if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
6370 0 : increment = p->mYValue.GetIntValue();
6371 : } else {
6372 0 : increment = 1;
6373 : }
6374 0 : p->mXValue.GetStringValue(buffer);
6375 0 : content->SetCounterIncrementAt(count, buffer, increment);
6376 : }
6377 0 : break;
6378 : }
6379 :
6380 : default:
6381 0 : NS_ABORT_IF_FALSE(false, "unexpected value unit");
6382 : }
6383 :
6384 : // counter-reset: [string [int]]+, none, inherit
6385 0 : const nsCSSValue* counterResetValue = aRuleData->ValueForCounterReset();
6386 0 : switch (counterResetValue->GetUnit()) {
6387 : case eCSSUnit_Null:
6388 0 : break;
6389 :
6390 : case eCSSUnit_None:
6391 : case eCSSUnit_Initial:
6392 0 : content->AllocateCounterResets(0);
6393 0 : break;
6394 :
6395 : case eCSSUnit_Inherit:
6396 0 : canStoreInRuleTree = false;
6397 0 : count = parentContent->CounterResetCount();
6398 0 : if (NS_SUCCEEDED(content->AllocateCounterResets(count))) {
6399 0 : while (0 < count--) {
6400 : const nsStyleCounterData *data =
6401 0 : parentContent->GetCounterResetAt(count);
6402 0 : content->SetCounterResetAt(count, data->mCounter, data->mValue);
6403 : }
6404 : }
6405 0 : break;
6406 :
6407 : case eCSSUnit_PairList:
6408 : case eCSSUnit_PairListDep: {
6409 : const nsCSSValuePairList* ourReset =
6410 0 : counterResetValue->GetPairListValue();
6411 0 : NS_ABORT_IF_FALSE(ourReset->mXValue.GetUnit() == eCSSUnit_Ident,
6412 : "unexpected value unit");
6413 0 : count = ListLength(ourReset);
6414 0 : if (NS_FAILED(content->AllocateCounterResets(count))) {
6415 0 : break;
6416 : }
6417 :
6418 0 : count = 0;
6419 0 : for (const nsCSSValuePairList* p = ourReset; p; p = p->mNext, count++) {
6420 : PRInt32 reset;
6421 0 : if (p->mYValue.GetUnit() == eCSSUnit_Integer) {
6422 0 : reset = p->mYValue.GetIntValue();
6423 : } else {
6424 0 : reset = 0;
6425 : }
6426 0 : p->mXValue.GetStringValue(buffer);
6427 0 : content->SetCounterResetAt(count, buffer, reset);
6428 : }
6429 0 : break;
6430 : }
6431 :
6432 : default:
6433 0 : NS_ABORT_IF_FALSE(false, "unexpected value unit");
6434 : }
6435 :
6436 : // marker-offset: length, auto, inherit
6437 0 : SetCoord(*aRuleData->ValueForMarkerOffset(), content->mMarkerOffset, parentContent->mMarkerOffset,
6438 : SETCOORD_LH | SETCOORD_AUTO | SETCOORD_INITIAL_AUTO |
6439 : SETCOORD_CALC_LENGTH_ONLY,
6440 0 : aContext, mPresContext, canStoreInRuleTree);
6441 :
6442 : // If we ended up with an image, track it.
6443 0 : for (PRUint32 i = 0; i < content->ContentCount(); ++i) {
6444 0 : if ((content->ContentAt(i).mType == eStyleContentType_Image) &&
6445 0 : content->ContentAt(i).mContent.mImage) {
6446 0 : content->ContentAt(i).TrackImage(aContext->PresContext());
6447 : }
6448 : }
6449 :
6450 0 : COMPUTE_END_RESET(Content, content)
6451 : }
6452 :
6453 : const void*
6454 0 : nsRuleNode::ComputeQuotesData(void* aStartStruct,
6455 : const nsRuleData* aRuleData,
6456 : nsStyleContext* aContext,
6457 : nsRuleNode* aHighestNode,
6458 : const RuleDetail aRuleDetail,
6459 : const bool aCanStoreInRuleTree)
6460 : {
6461 0 : COMPUTE_START_INHERITED(Quotes, (), quotes, parentQuotes)
6462 :
6463 : // quotes: inherit, initial, none, [string string]+
6464 0 : const nsCSSValue* quotesValue = aRuleData->ValueForQuotes();
6465 0 : switch (quotesValue->GetUnit()) {
6466 : case eCSSUnit_Null:
6467 0 : break;
6468 : case eCSSUnit_Inherit:
6469 0 : canStoreInRuleTree = false;
6470 0 : quotes->CopyFrom(*parentQuotes);
6471 0 : break;
6472 : case eCSSUnit_Initial:
6473 0 : quotes->SetInitial();
6474 0 : break;
6475 : case eCSSUnit_None:
6476 0 : quotes->AllocateQuotes(0);
6477 0 : break;
6478 : case eCSSUnit_PairList:
6479 : case eCSSUnit_PairListDep: {
6480 : const nsCSSValuePairList* ourQuotes
6481 0 : = quotesValue->GetPairListValue();
6482 0 : nsAutoString buffer;
6483 0 : nsAutoString closeBuffer;
6484 0 : PRUint32 count = ListLength(ourQuotes);
6485 0 : if (NS_FAILED(quotes->AllocateQuotes(count))) {
6486 : break;
6487 : }
6488 0 : count = 0;
6489 0 : while (ourQuotes) {
6490 0 : NS_ABORT_IF_FALSE(ourQuotes->mXValue.GetUnit() == eCSSUnit_String &&
6491 : ourQuotes->mYValue.GetUnit() == eCSSUnit_String,
6492 : "improper list contents for quotes");
6493 0 : ourQuotes->mXValue.GetStringValue(buffer);
6494 0 : ourQuotes->mYValue.GetStringValue(closeBuffer);
6495 0 : quotes->SetQuotesAt(count++, buffer, closeBuffer);
6496 0 : ourQuotes = ourQuotes->mNext;
6497 : }
6498 : break;
6499 : }
6500 : default:
6501 0 : NS_ABORT_IF_FALSE(false, "unexpected value unit");
6502 : }
6503 :
6504 0 : COMPUTE_END_INHERITED(Quotes, quotes)
6505 : }
6506 :
6507 : const void*
6508 0 : nsRuleNode::ComputeXULData(void* aStartStruct,
6509 : const nsRuleData* aRuleData,
6510 : nsStyleContext* aContext,
6511 : nsRuleNode* aHighestNode,
6512 : const RuleDetail aRuleDetail,
6513 : const bool aCanStoreInRuleTree)
6514 : {
6515 0 : COMPUTE_START_RESET(XUL, (), xul, parentXUL)
6516 :
6517 : // box-align: enum, inherit, initial
6518 0 : SetDiscrete(*aRuleData->ValueForBoxAlign(),
6519 : xul->mBoxAlign, canStoreInRuleTree,
6520 : SETDSC_ENUMERATED, parentXUL->mBoxAlign,
6521 0 : NS_STYLE_BOX_ALIGN_STRETCH, 0, 0, 0, 0);
6522 :
6523 : // box-direction: enum, inherit, initial
6524 0 : SetDiscrete(*aRuleData->ValueForBoxDirection(),
6525 : xul->mBoxDirection, canStoreInRuleTree,
6526 : SETDSC_ENUMERATED, parentXUL->mBoxDirection,
6527 0 : NS_STYLE_BOX_DIRECTION_NORMAL, 0, 0, 0, 0);
6528 :
6529 : // box-flex: factor, inherit
6530 0 : SetFactor(*aRuleData->ValueForBoxFlex(),
6531 : xul->mBoxFlex, canStoreInRuleTree,
6532 0 : parentXUL->mBoxFlex, 0.0f);
6533 :
6534 : // box-orient: enum, inherit, initial
6535 0 : SetDiscrete(*aRuleData->ValueForBoxOrient(),
6536 : xul->mBoxOrient, canStoreInRuleTree,
6537 : SETDSC_ENUMERATED, parentXUL->mBoxOrient,
6538 0 : NS_STYLE_BOX_ORIENT_HORIZONTAL, 0, 0, 0, 0);
6539 :
6540 : // box-pack: enum, inherit, initial
6541 0 : SetDiscrete(*aRuleData->ValueForBoxPack(),
6542 : xul->mBoxPack, canStoreInRuleTree,
6543 : SETDSC_ENUMERATED, parentXUL->mBoxPack,
6544 0 : NS_STYLE_BOX_PACK_START, 0, 0, 0, 0);
6545 :
6546 : // box-ordinal-group: integer, inherit, initial
6547 0 : SetDiscrete(*aRuleData->ValueForBoxOrdinalGroup(),
6548 : xul->mBoxOrdinal, canStoreInRuleTree,
6549 : SETDSC_INTEGER, parentXUL->mBoxOrdinal, 1,
6550 0 : 0, 0, 0, 0);
6551 :
6552 0 : const nsCSSValue* stackSizingValue = aRuleData->ValueForStackSizing();
6553 0 : if (eCSSUnit_Inherit == stackSizingValue->GetUnit()) {
6554 0 : canStoreInRuleTree = false;
6555 0 : xul->mStretchStack = parentXUL->mStretchStack;
6556 0 : } else if (eCSSUnit_Initial == stackSizingValue->GetUnit()) {
6557 0 : xul->mStretchStack = true;
6558 0 : } else if (eCSSUnit_Enumerated == stackSizingValue->GetUnit()) {
6559 0 : xul->mStretchStack = stackSizingValue->GetIntValue() ==
6560 0 : NS_STYLE_STACK_SIZING_STRETCH_TO_FIT;
6561 : }
6562 :
6563 0 : COMPUTE_END_RESET(XUL, xul)
6564 : }
6565 :
6566 : const void*
6567 0 : nsRuleNode::ComputeColumnData(void* aStartStruct,
6568 : const nsRuleData* aRuleData,
6569 : nsStyleContext* aContext,
6570 : nsRuleNode* aHighestNode,
6571 : const RuleDetail aRuleDetail,
6572 : const bool aCanStoreInRuleTree)
6573 : {
6574 0 : COMPUTE_START_RESET(Column, (mPresContext), column, parent)
6575 :
6576 : // column-width: length, auto, inherit
6577 0 : SetCoord(*aRuleData->ValueForColumnWidth(),
6578 : column->mColumnWidth, parent->mColumnWidth,
6579 : SETCOORD_LAH | SETCOORD_INITIAL_AUTO |
6580 : SETCOORD_CALC_LENGTH_ONLY | SETCOORD_CALC_CLAMP_NONNEGATIVE,
6581 0 : aContext, mPresContext, canStoreInRuleTree);
6582 :
6583 : // column-gap: length, inherit, normal
6584 0 : SetCoord(*aRuleData->ValueForColumnGap(),
6585 : column->mColumnGap, parent->mColumnGap,
6586 : SETCOORD_LH | SETCOORD_NORMAL | SETCOORD_INITIAL_NORMAL |
6587 : SETCOORD_CALC_LENGTH_ONLY,
6588 0 : aContext, mPresContext, canStoreInRuleTree);
6589 : // clamp negative calc() to 0
6590 0 : if (column->mColumnGap.GetUnit() == eStyleUnit_Coord) {
6591 : column->mColumnGap.SetCoordValue(
6592 0 : NS_MAX(column->mColumnGap.GetCoordValue(), 0));
6593 : }
6594 :
6595 : // column-count: auto, integer, inherit
6596 0 : const nsCSSValue* columnCountValue = aRuleData->ValueForColumnCount();
6597 0 : if (eCSSUnit_Auto == columnCountValue->GetUnit() ||
6598 0 : eCSSUnit_Initial == columnCountValue->GetUnit()) {
6599 0 : column->mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
6600 0 : } else if (eCSSUnit_Integer == columnCountValue->GetUnit()) {
6601 0 : column->mColumnCount = columnCountValue->GetIntValue();
6602 : // Max 1000 columns - wallpaper for bug 345583.
6603 0 : column->mColumnCount = NS_MIN(column->mColumnCount, 1000U);
6604 0 : } else if (eCSSUnit_Inherit == columnCountValue->GetUnit()) {
6605 0 : canStoreInRuleTree = false;
6606 0 : column->mColumnCount = parent->mColumnCount;
6607 : }
6608 :
6609 : // column-rule-width: length, enum, inherit
6610 0 : const nsCSSValue& widthValue = *aRuleData->ValueForColumnRuleWidth();
6611 0 : if (eCSSUnit_Initial == widthValue.GetUnit()) {
6612 : column->SetColumnRuleWidth(
6613 0 : (mPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]);
6614 : }
6615 0 : else if (eCSSUnit_Enumerated == widthValue.GetUnit()) {
6616 0 : NS_ASSERTION(widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
6617 : widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
6618 : widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
6619 : "Unexpected enum value");
6620 : column->SetColumnRuleWidth(
6621 0 : (mPresContext->GetBorderWidthTable())[widthValue.GetIntValue()]);
6622 : }
6623 0 : else if (eCSSUnit_Inherit == widthValue.GetUnit()) {
6624 0 : column->SetColumnRuleWidth(parent->GetComputedColumnRuleWidth());
6625 0 : canStoreInRuleTree = false;
6626 : }
6627 0 : else if (widthValue.IsLengthUnit() || widthValue.IsCalcUnit()) {
6628 : nscoord len =
6629 0 : CalcLength(widthValue, aContext, mPresContext, canStoreInRuleTree);
6630 0 : if (len < 0) {
6631 : // FIXME: This is untested (by test_value_storage.html) for
6632 : // column-rule-width since it gets covered up by the border
6633 : // rounding code.
6634 0 : NS_ASSERTION(widthValue.IsCalcUnit(),
6635 : "parser should have rejected negative length");
6636 0 : len = 0;
6637 : }
6638 0 : column->SetColumnRuleWidth(len);
6639 : }
6640 :
6641 : // column-rule-style: enum, inherit
6642 0 : const nsCSSValue& styleValue = *aRuleData->ValueForColumnRuleStyle();
6643 0 : NS_ABORT_IF_FALSE(eCSSUnit_None != styleValue.GetUnit(),
6644 : "'none' should be handled as enumerated value");
6645 0 : if (eCSSUnit_Enumerated == styleValue.GetUnit()) {
6646 0 : column->mColumnRuleStyle = styleValue.GetIntValue();
6647 : }
6648 0 : else if (eCSSUnit_Initial == styleValue.GetUnit()) {
6649 0 : column->mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
6650 : }
6651 0 : else if (eCSSUnit_Inherit == styleValue.GetUnit()) {
6652 0 : canStoreInRuleTree = false;
6653 0 : column->mColumnRuleStyle = parent->mColumnRuleStyle;
6654 : }
6655 :
6656 : // column-rule-color: color, inherit
6657 0 : const nsCSSValue& colorValue = *aRuleData->ValueForColumnRuleColor();
6658 0 : if (eCSSUnit_Inherit == colorValue.GetUnit()) {
6659 0 : canStoreInRuleTree = false;
6660 0 : column->mColumnRuleColorIsForeground = false;
6661 0 : if (parent->mColumnRuleColorIsForeground) {
6662 0 : column->mColumnRuleColor = parentContext->GetStyleColor()->mColor;
6663 : } else {
6664 0 : column->mColumnRuleColor = parent->mColumnRuleColor;
6665 : }
6666 : }
6667 0 : else if (eCSSUnit_Initial == colorValue.GetUnit() ||
6668 0 : eCSSUnit_Enumerated == colorValue.GetUnit()) {
6669 0 : column->mColumnRuleColorIsForeground = true;
6670 : }
6671 0 : else if (SetColor(colorValue, 0, mPresContext, aContext,
6672 0 : column->mColumnRuleColor, canStoreInRuleTree)) {
6673 0 : column->mColumnRuleColorIsForeground = false;
6674 : }
6675 :
6676 : // column-fill: enum
6677 0 : SetDiscrete(*aRuleData->ValueForColumnFill(),
6678 : column->mColumnFill, canStoreInRuleTree,
6679 : SETDSC_ENUMERATED, parent->mColumnFill,
6680 : NS_STYLE_COLUMN_FILL_BALANCE,
6681 0 : 0, 0, 0, 0);
6682 :
6683 0 : COMPUTE_END_RESET(Column, column)
6684 : }
6685 :
6686 : static void
6687 0 : SetSVGPaint(const nsCSSValue& aValue, const nsStyleSVGPaint& parentPaint,
6688 : nsPresContext* aPresContext, nsStyleContext *aContext,
6689 : nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
6690 : bool& aCanStoreInRuleTree)
6691 : {
6692 : nscolor color;
6693 :
6694 0 : if (aValue.GetUnit() == eCSSUnit_Inherit) {
6695 0 : aResult = parentPaint;
6696 0 : aCanStoreInRuleTree = false;
6697 0 : } else if (aValue.GetUnit() == eCSSUnit_None) {
6698 0 : aResult.SetType(eStyleSVGPaintType_None);
6699 0 : } else if (aValue.GetUnit() == eCSSUnit_Initial) {
6700 0 : aResult.SetType(aInitialPaintType);
6701 0 : aResult.mPaint.mColor = NS_RGB(0, 0, 0);
6702 0 : aResult.mFallbackColor = NS_RGB(0, 0, 0);
6703 0 : } else if (SetColor(aValue, NS_RGB(0, 0, 0), aPresContext, aContext,
6704 : color, aCanStoreInRuleTree)) {
6705 0 : aResult.SetType(eStyleSVGPaintType_Color);
6706 0 : aResult.mPaint.mColor = color;
6707 0 : } else if (aValue.GetUnit() == eCSSUnit_Pair) {
6708 0 : const nsCSSValuePair& pair = aValue.GetPairValue();
6709 0 : NS_ABORT_IF_FALSE(pair.mXValue.GetUnit() == eCSSUnit_URL,
6710 : "malformed paint server value");
6711 :
6712 0 : aResult.SetType(eStyleSVGPaintType_Server);
6713 0 : aResult.mPaint.mPaintServer = pair.mXValue.GetURLValue();
6714 0 : NS_IF_ADDREF(aResult.mPaint.mPaintServer);
6715 :
6716 0 : if (pair.mYValue.GetUnit() == eCSSUnit_None) {
6717 0 : aResult.mFallbackColor = NS_RGBA(0, 0, 0, 0);
6718 : } else {
6719 0 : NS_ABORT_IF_FALSE(pair.mYValue.GetUnit() != eCSSUnit_Inherit,
6720 : "cannot inherit fallback colour");
6721 : SetColor(pair.mYValue, NS_RGB(0, 0, 0), aPresContext, aContext,
6722 0 : aResult.mFallbackColor, aCanStoreInRuleTree);
6723 : }
6724 : } else {
6725 0 : NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Null,
6726 : "malformed paint server value");
6727 : }
6728 0 : }
6729 :
6730 : const void*
6731 0 : nsRuleNode::ComputeSVGData(void* aStartStruct,
6732 : const nsRuleData* aRuleData,
6733 : nsStyleContext* aContext,
6734 : nsRuleNode* aHighestNode,
6735 : const RuleDetail aRuleDetail,
6736 : const bool aCanStoreInRuleTree)
6737 : {
6738 0 : COMPUTE_START_INHERITED(SVG, (), svg, parentSVG)
6739 :
6740 : // clip-rule: enum, inherit, initial
6741 0 : SetDiscrete(*aRuleData->ValueForClipRule(),
6742 : svg->mClipRule, canStoreInRuleTree,
6743 : SETDSC_ENUMERATED, parentSVG->mClipRule,
6744 0 : NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
6745 :
6746 : // color-interpolation: enum, inherit, initial
6747 0 : SetDiscrete(*aRuleData->ValueForColorInterpolation(),
6748 : svg->mColorInterpolation, canStoreInRuleTree,
6749 : SETDSC_ENUMERATED, parentSVG->mColorInterpolation,
6750 0 : NS_STYLE_COLOR_INTERPOLATION_SRGB, 0, 0, 0, 0);
6751 :
6752 : // color-interpolation-filters: enum, inherit, initial
6753 0 : SetDiscrete(*aRuleData->ValueForColorInterpolationFilters(),
6754 : svg->mColorInterpolationFilters, canStoreInRuleTree,
6755 : SETDSC_ENUMERATED, parentSVG->mColorInterpolationFilters,
6756 0 : NS_STYLE_COLOR_INTERPOLATION_LINEARRGB, 0, 0, 0, 0);
6757 :
6758 : // fill:
6759 0 : SetSVGPaint(*aRuleData->ValueForFill(),
6760 : parentSVG->mFill, mPresContext, aContext,
6761 0 : svg->mFill, eStyleSVGPaintType_Color, canStoreInRuleTree);
6762 :
6763 : // fill-opacity: factor, inherit, initial
6764 0 : SetFactor(*aRuleData->ValueForFillOpacity(),
6765 : svg->mFillOpacity, canStoreInRuleTree,
6766 0 : parentSVG->mFillOpacity, 1.0f, SETFCT_OPACITY);
6767 :
6768 : // fill-rule: enum, inherit, initial
6769 0 : SetDiscrete(*aRuleData->ValueForFillRule(),
6770 : svg->mFillRule, canStoreInRuleTree,
6771 : SETDSC_ENUMERATED, parentSVG->mFillRule,
6772 0 : NS_STYLE_FILL_RULE_NONZERO, 0, 0, 0, 0);
6773 :
6774 : // image-rendering: enum, inherit
6775 0 : SetDiscrete(*aRuleData->ValueForImageRendering(),
6776 : svg->mImageRendering, canStoreInRuleTree,
6777 : SETDSC_ENUMERATED, parentSVG->mImageRendering,
6778 0 : NS_STYLE_IMAGE_RENDERING_AUTO, 0, 0, 0, 0);
6779 :
6780 : // marker-end: url, none, inherit
6781 0 : const nsCSSValue* markerEndValue = aRuleData->ValueForMarkerEnd();
6782 0 : if (eCSSUnit_URL == markerEndValue->GetUnit()) {
6783 0 : svg->mMarkerEnd = markerEndValue->GetURLValue();
6784 0 : } else if (eCSSUnit_None == markerEndValue->GetUnit() ||
6785 0 : eCSSUnit_Initial == markerEndValue->GetUnit()) {
6786 0 : svg->mMarkerEnd = nsnull;
6787 0 : } else if (eCSSUnit_Inherit == markerEndValue->GetUnit()) {
6788 0 : canStoreInRuleTree = false;
6789 0 : svg->mMarkerEnd = parentSVG->mMarkerEnd;
6790 : }
6791 :
6792 : // marker-mid: url, none, inherit
6793 0 : const nsCSSValue* markerMidValue = aRuleData->ValueForMarkerMid();
6794 0 : if (eCSSUnit_URL == markerMidValue->GetUnit()) {
6795 0 : svg->mMarkerMid = markerMidValue->GetURLValue();
6796 0 : } else if (eCSSUnit_None == markerMidValue->GetUnit() ||
6797 0 : eCSSUnit_Initial == markerMidValue->GetUnit()) {
6798 0 : svg->mMarkerMid = nsnull;
6799 0 : } else if (eCSSUnit_Inherit == markerMidValue->GetUnit()) {
6800 0 : canStoreInRuleTree = false;
6801 0 : svg->mMarkerMid = parentSVG->mMarkerMid;
6802 : }
6803 :
6804 : // marker-start: url, none, inherit
6805 0 : const nsCSSValue* markerStartValue = aRuleData->ValueForMarkerStart();
6806 0 : if (eCSSUnit_URL == markerStartValue->GetUnit()) {
6807 0 : svg->mMarkerStart = markerStartValue->GetURLValue();
6808 0 : } else if (eCSSUnit_None == markerStartValue->GetUnit() ||
6809 0 : eCSSUnit_Initial == markerStartValue->GetUnit()) {
6810 0 : svg->mMarkerStart = nsnull;
6811 0 : } else if (eCSSUnit_Inherit == markerStartValue->GetUnit()) {
6812 0 : canStoreInRuleTree = false;
6813 0 : svg->mMarkerStart = parentSVG->mMarkerStart;
6814 : }
6815 :
6816 : // shape-rendering: enum, inherit
6817 0 : SetDiscrete(*aRuleData->ValueForShapeRendering(),
6818 : svg->mShapeRendering, canStoreInRuleTree,
6819 : SETDSC_ENUMERATED, parentSVG->mShapeRendering,
6820 0 : NS_STYLE_SHAPE_RENDERING_AUTO, 0, 0, 0, 0);
6821 :
6822 : // stroke:
6823 0 : SetSVGPaint(*aRuleData->ValueForStroke(),
6824 : parentSVG->mStroke, mPresContext, aContext,
6825 0 : svg->mStroke, eStyleSVGPaintType_None, canStoreInRuleTree);
6826 :
6827 : // stroke-dasharray: <dasharray>, none, inherit
6828 0 : const nsCSSValue* strokeDasharrayValue = aRuleData->ValueForStrokeDasharray();
6829 0 : switch (strokeDasharrayValue->GetUnit()) {
6830 : case eCSSUnit_Null:
6831 0 : break;
6832 :
6833 : case eCSSUnit_Inherit:
6834 0 : canStoreInRuleTree = false;
6835 : // only do the copy if weren't already set up by the copy constructor
6836 : // FIXME Bug 389408: This is broken when aStartStruct is non-null!
6837 0 : if (!svg->mStrokeDasharray) {
6838 0 : svg->mStrokeDasharrayLength = parentSVG->mStrokeDasharrayLength;
6839 0 : if (svg->mStrokeDasharrayLength) {
6840 0 : svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
6841 0 : if (svg->mStrokeDasharray)
6842 : memcpy(svg->mStrokeDasharray,
6843 : parentSVG->mStrokeDasharray,
6844 0 : svg->mStrokeDasharrayLength * sizeof(nsStyleCoord));
6845 : else
6846 0 : svg->mStrokeDasharrayLength = 0;
6847 : }
6848 : }
6849 0 : break;
6850 :
6851 : case eCSSUnit_Initial:
6852 : case eCSSUnit_None:
6853 0 : delete [] svg->mStrokeDasharray;
6854 0 : svg->mStrokeDasharray = nsnull;
6855 0 : svg->mStrokeDasharrayLength = 0;
6856 0 : break;
6857 :
6858 : case eCSSUnit_List:
6859 : case eCSSUnit_ListDep: {
6860 0 : delete [] svg->mStrokeDasharray;
6861 0 : svg->mStrokeDasharray = nsnull;
6862 0 : svg->mStrokeDasharrayLength = 0;
6863 :
6864 : // count number of values
6865 0 : const nsCSSValueList *value = strokeDasharrayValue->GetListValue();
6866 0 : svg->mStrokeDasharrayLength = ListLength(value);
6867 :
6868 0 : NS_ASSERTION(svg->mStrokeDasharrayLength != 0, "no dasharray items");
6869 :
6870 0 : svg->mStrokeDasharray = new nsStyleCoord[svg->mStrokeDasharrayLength];
6871 :
6872 0 : if (svg->mStrokeDasharray) {
6873 0 : PRUint32 i = 0;
6874 0 : while (nsnull != value) {
6875 : SetCoord(value->mValue,
6876 0 : svg->mStrokeDasharray[i++], nsStyleCoord(),
6877 : SETCOORD_LP | SETCOORD_FACTOR,
6878 0 : aContext, mPresContext, canStoreInRuleTree);
6879 0 : value = value->mNext;
6880 : }
6881 : } else {
6882 0 : svg->mStrokeDasharrayLength = 0;
6883 : }
6884 0 : break;
6885 : }
6886 :
6887 : default:
6888 0 : NS_ABORT_IF_FALSE(false, "unrecognized dasharray unit");
6889 : }
6890 :
6891 : // stroke-dashoffset: <dashoffset>, inherit
6892 0 : SetCoord(*aRuleData->ValueForStrokeDashoffset(),
6893 : svg->mStrokeDashoffset, parentSVG->mStrokeDashoffset,
6894 : SETCOORD_LPH | SETCOORD_FACTOR | SETCOORD_INITIAL_ZERO,
6895 0 : aContext, mPresContext, canStoreInRuleTree);
6896 :
6897 : // stroke-linecap: enum, inherit, initial
6898 0 : SetDiscrete(*aRuleData->ValueForStrokeLinecap(),
6899 : svg->mStrokeLinecap, canStoreInRuleTree,
6900 : SETDSC_ENUMERATED, parentSVG->mStrokeLinecap,
6901 0 : NS_STYLE_STROKE_LINECAP_BUTT, 0, 0, 0, 0);
6902 :
6903 : // stroke-linejoin: enum, inherit, initial
6904 0 : SetDiscrete(*aRuleData->ValueForStrokeLinejoin(),
6905 : svg->mStrokeLinejoin, canStoreInRuleTree,
6906 : SETDSC_ENUMERATED, parentSVG->mStrokeLinejoin,
6907 0 : NS_STYLE_STROKE_LINEJOIN_MITER, 0, 0, 0, 0);
6908 :
6909 : // stroke-miterlimit: <miterlimit>, inherit
6910 0 : SetFactor(*aRuleData->ValueForStrokeMiterlimit(),
6911 : svg->mStrokeMiterlimit,
6912 : canStoreInRuleTree,
6913 0 : parentSVG->mStrokeMiterlimit, 4.0f);
6914 :
6915 : // stroke-opacity:
6916 0 : SetFactor(*aRuleData->ValueForStrokeOpacity(),
6917 : svg->mStrokeOpacity, canStoreInRuleTree,
6918 0 : parentSVG->mStrokeOpacity, 1.0f, SETFCT_OPACITY);
6919 :
6920 : // stroke-width:
6921 0 : const nsCSSValue* strokeWidthValue = aRuleData->ValueForStrokeWidth();
6922 0 : if (eCSSUnit_Initial == strokeWidthValue->GetUnit()) {
6923 0 : svg->mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
6924 : } else {
6925 : SetCoord(*strokeWidthValue,
6926 : svg->mStrokeWidth, parentSVG->mStrokeWidth,
6927 : SETCOORD_LPH | SETCOORD_FACTOR,
6928 0 : aContext, mPresContext, canStoreInRuleTree);
6929 : }
6930 :
6931 : // text-anchor: enum, inherit, initial
6932 0 : SetDiscrete(*aRuleData->ValueForTextAnchor(),
6933 : svg->mTextAnchor, canStoreInRuleTree,
6934 : SETDSC_ENUMERATED, parentSVG->mTextAnchor,
6935 0 : NS_STYLE_TEXT_ANCHOR_START, 0, 0, 0, 0);
6936 :
6937 : // text-rendering: enum, inherit, initial
6938 0 : SetDiscrete(*aRuleData->ValueForTextRendering(),
6939 : svg->mTextRendering, canStoreInRuleTree,
6940 : SETDSC_ENUMERATED, parentSVG->mTextRendering,
6941 0 : NS_STYLE_TEXT_RENDERING_AUTO, 0, 0, 0, 0);
6942 :
6943 0 : COMPUTE_END_INHERITED(SVG, svg)
6944 : }
6945 :
6946 : const void*
6947 0 : nsRuleNode::ComputeSVGResetData(void* aStartStruct,
6948 : const nsRuleData* aRuleData,
6949 : nsStyleContext* aContext,
6950 : nsRuleNode* aHighestNode,
6951 : const RuleDetail aRuleDetail,
6952 : const bool aCanStoreInRuleTree)
6953 : {
6954 0 : COMPUTE_START_RESET(SVGReset, (), svgReset, parentSVGReset)
6955 :
6956 : // stop-color:
6957 0 : const nsCSSValue* stopColorValue = aRuleData->ValueForStopColor();
6958 0 : if (eCSSUnit_Initial == stopColorValue->GetUnit()) {
6959 0 : svgReset->mStopColor = NS_RGB(0, 0, 0);
6960 : } else {
6961 : SetColor(*stopColorValue, parentSVGReset->mStopColor,
6962 0 : mPresContext, aContext, svgReset->mStopColor, canStoreInRuleTree);
6963 : }
6964 :
6965 : // flood-color:
6966 0 : const nsCSSValue* floodColorValue = aRuleData->ValueForFloodColor();
6967 0 : if (eCSSUnit_Initial == floodColorValue->GetUnit()) {
6968 0 : svgReset->mFloodColor = NS_RGB(0, 0, 0);
6969 : } else {
6970 : SetColor(*floodColorValue, parentSVGReset->mFloodColor,
6971 0 : mPresContext, aContext, svgReset->mFloodColor, canStoreInRuleTree);
6972 : }
6973 :
6974 : // lighting-color:
6975 0 : const nsCSSValue* lightingColorValue = aRuleData->ValueForLightingColor();
6976 0 : if (eCSSUnit_Initial == lightingColorValue->GetUnit()) {
6977 0 : svgReset->mLightingColor = NS_RGB(255, 255, 255);
6978 : } else {
6979 : SetColor(*lightingColorValue, parentSVGReset->mLightingColor,
6980 : mPresContext, aContext, svgReset->mLightingColor,
6981 0 : canStoreInRuleTree);
6982 : }
6983 :
6984 : // clip-path: url, none, inherit
6985 0 : const nsCSSValue* clipPathValue = aRuleData->ValueForClipPath();
6986 0 : if (eCSSUnit_URL == clipPathValue->GetUnit()) {
6987 0 : svgReset->mClipPath = clipPathValue->GetURLValue();
6988 0 : } else if (eCSSUnit_None == clipPathValue->GetUnit() ||
6989 0 : eCSSUnit_Initial == clipPathValue->GetUnit()) {
6990 0 : svgReset->mClipPath = nsnull;
6991 0 : } else if (eCSSUnit_Inherit == clipPathValue->GetUnit()) {
6992 0 : canStoreInRuleTree = false;
6993 0 : svgReset->mClipPath = parentSVGReset->mClipPath;
6994 : }
6995 :
6996 : // stop-opacity:
6997 0 : SetFactor(*aRuleData->ValueForStopOpacity(),
6998 : svgReset->mStopOpacity, canStoreInRuleTree,
6999 0 : parentSVGReset->mStopOpacity, 1.0f, SETFCT_OPACITY);
7000 :
7001 : // flood-opacity:
7002 0 : SetFactor(*aRuleData->ValueForFloodOpacity(),
7003 : svgReset->mFloodOpacity, canStoreInRuleTree,
7004 0 : parentSVGReset->mFloodOpacity, 1.0f, SETFCT_OPACITY);
7005 :
7006 : // dominant-baseline: enum, inherit, initial
7007 0 : SetDiscrete(*aRuleData->ValueForDominantBaseline(),
7008 : svgReset->mDominantBaseline,
7009 : canStoreInRuleTree, SETDSC_ENUMERATED,
7010 : parentSVGReset->mDominantBaseline,
7011 0 : NS_STYLE_DOMINANT_BASELINE_AUTO, 0, 0, 0, 0);
7012 :
7013 : // filter: url, none, inherit
7014 0 : const nsCSSValue* filterValue = aRuleData->ValueForFilter();
7015 0 : if (eCSSUnit_URL == filterValue->GetUnit()) {
7016 0 : svgReset->mFilter = filterValue->GetURLValue();
7017 0 : } else if (eCSSUnit_None == filterValue->GetUnit() ||
7018 0 : eCSSUnit_Initial == filterValue->GetUnit()) {
7019 0 : svgReset->mFilter = nsnull;
7020 0 : } else if (eCSSUnit_Inherit == filterValue->GetUnit()) {
7021 0 : canStoreInRuleTree = false;
7022 0 : svgReset->mFilter = parentSVGReset->mFilter;
7023 : }
7024 :
7025 : // mask: url, none, inherit
7026 0 : const nsCSSValue* maskValue = aRuleData->ValueForMask();
7027 0 : if (eCSSUnit_URL == maskValue->GetUnit()) {
7028 0 : svgReset->mMask = maskValue->GetURLValue();
7029 0 : } else if (eCSSUnit_None == maskValue->GetUnit() ||
7030 0 : eCSSUnit_Initial == maskValue->GetUnit()) {
7031 0 : svgReset->mMask = nsnull;
7032 0 : } else if (eCSSUnit_Inherit == maskValue->GetUnit()) {
7033 0 : canStoreInRuleTree = false;
7034 0 : svgReset->mMask = parentSVGReset->mMask;
7035 : }
7036 :
7037 0 : COMPUTE_END_RESET(SVGReset, svgReset)
7038 : }
7039 :
7040 : inline const void*
7041 0 : nsRuleNode::GetParentData(const nsStyleStructID aSID)
7042 : {
7043 0 : NS_PRECONDITION(mDependentBits & nsCachedStyleData::GetBitForSID(aSID),
7044 : "should be called when node depends on parent data");
7045 0 : NS_ASSERTION(mStyleData.GetStyleData(aSID) == nsnull,
7046 : "both struct and dependent bits present");
7047 : // Walk up the rule tree from this rule node (towards less specific
7048 : // rules).
7049 0 : PRUint32 bit = nsCachedStyleData::GetBitForSID(aSID);
7050 0 : nsRuleNode *ruleNode = mParent;
7051 0 : while (ruleNode->mDependentBits & bit) {
7052 0 : NS_ASSERTION(ruleNode->mStyleData.GetStyleData(aSID) == nsnull,
7053 : "both struct and dependent bits present");
7054 0 : ruleNode = ruleNode->mParent;
7055 : }
7056 :
7057 0 : return ruleNode->mStyleData.GetStyleData(aSID);
7058 : }
7059 :
7060 : #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
7061 : inline const nsStyle##name_ * \
7062 : nsRuleNode::GetParent##name_() \
7063 : { \
7064 : NS_PRECONDITION(mDependentBits & \
7065 : nsCachedStyleData::GetBitForSID(eStyleStruct_##name_), \
7066 : "should be called when node depends on parent data"); \
7067 : NS_ASSERTION(mStyleData.GetStyle##name_() == nsnull, \
7068 : "both struct and dependent bits present"); \
7069 : /* Walk up the rule tree from this rule node (towards less specific */ \
7070 : /* rules). */ \
7071 : PRUint32 bit = nsCachedStyleData::GetBitForSID(eStyleStruct_##name_); \
7072 : nsRuleNode *ruleNode = mParent; \
7073 : while (ruleNode->mDependentBits & bit) { \
7074 : NS_ASSERTION(ruleNode->mStyleData.GetStyle##name_() == nsnull, \
7075 : "both struct and dependent bits present"); \
7076 : ruleNode = ruleNode->mParent; \
7077 : } \
7078 : \
7079 : return ruleNode->mStyleData.GetStyle##name_(); \
7080 : }
7081 : #include "nsStyleStructList.h"
7082 : #undef STYLE_STRUCT
7083 :
7084 : const void*
7085 0 : nsRuleNode::GetStyleData(nsStyleStructID aSID,
7086 : nsStyleContext* aContext,
7087 : bool aComputeData)
7088 : {
7089 : const void *data;
7090 0 : if (mDependentBits & nsCachedStyleData::GetBitForSID(aSID)) {
7091 : // We depend on an ancestor for this struct since the cached struct
7092 : // it has is also appropriate for this rule node. Just go up the
7093 : // rule tree and return the first cached struct we find.
7094 0 : data = GetParentData(aSID);
7095 0 : NS_ASSERTION(data, "dependent bits set but no cached struct present");
7096 0 : return data;
7097 : }
7098 :
7099 0 : data = mStyleData.GetStyleData(aSID);
7100 0 : if (NS_LIKELY(data != nsnull))
7101 0 : return data; // We have a fully specified struct. Just return it.
7102 :
7103 0 : if (NS_UNLIKELY(!aComputeData))
7104 0 : return nsnull;
7105 :
7106 : // Nothing is cached. We'll have to delve further and examine our rules.
7107 0 : data = WalkRuleTree(aSID, aContext);
7108 :
7109 0 : if (NS_LIKELY(data != nsnull))
7110 0 : return data;
7111 :
7112 0 : NS_NOTREACHED("could not create style struct");
7113 : // To ensure that |GetStyleData| never returns null (even when we're
7114 : // out of memory), we'll get the style set and get a copy of the
7115 : // default values for the given style struct from the set. Note that
7116 : // this works fine even if |this| is a rule node that has been
7117 : // destroyed (leftover from a previous rule tree) but is somehow still
7118 : // used.
7119 : return mPresContext->PresShell()->StyleSet()->
7120 0 : DefaultStyleData()->GetStyleData(aSID);
7121 : }
7122 :
7123 : // See comments above in GetStyleData for an explanation of what the
7124 : // code below does.
7125 : #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
7126 : const nsStyle##name_* \
7127 : nsRuleNode::GetStyle##name_(nsStyleContext* aContext, bool aComputeData) \
7128 : { \
7129 : const nsStyle##name_ *data; \
7130 : if (mDependentBits & \
7131 : nsCachedStyleData::GetBitForSID(eStyleStruct_##name_)) { \
7132 : data = GetParent##name_(); \
7133 : NS_ASSERTION(data, "dependent bits set but no cached struct present"); \
7134 : return data; \
7135 : } \
7136 : \
7137 : data = mStyleData.GetStyle##name_(); \
7138 : if (NS_LIKELY(data != nsnull)) \
7139 : return data; \
7140 : \
7141 : if (NS_UNLIKELY(!aComputeData)) \
7142 : return nsnull; \
7143 : \
7144 : data = static_cast<const nsStyle##name_ *> \
7145 : (WalkRuleTree(eStyleStruct_##name_, aContext)); \
7146 : \
7147 : if (NS_LIKELY(data != nsnull)) \
7148 : return data; \
7149 : \
7150 : NS_NOTREACHED("could not create style struct"); \
7151 : return \
7152 : static_cast<const nsStyle##name_ *>( \
7153 : mPresContext->PresShell()->StyleSet()-> \
7154 : DefaultStyleData()->GetStyleData(eStyleStruct_##name_)); \
7155 : }
7156 : #include "nsStyleStructList.h"
7157 : #undef STYLE_STRUCT
7158 :
7159 : void
7160 0 : nsRuleNode::Mark()
7161 : {
7162 0 : for (nsRuleNode *node = this;
7163 0 : node && !(node->mDependentBits & NS_RULE_NODE_GC_MARK);
7164 : node = node->mParent)
7165 0 : node->mDependentBits |= NS_RULE_NODE_GC_MARK;
7166 0 : }
7167 :
7168 : static PLDHashOperator
7169 0 : SweepRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
7170 : PRUint32 number, void *arg)
7171 : {
7172 0 : ChildrenHashEntry *entry = static_cast<ChildrenHashEntry*>(hdr);
7173 0 : if (entry->mRuleNode->Sweep())
7174 0 : return PL_DHASH_REMOVE; // implies NEXT, unless |ed with STOP
7175 0 : return PL_DHASH_NEXT;
7176 : }
7177 :
7178 : bool
7179 0 : nsRuleNode::Sweep()
7180 : {
7181 : // If we're not marked, then we have to delete ourself.
7182 : // However, we never allow the root node to GC itself, because nsStyleSet
7183 : // wants to hold onto the root node and not worry about re-creating a
7184 : // rule walker if the root node is deleted.
7185 0 : if (!(mDependentBits & NS_RULE_NODE_GC_MARK) &&
7186 : // Skip this only if we're the *current* root and not an old one.
7187 0 : !(IsRoot() && mPresContext->StyleSet()->GetRuleTree() == this)) {
7188 0 : Destroy();
7189 0 : return true;
7190 : }
7191 :
7192 : // Clear our mark, for the next time around.
7193 0 : mDependentBits &= ~NS_RULE_NODE_GC_MARK;
7194 :
7195 : // Call sweep on the children, since some may not be marked, and
7196 : // remove any deleted children from the child lists.
7197 0 : if (HaveChildren()) {
7198 : PRUint32 childrenDestroyed;
7199 0 : if (ChildrenAreHashed()) {
7200 0 : PLDHashTable *children = ChildrenHash();
7201 0 : PRUint32 oldChildCount = children->entryCount;
7202 0 : PL_DHashTableEnumerate(children, SweepRuleNodeChildren, nsnull);
7203 0 : childrenDestroyed = children->entryCount - oldChildCount;
7204 : } else {
7205 0 : childrenDestroyed = 0;
7206 0 : for (nsRuleNode **children = ChildrenListPtr(); *children; ) {
7207 0 : nsRuleNode *next = (*children)->mNextSibling;
7208 0 : if ((*children)->Sweep()) {
7209 : // This rule node was destroyed, so implicitly advance by
7210 : // making *children point to the next entry.
7211 0 : *children = next;
7212 0 : ++childrenDestroyed;
7213 : } else {
7214 : // Advance.
7215 0 : children = &(*children)->mNextSibling;
7216 : }
7217 : }
7218 : }
7219 0 : mRefCnt -= childrenDestroyed;
7220 0 : NS_POSTCONDITION(IsRoot() || mRefCnt > 0,
7221 : "We didn't get swept, so we'd better have style contexts "
7222 : "pointing to us or to one of our descendants, which means "
7223 : "we'd better have a nonzero mRefCnt here!");
7224 : }
7225 0 : return false;
7226 : }
7227 :
7228 : /* static */ bool
7229 0 : nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
7230 : PRUint32 ruleTypeMask,
7231 : bool aAuthorColorsAllowed)
7232 : {
7233 0 : PRUint32 inheritBits = 0;
7234 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND)
7235 0 : inheritBits |= NS_STYLE_INHERIT_BIT(Background);
7236 :
7237 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER)
7238 0 : inheritBits |= NS_STYLE_INHERIT_BIT(Border);
7239 :
7240 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING)
7241 0 : inheritBits |= NS_STYLE_INHERIT_BIT(Padding);
7242 :
7243 : // properties in the SIDS, whether or not we care about them
7244 0 : size_t nprops = 0, backgroundOffset, borderOffset, paddingOffset;
7245 :
7246 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
7247 0 : backgroundOffset = nprops;
7248 0 : nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Background);
7249 : }
7250 :
7251 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
7252 0 : borderOffset = nprops;
7253 0 : nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Border);
7254 : }
7255 :
7256 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
7257 0 : paddingOffset = nprops;
7258 0 : nprops += nsCSSProps::PropertyCountInStruct(eStyleStruct_Padding);
7259 : }
7260 :
7261 0 : void* dataStorage = alloca(nprops * sizeof(nsCSSValue));
7262 0 : AutoCSSValueArray dataArray(dataStorage, nprops);
7263 :
7264 : /* We're relying on the use of |aStyleContext| not mutating it! */
7265 : nsRuleData ruleData(inheritBits, dataArray.get(),
7266 0 : aStyleContext->PresContext(), aStyleContext);
7267 :
7268 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
7269 0 : ruleData.mValueOffsets[eStyleStruct_Background] = backgroundOffset;
7270 : }
7271 :
7272 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
7273 0 : ruleData.mValueOffsets[eStyleStruct_Border] = borderOffset;
7274 : }
7275 :
7276 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
7277 0 : ruleData.mValueOffsets[eStyleStruct_Padding] = paddingOffset;
7278 : }
7279 :
7280 : static const nsCSSProperty backgroundValues[] = {
7281 : eCSSProperty_background_color,
7282 : eCSSProperty_background_image,
7283 : };
7284 :
7285 : static const nsCSSProperty borderValues[] = {
7286 : eCSSProperty_border_top_color,
7287 : eCSSProperty_border_top_style,
7288 : eCSSProperty_border_top_width,
7289 : eCSSProperty_border_right_color_value,
7290 : eCSSProperty_border_right_style_value,
7291 : eCSSProperty_border_right_width_value,
7292 : eCSSProperty_border_bottom_color,
7293 : eCSSProperty_border_bottom_style,
7294 : eCSSProperty_border_bottom_width,
7295 : eCSSProperty_border_left_color_value,
7296 : eCSSProperty_border_left_style_value,
7297 : eCSSProperty_border_left_width_value,
7298 : eCSSProperty_border_start_color_value,
7299 : eCSSProperty_border_start_style_value,
7300 : eCSSProperty_border_start_width_value,
7301 : eCSSProperty_border_end_color_value,
7302 : eCSSProperty_border_end_style_value,
7303 : eCSSProperty_border_end_width_value,
7304 : eCSSProperty_border_top_left_radius,
7305 : eCSSProperty_border_top_right_radius,
7306 : eCSSProperty_border_bottom_right_radius,
7307 : eCSSProperty_border_bottom_left_radius,
7308 : };
7309 :
7310 : static const nsCSSProperty paddingValues[] = {
7311 : eCSSProperty_padding_top,
7312 : eCSSProperty_padding_right_value,
7313 : eCSSProperty_padding_bottom,
7314 : eCSSProperty_padding_left_value,
7315 : eCSSProperty_padding_start_value,
7316 : eCSSProperty_padding_end_value,
7317 : };
7318 :
7319 : // Number of properties we care about
7320 0 : size_t nValues = 0;
7321 :
7322 : nsCSSValue* values[NS_ARRAY_LENGTH(backgroundValues) +
7323 : NS_ARRAY_LENGTH(borderValues) +
7324 : NS_ARRAY_LENGTH(paddingValues)];
7325 :
7326 : nsCSSProperty properties[NS_ARRAY_LENGTH(backgroundValues) +
7327 : NS_ARRAY_LENGTH(borderValues) +
7328 : NS_ARRAY_LENGTH(paddingValues)];
7329 :
7330 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND) {
7331 0 : for (PRUint32 i = 0, i_end = ArrayLength(backgroundValues);
7332 : i < i_end; ++i) {
7333 0 : properties[nValues] = backgroundValues[i];
7334 0 : values[nValues++] = ruleData.ValueFor(backgroundValues[i]);
7335 : }
7336 : }
7337 :
7338 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BORDER) {
7339 0 : for (PRUint32 i = 0, i_end = ArrayLength(borderValues);
7340 : i < i_end; ++i) {
7341 0 : properties[nValues] = borderValues[i];
7342 0 : values[nValues++] = ruleData.ValueFor(borderValues[i]);
7343 : }
7344 : }
7345 :
7346 0 : if (ruleTypeMask & NS_AUTHOR_SPECIFIED_PADDING) {
7347 0 : for (PRUint32 i = 0, i_end = ArrayLength(paddingValues);
7348 : i < i_end; ++i) {
7349 0 : properties[nValues] = paddingValues[i];
7350 0 : values[nValues++] = ruleData.ValueFor(paddingValues[i]);
7351 : }
7352 : }
7353 :
7354 0 : nsStyleContext* styleContext = aStyleContext;
7355 :
7356 : // We need to be careful not to count styles covered up by user-important or
7357 : // UA-important declarations. But we do want to catch explicit inherit
7358 : // styling in those and check our parent style context to see whether we have
7359 : // user styling for those properties. Note that we don't care here about
7360 : // inheritance due to lack of a specified value, since all the properties we
7361 : // care about are reset properties.
7362 : bool haveExplicitUAInherit;
7363 0 : do {
7364 0 : haveExplicitUAInherit = false;
7365 0 : for (nsRuleNode* ruleNode = styleContext->GetRuleNode(); ruleNode;
7366 : ruleNode = ruleNode->GetParent()) {
7367 0 : nsIStyleRule *rule = ruleNode->GetRule();
7368 0 : if (rule) {
7369 0 : ruleData.mLevel = ruleNode->GetLevel();
7370 0 : ruleData.mIsImportantRule = ruleNode->IsImportantRule();
7371 :
7372 0 : rule->MapRuleInfoInto(&ruleData);
7373 :
7374 0 : if (ruleData.mLevel == nsStyleSet::eAgentSheet ||
7375 : ruleData.mLevel == nsStyleSet::eUserSheet) {
7376 : // This is a rule whose effect we want to ignore, so if any of
7377 : // the properties we care about were set, set them to the dummy
7378 : // value that they'll never otherwise get.
7379 0 : for (PRUint32 i = 0; i < nValues; ++i) {
7380 0 : nsCSSUnit unit = values[i]->GetUnit();
7381 0 : if (unit != eCSSUnit_Null &&
7382 : unit != eCSSUnit_Dummy &&
7383 : unit != eCSSUnit_DummyInherit) {
7384 0 : if (unit == eCSSUnit_Inherit) {
7385 0 : haveExplicitUAInherit = true;
7386 0 : values[i]->SetDummyInheritValue();
7387 : } else {
7388 0 : values[i]->SetDummyValue();
7389 : }
7390 : }
7391 0 : }
7392 : } else {
7393 : // If any of the values we care about was set by the above rule,
7394 : // we have author style.
7395 0 : for (PRUint32 i = 0; i < nValues; ++i) {
7396 0 : if (values[i]->GetUnit() != eCSSUnit_Null &&
7397 0 : values[i]->GetUnit() != eCSSUnit_Dummy && // see above
7398 0 : values[i]->GetUnit() != eCSSUnit_DummyInherit) {
7399 : // If author colors are not allowed, only claim to have
7400 : // author-specified rules if we're looking at a non-color
7401 : // property or if we're looking at the background color and it's
7402 : // set to transparent. Anything else should get set to a dummy
7403 : // value instead.
7404 0 : if (aAuthorColorsAllowed ||
7405 : !nsCSSProps::PropHasFlags(properties[i],
7406 0 : CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED) ||
7407 0 : (properties[i] == eCSSProperty_background_color &&
7408 0 : !values[i]->IsNonTransparentColor())) {
7409 0 : return true;
7410 : }
7411 :
7412 0 : values[i]->SetDummyValue();
7413 : }
7414 : }
7415 : }
7416 : }
7417 : }
7418 :
7419 0 : if (haveExplicitUAInherit) {
7420 : // reset all the eCSSUnit_Null values to eCSSUnit_Dummy (since they're
7421 : // not styled by the author, or by anyone else), and then reset all the
7422 : // eCSSUnit_DummyInherit values to eCSSUnit_Null (so we will be able to
7423 : // detect them being styled by the author) and move up to our parent
7424 : // style context.
7425 0 : for (PRUint32 i = 0; i < nValues; ++i)
7426 0 : if (values[i]->GetUnit() == eCSSUnit_Null)
7427 0 : values[i]->SetDummyValue();
7428 0 : for (PRUint32 i = 0; i < nValues; ++i)
7429 0 : if (values[i]->GetUnit() == eCSSUnit_DummyInherit)
7430 0 : values[i]->Reset();
7431 0 : styleContext = styleContext->GetParent();
7432 : }
7433 : } while (haveExplicitUAInherit && styleContext);
7434 :
7435 0 : return false;
7436 : }
|