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