Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / layout / style / nsStyleStruct.cpp
blob35cde98dc8ab98c304a6a905a01b94f1be4d2212
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
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/
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.
15 * The Original Code is mozilla.org code.
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.
22 * Contributor(s):
23 * David Hyatt (hyatt@netscape.com)
24 * Mats Palmgren <mats.palmgren@bredband.net>
25 * Michael Ventnor <m.ventnor@gmail.com>
26 * Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
27 * L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
29 * Alternatively, the contents of this file may be used under the terms of
30 * either of the GNU General Public License Version 2 or later (the "GPL"),
31 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 * in which case the provisions of the GPL or the LGPL are applicable instead
33 * of those above. If you wish to allow use of your version of this file only
34 * under the terms of either the GPL or the LGPL, and not to allow others to
35 * use your version of this file under the terms of the MPL, indicate your
36 * decision by deleting the provisions above and replace them with the notice
37 * and other provisions required by the GPL or the LGPL. If you do not delete
38 * the provisions above, a recipient may use your version of this file under
39 * the terms of any one of the MPL, the GPL or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
44 * structs that contain the data provided by nsStyleContext, the
45 * internal API for computed style data for an element
48 #include "nsStyleStruct.h"
49 #include "nsStyleStructInlines.h"
50 #include "nsStyleConsts.h"
51 #include "nsThemeConstants.h"
52 #include "nsString.h"
53 #include "nsPresContext.h"
54 #include "nsIDeviceContext.h"
55 #include "nsIWidget.h"
56 #include "nsIStyleRule.h"
57 #include "nsCRT.h"
58 #include "nsCSSProps.h"
60 #include "nsCOMPtr.h"
61 #include "nsIFrame.h"
62 #include "nsHTMLReflowState.h"
63 #include "prenv.h"
65 #include "nsSVGUtils.h"
66 #include "nsBidiUtils.h"
68 #include "imgIRequest.h"
69 #include "imgIContainer.h"
70 #include "prlog.h"
72 // Make sure we have enough bits in NS_STYLE_INHERIT_MASK.
73 PR_STATIC_ASSERT((((1 << nsStyleStructID_Length) - 1) &
74 ~(NS_STYLE_INHERIT_MASK)) == 0);
76 inline PRBool IsFixedUnit(const nsStyleCoord& aCoord, PRBool aEnumOK)
78 return aCoord.ConvertsToLength() ||
79 (aEnumOK && aCoord.GetUnit() == eStyleUnit_Enumerated);
82 static PRBool EqualURIs(nsIURI *aURI1, nsIURI *aURI2)
84 PRBool eq;
85 return aURI1 == aURI2 || // handle null==null, and optimize
86 (aURI1 && aURI2 &&
87 NS_SUCCEEDED(aURI1->Equals(aURI2, &eq)) && // not equal on fail
88 eq);
91 static PRBool EqualURIs(nsCSSValue::URL *aURI1, nsCSSValue::URL *aURI2)
93 return aURI1 == aURI2 || // handle null==null, and optimize
94 (aURI1 && aURI2 && aURI1->URIEquals(*aURI2));
97 static PRBool EqualImages(imgIRequest *aImage1, imgIRequest* aImage2)
99 if (aImage1 == aImage2) {
100 return PR_TRUE;
103 if (!aImage1 || !aImage2) {
104 return PR_FALSE;
107 nsCOMPtr<nsIURI> uri1, uri2;
108 aImage1->GetURI(getter_AddRefs(uri1));
109 aImage2->GetURI(getter_AddRefs(uri2));
110 return EqualURIs(uri1, uri2);
113 static nsChangeHint CalcShadowDifference(nsCSSShadowArray* lhs,
114 nsCSSShadowArray* rhs);
116 // --------------------
117 // nsStyleFont
119 nsStyleFont::nsStyleFont(const nsFont& aFont, nsPresContext *aPresContext)
120 : mFont(aFont),
121 mGenericID(kGenericFont_NONE)
123 MOZ_COUNT_CTOR(nsStyleFont);
124 mSize = mFont.size = nsStyleFont::ZoomText(aPresContext, mFont.size);
125 #ifdef MOZ_MATHML
126 mScriptUnconstrainedSize = mSize;
127 mScriptMinSize = aPresContext->CSSTwipsToAppUnits(
128 NS_POINTS_TO_TWIPS(NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT));
129 mScriptLevel = 0;
130 mScriptSizeMultiplier = NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER;
131 #endif
134 nsStyleFont::nsStyleFont(const nsStyleFont& aSrc)
135 : mFont(aSrc.mFont)
136 , mSize(aSrc.mSize)
137 , mGenericID(aSrc.mGenericID)
138 #ifdef MOZ_MATHML
139 , mScriptLevel(aSrc.mScriptLevel)
140 , mScriptUnconstrainedSize(aSrc.mScriptUnconstrainedSize)
141 , mScriptMinSize(aSrc.mScriptMinSize)
142 , mScriptSizeMultiplier(aSrc.mScriptSizeMultiplier)
143 #endif
145 MOZ_COUNT_CTOR(nsStyleFont);
148 nsStyleFont::nsStyleFont(nsPresContext* aPresContext)
149 : mFont(*(aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID))),
150 mGenericID(kGenericFont_NONE)
152 MOZ_COUNT_CTOR(nsStyleFont);
153 mSize = mFont.size = nsStyleFont::ZoomText(aPresContext, mFont.size);
154 #ifdef MOZ_MATHML
155 mScriptUnconstrainedSize = mSize;
156 mScriptMinSize = aPresContext->CSSTwipsToAppUnits(
157 NS_POINTS_TO_TWIPS(NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT));
158 mScriptLevel = 0;
159 mScriptSizeMultiplier = NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER;
160 #endif
163 void*
164 nsStyleFont::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
165 void* result = aContext->AllocateFromShell(sz);
166 if (result)
167 memset(result, 0, sz);
168 return result;
171 void
172 nsStyleFont::Destroy(nsPresContext* aContext) {
173 this->~nsStyleFont();
174 aContext->FreeToShell(sizeof(nsStyleFont), this);
177 nsChangeHint nsStyleFont::CalcDifference(const nsStyleFont& aOther) const
179 if (mSize == aOther.mSize) {
180 return CalcFontDifference(mFont, aOther.mFont);
182 return NS_STYLE_HINT_REFLOW;
185 #ifdef DEBUG
186 /* static */
187 nsChangeHint nsStyleFont::MaxDifference()
189 return NS_STYLE_HINT_REFLOW;
191 #endif
193 /* static */ nscoord
194 nsStyleFont::ZoomText(nsPresContext *aPresContext, nscoord aSize)
196 return nscoord(float(aSize) * aPresContext->TextZoom());
199 /* static */ nscoord
200 nsStyleFont::UnZoomText(nsPresContext *aPresContext, nscoord aSize)
202 return nscoord(float(aSize) / aPresContext->TextZoom());
205 nsChangeHint nsStyleFont::CalcFontDifference(const nsFont& aFont1, const nsFont& aFont2)
207 if ((aFont1.size == aFont2.size) &&
208 (aFont1.sizeAdjust == aFont2.sizeAdjust) &&
209 (aFont1.style == aFont2.style) &&
210 (aFont1.variant == aFont2.variant) &&
211 (aFont1.familyNameQuirks == aFont2.familyNameQuirks) &&
212 (aFont1.weight == aFont2.weight) &&
213 (aFont1.stretch == aFont2.stretch) &&
214 (aFont1.name == aFont2.name) &&
215 (aFont1.featureSettings == aFont2.featureSettings) &&
216 (aFont1.languageOverride == aFont2.languageOverride)) {
217 if ((aFont1.decorations == aFont2.decorations)) {
218 return NS_STYLE_HINT_NONE;
220 return NS_STYLE_HINT_VISUAL;
222 return NS_STYLE_HINT_REFLOW;
225 static PRBool IsFixedData(const nsStyleSides& aSides, PRBool aEnumOK)
227 NS_FOR_CSS_SIDES(side) {
228 if (!IsFixedUnit(aSides.Get(side), aEnumOK))
229 return PR_FALSE;
231 return PR_TRUE;
234 static nscoord CalcCoord(const nsStyleCoord& aCoord,
235 const nscoord* aEnumTable,
236 PRInt32 aNumEnums)
238 if (aCoord.GetUnit() == eStyleUnit_Enumerated) {
239 NS_ABORT_IF_FALSE(aEnumTable, "must have enum table");
240 PRInt32 value = aCoord.GetIntValue();
241 if (0 <= value && value < aNumEnums) {
242 return aEnumTable[aCoord.GetIntValue()];
244 NS_NOTREACHED("unexpected enum value");
245 return 0;
247 NS_ABORT_IF_FALSE(aCoord.ConvertsToLength(), "unexpected unit");
248 return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
251 nsStyleMargin::nsStyleMargin() {
252 MOZ_COUNT_CTOR(nsStyleMargin);
253 nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
254 NS_FOR_CSS_SIDES(side) {
255 mMargin.Set(side, zero);
257 mHasCachedMargin = PR_FALSE;
260 nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc) {
261 MOZ_COUNT_CTOR(nsStyleMargin);
262 mMargin = aSrc.mMargin;
263 mHasCachedMargin = PR_FALSE;
266 void*
267 nsStyleMargin::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
268 void* result = aContext->AllocateFromShell(sz);
269 if (result)
270 memset(result, 0, sz);
271 return result;
274 void
275 nsStyleMargin::Destroy(nsPresContext* aContext) {
276 this->~nsStyleMargin();
277 aContext->FreeToShell(sizeof(nsStyleMargin), this);
281 void nsStyleMargin::RecalcData()
283 if (IsFixedData(mMargin, PR_FALSE)) {
284 NS_FOR_CSS_SIDES(side) {
285 mCachedMargin.side(side) = CalcCoord(mMargin.Get(side), nsnull, 0);
287 mHasCachedMargin = PR_TRUE;
289 else
290 mHasCachedMargin = PR_FALSE;
293 nsChangeHint nsStyleMargin::CalcDifference(const nsStyleMargin& aOther) const
295 if (mMargin == aOther.mMargin) {
296 return NS_STYLE_HINT_NONE;
298 // Margin differences can't affect descendant intrinsic sizes and
299 // don't need to force children to reflow.
300 return NS_SubtractHint(NS_STYLE_HINT_REFLOW,
301 NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
302 nsChangeHint_NeedDirtyReflow));
305 #ifdef DEBUG
306 /* static */
307 nsChangeHint nsStyleMargin::MaxDifference()
309 return NS_SubtractHint(NS_STYLE_HINT_REFLOW,
310 NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
311 nsChangeHint_NeedDirtyReflow));
313 #endif
315 nsStylePadding::nsStylePadding() {
316 MOZ_COUNT_CTOR(nsStylePadding);
317 nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
318 NS_FOR_CSS_SIDES(side) {
319 mPadding.Set(side, zero);
321 mHasCachedPadding = PR_FALSE;
324 nsStylePadding::nsStylePadding(const nsStylePadding& aSrc) {
325 MOZ_COUNT_CTOR(nsStylePadding);
326 mPadding = aSrc.mPadding;
327 mHasCachedPadding = PR_FALSE;
330 void*
331 nsStylePadding::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
332 void* result = aContext->AllocateFromShell(sz);
333 if (result)
334 memset(result, 0, sz);
335 return result;
338 void
339 nsStylePadding::Destroy(nsPresContext* aContext) {
340 this->~nsStylePadding();
341 aContext->FreeToShell(sizeof(nsStylePadding), this);
344 void nsStylePadding::RecalcData()
346 if (IsFixedData(mPadding, PR_FALSE)) {
347 NS_FOR_CSS_SIDES(side) {
348 // Clamp negative calc() to 0.
349 mCachedPadding.side(side) =
350 NS_MAX(CalcCoord(mPadding.Get(side), nsnull, 0), 0);
352 mHasCachedPadding = PR_TRUE;
354 else
355 mHasCachedPadding = PR_FALSE;
358 nsChangeHint nsStylePadding::CalcDifference(const nsStylePadding& aOther) const
360 if (mPadding == aOther.mPadding) {
361 return NS_STYLE_HINT_NONE;
363 // Padding differences can't affect descendant intrinsic sizes, but do need
364 // to force children to reflow so that we can reposition them, since their
365 // offsets are from our frame bounds but our content rect's position within
366 // those bounds is moving.
367 return NS_SubtractHint(NS_STYLE_HINT_REFLOW,
368 nsChangeHint_ClearDescendantIntrinsics);
371 #ifdef DEBUG
372 /* static */
373 nsChangeHint nsStylePadding::MaxDifference()
375 return NS_SubtractHint(NS_STYLE_HINT_REFLOW,
376 nsChangeHint_ClearDescendantIntrinsics);
378 #endif
380 nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext)
381 : mHaveBorderImageWidth(PR_FALSE)
382 #ifdef DEBUG
383 , mImageTracked(false)
384 #endif
385 , mComputedBorder(0, 0, 0, 0)
386 , mBorderImage(nsnull)
388 MOZ_COUNT_CTOR(nsStyleBorder);
389 nscoord medium =
390 (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
391 NS_FOR_CSS_SIDES(side) {
392 mBorder.side(side) = medium;
393 mBorderStyle[side] = NS_STYLE_BORDER_STYLE_NONE | BORDER_COLOR_FOREGROUND;
394 mBorderColor[side] = NS_RGB(0, 0, 0);
396 NS_FOR_CSS_HALF_CORNERS(corner) {
397 mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
400 mBorderColors = nsnull;
401 mBoxShadow = nsnull;
403 mFloatEdge = NS_STYLE_FLOAT_EDGE_CONTENT;
405 mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
408 nsBorderColors::~nsBorderColors()
410 NS_CSS_DELETE_LIST_MEMBER(nsBorderColors, this, mNext);
413 nsBorderColors*
414 nsBorderColors::Clone(PRBool aDeep) const
416 nsBorderColors* result = new nsBorderColors(mColor);
417 if (NS_UNLIKELY(!result))
418 return result;
419 if (aDeep)
420 NS_CSS_CLONE_LIST_MEMBER(nsBorderColors, this, mNext, result, (PR_FALSE));
421 return result;
424 nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
425 : mBorderRadius(aSrc.mBorderRadius),
426 mBorderImageSplit(aSrc.mBorderImageSplit),
427 mFloatEdge(aSrc.mFloatEdge),
428 mBorderImageHFill(aSrc.mBorderImageHFill),
429 mBorderImageVFill(aSrc.mBorderImageVFill),
430 mBorderColors(nsnull),
431 mBoxShadow(aSrc.mBoxShadow),
432 mHaveBorderImageWidth(aSrc.mHaveBorderImageWidth),
433 mBorderImageWidth(aSrc.mBorderImageWidth),
434 mComputedBorder(aSrc.mComputedBorder),
435 mBorder(aSrc.mBorder),
436 mBorderImage(aSrc.mBorderImage),
437 mTwipsPerPixel(aSrc.mTwipsPerPixel)
439 MOZ_COUNT_CTOR(nsStyleBorder);
440 if (aSrc.mBorderColors) {
441 EnsureBorderColors();
442 for (PRInt32 i = 0; i < 4; i++)
443 if (aSrc.mBorderColors[i])
444 mBorderColors[i] = aSrc.mBorderColors[i]->Clone();
445 else
446 mBorderColors[i] = nsnull;
449 NS_FOR_CSS_SIDES(side) {
450 mBorderStyle[side] = aSrc.mBorderStyle[side];
451 mBorderColor[side] = aSrc.mBorderColor[side];
453 NS_FOR_CSS_HALF_CORNERS(corner) {
454 mBorderRadius.Set(corner, aSrc.mBorderRadius.Get(corner));
458 nsStyleBorder::~nsStyleBorder()
460 NS_ABORT_IF_FALSE(!mImageTracked,
461 "nsStyleBorder being destroyed while still tracking image!");
462 MOZ_COUNT_DTOR(nsStyleBorder);
463 if (mBorderColors) {
464 for (PRInt32 i = 0; i < 4; i++)
465 delete mBorderColors[i];
466 delete [] mBorderColors;
470 void*
471 nsStyleBorder::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
472 void* result = aContext->AllocateFromShell(sz);
473 if (result)
474 memset(result, 0, sz);
475 return result;
478 void
479 nsStyleBorder::Destroy(nsPresContext* aContext) {
480 if (mBorderImage)
481 UntrackImage(aContext);
482 this->~nsStyleBorder();
483 aContext->FreeToShell(sizeof(nsStyleBorder), this);
487 nsChangeHint nsStyleBorder::CalcDifference(const nsStyleBorder& aOther) const
489 nsChangeHint shadowDifference =
490 CalcShadowDifference(mBoxShadow, aOther.mBoxShadow);
492 // Note that differences in mBorder don't affect rendering (which should only
493 // use mComputedBorder), so don't need to be tested for here.
494 // XXXbz we should be able to return a more specific change hint for
495 // at least GetActualBorder() differences...
496 if (mTwipsPerPixel != aOther.mTwipsPerPixel ||
497 GetActualBorder() != aOther.GetActualBorder() ||
498 mFloatEdge != aOther.mFloatEdge ||
499 (shadowDifference & nsChangeHint_ReflowFrame))
500 return NS_STYLE_HINT_REFLOW;
502 // Note that mBorderStyle stores not only the border style but also
503 // color-related flags. Given that we've already done an mComputedBorder
504 // comparison, border-style differences can only lead to a VISUAL hint. So
505 // it's OK to just compare the values directly -- if either the actual
506 // style or the color flags differ we want to repaint.
507 NS_FOR_CSS_SIDES(ix) {
508 if (mBorderStyle[ix] != aOther.mBorderStyle[ix] ||
509 mBorderColor[ix] != aOther.mBorderColor[ix])
510 return NS_STYLE_HINT_VISUAL;
513 if (mBorderRadius != aOther.mBorderRadius ||
514 !mBorderColors != !aOther.mBorderColors)
515 return NS_STYLE_HINT_VISUAL;
517 if (IsBorderImageLoaded() || aOther.IsBorderImageLoaded()) {
518 if (mBorderImage != aOther.mBorderImage ||
519 mBorderImageHFill != aOther.mBorderImageHFill ||
520 mBorderImageVFill != aOther.mBorderImageVFill ||
521 mBorderImageSplit != aOther.mBorderImageSplit)
522 return NS_STYLE_HINT_VISUAL;
523 // The call to GetActualBorder above already considered
524 // mBorderImageWidth and mHaveBorderImageWidth.
527 // Note that at this point if mBorderColors is non-null so is
528 // aOther.mBorderColors
529 if (mBorderColors) {
530 NS_FOR_CSS_SIDES(ix) {
531 if (!nsBorderColors::Equal(mBorderColors[ix],
532 aOther.mBorderColors[ix]))
533 return NS_STYLE_HINT_VISUAL;
537 return shadowDifference;
540 #ifdef DEBUG
541 /* static */
542 nsChangeHint nsStyleBorder::MaxDifference()
544 return NS_STYLE_HINT_REFLOW;
546 #endif
548 PRBool
549 nsStyleBorder::ImageBorderDiffers() const
551 return mComputedBorder !=
552 (mHaveBorderImageWidth ? mBorderImageWidth : mBorder);
555 const nsMargin&
556 nsStyleBorder::GetActualBorder() const
558 if (IsBorderImageLoaded())
559 if (mHaveBorderImageWidth)
560 return mBorderImageWidth;
561 else
562 return mBorder;
563 else
564 return mComputedBorder;
567 void
568 nsStyleBorder::TrackImage(nsPresContext* aContext)
570 // Sanity
571 NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!");
572 NS_ABORT_IF_FALSE(mBorderImage, "Can't track null image!");
574 // Register the image with the document
575 nsIDocument* doc = aContext->Document();
576 if (doc)
577 doc->AddImage(mBorderImage);
579 // Mark state
580 #ifdef DEBUG
581 mImageTracked = true;
582 #endif
585 void
586 nsStyleBorder::UntrackImage(nsPresContext* aContext)
588 // Sanity
589 NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!");
590 NS_ABORT_IF_FALSE(mBorderImage, "Can't track null image!");
592 // Unregister the image with the document
593 nsIDocument* doc = aContext->Document();
594 if (doc)
595 doc->RemoveImage(mBorderImage);
597 // Mark state
598 #ifdef DEBUG
599 mImageTracked = false;
600 #endif
603 nsStyleOutline::nsStyleOutline(nsPresContext* aPresContext)
605 MOZ_COUNT_CTOR(nsStyleOutline);
606 // spacing values not inherited
607 nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
608 NS_FOR_CSS_HALF_CORNERS(corner) {
609 mOutlineRadius.Set(corner, zero);
612 mOutlineOffset = 0;
614 mOutlineWidth = nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
615 mOutlineStyle = NS_STYLE_BORDER_STYLE_NONE;
616 mOutlineColor = NS_RGB(0, 0, 0);
618 mHasCachedOutline = PR_FALSE;
619 mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
622 nsStyleOutline::nsStyleOutline(const nsStyleOutline& aSrc) {
623 MOZ_COUNT_CTOR(nsStyleOutline);
624 memcpy((nsStyleOutline*)this, &aSrc, sizeof(nsStyleOutline));
627 void
628 nsStyleOutline::RecalcData(nsPresContext* aContext)
630 if (NS_STYLE_BORDER_STYLE_NONE == GetOutlineStyle()) {
631 mCachedOutlineWidth = 0;
632 mHasCachedOutline = PR_TRUE;
633 } else if (IsFixedUnit(mOutlineWidth, PR_TRUE)) {
634 // Clamp negative calc() to 0.
635 mCachedOutlineWidth =
636 NS_MAX(CalcCoord(mOutlineWidth, aContext->GetBorderWidthTable(), 3), 0);
637 mCachedOutlineWidth =
638 NS_ROUND_BORDER_TO_PIXELS(mCachedOutlineWidth, mTwipsPerPixel);
639 mHasCachedOutline = PR_TRUE;
641 else
642 mHasCachedOutline = PR_FALSE;
645 nsChangeHint nsStyleOutline::CalcDifference(const nsStyleOutline& aOther) const
647 PRBool outlineWasVisible =
648 mCachedOutlineWidth > 0 && mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE;
649 PRBool outlineIsVisible =
650 aOther.mCachedOutlineWidth > 0 && aOther.mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE;
651 if (outlineWasVisible != outlineIsVisible ||
652 (outlineIsVisible && (mOutlineOffset != aOther.mOutlineOffset ||
653 mOutlineWidth != aOther.mOutlineWidth ||
654 mTwipsPerPixel != aOther.mTwipsPerPixel))) {
655 return NS_CombineHint(nsChangeHint_ReflowFrame, nsChangeHint_RepaintFrame);
657 if ((mOutlineStyle != aOther.mOutlineStyle) ||
658 (mOutlineColor != aOther.mOutlineColor) ||
659 (mOutlineRadius != aOther.mOutlineRadius)) {
660 return nsChangeHint_RepaintFrame;
662 return NS_STYLE_HINT_NONE;
665 #ifdef DEBUG
666 /* static */
667 nsChangeHint nsStyleOutline::MaxDifference()
669 return NS_CombineHint(nsChangeHint_ReflowFrame, nsChangeHint_RepaintFrame);
671 #endif
673 // --------------------
674 // nsStyleList
676 nsStyleList::nsStyleList()
677 : mListStyleType(NS_STYLE_LIST_STYLE_DISC),
678 mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE)
680 MOZ_COUNT_CTOR(nsStyleList);
683 nsStyleList::~nsStyleList()
685 MOZ_COUNT_DTOR(nsStyleList);
688 nsStyleList::nsStyleList(const nsStyleList& aSource)
689 : mListStyleType(aSource.mListStyleType),
690 mListStylePosition(aSource.mListStylePosition),
691 mImageRegion(aSource.mImageRegion)
693 SetListStyleImage(aSource.GetListStyleImage());
694 MOZ_COUNT_CTOR(nsStyleList);
697 nsChangeHint nsStyleList::CalcDifference(const nsStyleList& aOther) const
699 if (mListStylePosition != aOther.mListStylePosition)
700 return NS_STYLE_HINT_FRAMECHANGE;
701 if (EqualImages(mListStyleImage, aOther.mListStyleImage) &&
702 mListStyleType == aOther.mListStyleType) {
703 if (mImageRegion == aOther.mImageRegion)
704 return NS_STYLE_HINT_NONE;
705 if (mImageRegion.width == aOther.mImageRegion.width &&
706 mImageRegion.height == aOther.mImageRegion.height)
707 return NS_STYLE_HINT_VISUAL;
709 return NS_STYLE_HINT_REFLOW;
712 #ifdef DEBUG
713 /* static */
714 nsChangeHint nsStyleList::MaxDifference()
716 return NS_STYLE_HINT_FRAMECHANGE;
718 #endif
720 // --------------------
721 // nsStyleXUL
723 nsStyleXUL::nsStyleXUL()
725 MOZ_COUNT_CTOR(nsStyleXUL);
726 mBoxAlign = NS_STYLE_BOX_ALIGN_STRETCH;
727 mBoxDirection = NS_STYLE_BOX_DIRECTION_NORMAL;
728 mBoxFlex = 0.0f;
729 mBoxOrient = NS_STYLE_BOX_ORIENT_HORIZONTAL;
730 mBoxPack = NS_STYLE_BOX_PACK_START;
731 mBoxOrdinal = 1;
732 mStretchStack = PR_TRUE;
735 nsStyleXUL::~nsStyleXUL()
737 MOZ_COUNT_DTOR(nsStyleXUL);
740 nsStyleXUL::nsStyleXUL(const nsStyleXUL& aSource)
742 MOZ_COUNT_CTOR(nsStyleXUL);
743 memcpy((nsStyleXUL*)this, &aSource, sizeof(nsStyleXUL));
746 nsChangeHint nsStyleXUL::CalcDifference(const nsStyleXUL& aOther) const
748 if (mBoxAlign == aOther.mBoxAlign &&
749 mBoxDirection == aOther.mBoxDirection &&
750 mBoxFlex == aOther.mBoxFlex &&
751 mBoxOrient == aOther.mBoxOrient &&
752 mBoxPack == aOther.mBoxPack &&
753 mBoxOrdinal == aOther.mBoxOrdinal)
754 return NS_STYLE_HINT_NONE;
755 if (mBoxOrdinal != aOther.mBoxOrdinal)
756 return NS_STYLE_HINT_FRAMECHANGE;
757 return NS_STYLE_HINT_REFLOW;
760 #ifdef DEBUG
761 /* static */
762 nsChangeHint nsStyleXUL::MaxDifference()
764 return NS_STYLE_HINT_FRAMECHANGE;
766 #endif
768 // --------------------
769 // nsStyleColumn
771 nsStyleColumn::nsStyleColumn(nsPresContext* aPresContext)
773 MOZ_COUNT_CTOR(nsStyleColumn);
774 mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
775 mColumnWidth.SetAutoValue();
776 mColumnGap.SetNormalValue();
778 mColumnRuleWidth = (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
779 mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
780 mColumnRuleColor = NS_RGB(0, 0, 0);
781 mColumnRuleColorIsForeground = PR_TRUE;
783 mTwipsPerPixel = aPresContext->AppUnitsPerDevPixel();
786 nsStyleColumn::~nsStyleColumn()
788 MOZ_COUNT_DTOR(nsStyleColumn);
791 nsStyleColumn::nsStyleColumn(const nsStyleColumn& aSource)
793 MOZ_COUNT_CTOR(nsStyleColumn);
794 memcpy((nsStyleColumn*)this, &aSource, sizeof(nsStyleColumn));
797 nsChangeHint nsStyleColumn::CalcDifference(const nsStyleColumn& aOther) const
799 if ((mColumnWidth.GetUnit() == eStyleUnit_Auto)
800 != (aOther.mColumnWidth.GetUnit() == eStyleUnit_Auto) ||
801 mColumnCount != aOther.mColumnCount)
802 // We force column count changes to do a reframe, because it's tricky to handle
803 // some edge cases where the column count gets smaller and content overflows.
804 // XXX not ideal
805 return NS_STYLE_HINT_FRAMECHANGE;
807 if (mColumnWidth != aOther.mColumnWidth ||
808 mColumnGap != aOther.mColumnGap)
809 return NS_STYLE_HINT_REFLOW;
811 if (GetComputedColumnRuleWidth() != aOther.GetComputedColumnRuleWidth() ||
812 mColumnRuleStyle != aOther.mColumnRuleStyle ||
813 mColumnRuleColor != aOther.mColumnRuleColor ||
814 mColumnRuleColorIsForeground != aOther.mColumnRuleColorIsForeground)
815 return NS_STYLE_HINT_VISUAL;
817 return NS_STYLE_HINT_NONE;
820 #ifdef DEBUG
821 /* static */
822 nsChangeHint nsStyleColumn::MaxDifference()
824 return NS_STYLE_HINT_FRAMECHANGE;
826 #endif
828 // --------------------
829 // nsStyleSVG
831 nsStyleSVG::nsStyleSVG()
833 MOZ_COUNT_CTOR(nsStyleSVG);
834 mFill.mType = eStyleSVGPaintType_Color;
835 mFill.mPaint.mColor = NS_RGB(0,0,0);
836 mFill.mFallbackColor = NS_RGB(0,0,0);
837 mStroke.mType = eStyleSVGPaintType_None;
838 mStroke.mPaint.mColor = NS_RGB(0,0,0);
839 mStroke.mFallbackColor = NS_RGB(0,0,0);
840 mStrokeDasharray = nsnull;
842 mStrokeDashoffset.SetCoordValue(0);
843 mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
845 mFillOpacity = 1.0f;
846 mStrokeMiterlimit = 4.0f;
847 mStrokeOpacity = 1.0f;
849 mStrokeDasharrayLength = 0;
850 mClipRule = NS_STYLE_FILL_RULE_NONZERO;
851 mColorInterpolation = NS_STYLE_COLOR_INTERPOLATION_SRGB;
852 mColorInterpolationFilters = NS_STYLE_COLOR_INTERPOLATION_LINEARRGB;
853 mFillRule = NS_STYLE_FILL_RULE_NONZERO;
854 mImageRendering = NS_STYLE_IMAGE_RENDERING_AUTO;
855 mShapeRendering = NS_STYLE_SHAPE_RENDERING_AUTO;
856 mStrokeLinecap = NS_STYLE_STROKE_LINECAP_BUTT;
857 mStrokeLinejoin = NS_STYLE_STROKE_LINEJOIN_MITER;
858 mTextAnchor = NS_STYLE_TEXT_ANCHOR_START;
859 mTextRendering = NS_STYLE_TEXT_RENDERING_AUTO;
862 nsStyleSVG::~nsStyleSVG()
864 MOZ_COUNT_DTOR(nsStyleSVG);
865 delete [] mStrokeDasharray;
868 nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
870 MOZ_COUNT_CTOR(nsStyleSVG);
871 mFill = aSource.mFill;
872 mStroke = aSource.mStroke;
874 mMarkerEnd = aSource.mMarkerEnd;
875 mMarkerMid = aSource.mMarkerMid;
876 mMarkerStart = aSource.mMarkerStart;
878 mStrokeDasharrayLength = aSource.mStrokeDasharrayLength;
879 if (aSource.mStrokeDasharray) {
880 mStrokeDasharray = new nsStyleCoord[mStrokeDasharrayLength];
881 if (mStrokeDasharray)
882 memcpy(mStrokeDasharray,
883 aSource.mStrokeDasharray,
884 mStrokeDasharrayLength * sizeof(nsStyleCoord));
885 else
886 mStrokeDasharrayLength = 0;
887 } else {
888 mStrokeDasharray = nsnull;
891 mStrokeDashoffset = aSource.mStrokeDashoffset;
892 mStrokeWidth = aSource.mStrokeWidth;
894 mFillOpacity = aSource.mFillOpacity;
895 mStrokeMiterlimit = aSource.mStrokeMiterlimit;
896 mStrokeOpacity = aSource.mStrokeOpacity;
898 mClipRule = aSource.mClipRule;
899 mColorInterpolation = aSource.mColorInterpolation;
900 mColorInterpolationFilters = aSource.mColorInterpolationFilters;
901 mFillRule = aSource.mFillRule;
902 mImageRendering = aSource.mImageRendering;
903 mShapeRendering = aSource.mShapeRendering;
904 mStrokeLinecap = aSource.mStrokeLinecap;
905 mStrokeLinejoin = aSource.mStrokeLinejoin;
906 mTextAnchor = aSource.mTextAnchor;
907 mTextRendering = aSource.mTextRendering;
910 static PRBool PaintURIChanged(const nsStyleSVGPaint& aPaint1,
911 const nsStyleSVGPaint& aPaint2)
913 if (aPaint1.mType != aPaint2.mType) {
914 return aPaint1.mType == eStyleSVGPaintType_Server ||
915 aPaint2.mType == eStyleSVGPaintType_Server;
917 return aPaint1.mType == eStyleSVGPaintType_Server &&
918 !EqualURIs(aPaint1.mPaint.mPaintServer, aPaint2.mPaint.mPaintServer);
921 nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aOther) const
923 nsChangeHint hint = nsChangeHint(0);
925 if (mTextRendering != aOther.mTextRendering) {
926 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
927 // May be needed for non-svg frames
928 NS_UpdateHint(hint, nsChangeHint_ReflowFrame);
931 if (!EqualURIs(mMarkerEnd, aOther.mMarkerEnd) ||
932 !EqualURIs(mMarkerMid, aOther.mMarkerMid) ||
933 !EqualURIs(mMarkerStart, aOther.mMarkerStart)) {
934 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
935 NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
936 return hint;
939 if (mFill != aOther.mFill ||
940 mStroke != aOther.mStroke) {
941 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
942 if (PaintURIChanged(mFill, aOther.mFill) ||
943 PaintURIChanged(mStroke, aOther.mStroke)) {
944 NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
946 // Nothing more to do, below we can only set "repaint"
947 return hint;
950 if ( mStrokeDashoffset != aOther.mStrokeDashoffset ||
951 mStrokeWidth != aOther.mStrokeWidth ||
953 mFillOpacity != aOther.mFillOpacity ||
954 mStrokeMiterlimit != aOther.mStrokeMiterlimit ||
955 mStrokeOpacity != aOther.mStrokeOpacity ||
957 mClipRule != aOther.mClipRule ||
958 mColorInterpolation != aOther.mColorInterpolation ||
959 mColorInterpolationFilters != aOther.mColorInterpolationFilters ||
960 mFillRule != aOther.mFillRule ||
961 mImageRendering != aOther.mImageRendering ||
962 mShapeRendering != aOther.mShapeRendering ||
963 mStrokeDasharrayLength != aOther.mStrokeDasharrayLength ||
964 mStrokeLinecap != aOther.mStrokeLinecap ||
965 mStrokeLinejoin != aOther.mStrokeLinejoin ||
966 mTextAnchor != aOther.mTextAnchor) {
967 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
968 return hint;
971 // length of stroke dasharrays are the same (tested above) - check entries
972 for (PRUint32 i=0; i<mStrokeDasharrayLength; i++)
973 if (mStrokeDasharray[i] != aOther.mStrokeDasharray[i]) {
974 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
975 return hint;
978 return hint;
981 #ifdef DEBUG
982 /* static */
983 nsChangeHint nsStyleSVG::MaxDifference()
985 return NS_CombineHint(NS_CombineHint(nsChangeHint_UpdateEffects,
986 nsChangeHint_ReflowFrame),
987 nsChangeHint_RepaintFrame);
989 #endif
991 // --------------------
992 // nsStyleSVGReset
994 nsStyleSVGReset::nsStyleSVGReset()
996 MOZ_COUNT_CTOR(nsStyleSVGReset);
997 mStopColor = NS_RGB(0,0,0);
998 mFloodColor = NS_RGB(0,0,0);
999 mLightingColor = NS_RGB(255,255,255);
1000 mClipPath = nsnull;
1001 mFilter = nsnull;
1002 mMask = nsnull;
1003 mStopOpacity = 1.0f;
1004 mFloodOpacity = 1.0f;
1005 mDominantBaseline = NS_STYLE_DOMINANT_BASELINE_AUTO;
1008 nsStyleSVGReset::~nsStyleSVGReset()
1010 MOZ_COUNT_DTOR(nsStyleSVGReset);
1013 nsStyleSVGReset::nsStyleSVGReset(const nsStyleSVGReset& aSource)
1015 MOZ_COUNT_CTOR(nsStyleSVGReset);
1016 mStopColor = aSource.mStopColor;
1017 mFloodColor = aSource.mFloodColor;
1018 mLightingColor = aSource.mLightingColor;
1019 mClipPath = aSource.mClipPath;
1020 mFilter = aSource.mFilter;
1021 mMask = aSource.mMask;
1022 mStopOpacity = aSource.mStopOpacity;
1023 mFloodOpacity = aSource.mFloodOpacity;
1024 mDominantBaseline = aSource.mDominantBaseline;
1027 nsChangeHint nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aOther) const
1029 nsChangeHint hint = nsChangeHint(0);
1031 if (!EqualURIs(mClipPath, aOther.mClipPath) ||
1032 !EqualURIs(mFilter, aOther.mFilter) ||
1033 !EqualURIs(mMask, aOther.mMask)) {
1034 NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
1035 NS_UpdateHint(hint, nsChangeHint_ReflowFrame);
1036 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
1037 } else if (mStopColor != aOther.mStopColor ||
1038 mFloodColor != aOther.mFloodColor ||
1039 mLightingColor != aOther.mLightingColor ||
1040 mStopOpacity != aOther.mStopOpacity ||
1041 mFloodOpacity != aOther.mFloodOpacity ||
1042 mDominantBaseline != aOther.mDominantBaseline)
1043 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
1045 return hint;
1048 #ifdef DEBUG
1049 /* static */
1050 nsChangeHint nsStyleSVGReset::MaxDifference()
1052 return NS_CombineHint(NS_CombineHint(nsChangeHint_UpdateEffects,
1053 nsChangeHint_ReflowFrame),
1054 nsChangeHint_RepaintFrame);
1056 #endif
1058 // nsStyleSVGPaint implementation
1059 nsStyleSVGPaint::~nsStyleSVGPaint()
1061 if (mType == eStyleSVGPaintType_Server) {
1062 NS_IF_RELEASE(mPaint.mPaintServer);
1066 void
1067 nsStyleSVGPaint::SetType(nsStyleSVGPaintType aType)
1069 if (mType == eStyleSVGPaintType_Server) {
1070 this->~nsStyleSVGPaint();
1071 new (this) nsStyleSVGPaint();
1073 mType = aType;
1076 nsStyleSVGPaint& nsStyleSVGPaint::operator=(const nsStyleSVGPaint& aOther)
1078 if (this == &aOther)
1079 return *this;
1081 SetType(aOther.mType);
1083 mFallbackColor = aOther.mFallbackColor;
1084 if (mType == eStyleSVGPaintType_Server) {
1085 mPaint.mPaintServer = aOther.mPaint.mPaintServer;
1086 NS_IF_ADDREF(mPaint.mPaintServer);
1087 } else {
1088 mPaint.mColor = aOther.mPaint.mColor;
1090 return *this;
1093 PRBool nsStyleSVGPaint::operator==(const nsStyleSVGPaint& aOther) const
1095 if (mType != aOther.mType)
1096 return PR_FALSE;
1097 if (mType == eStyleSVGPaintType_Server)
1098 return EqualURIs(mPaint.mPaintServer, aOther.mPaint.mPaintServer) &&
1099 mFallbackColor == aOther.mFallbackColor;
1100 if (mType == eStyleSVGPaintType_None)
1101 return PR_TRUE;
1102 return mPaint.mColor == aOther.mPaint.mColor;
1106 // --------------------
1107 // nsStylePosition
1109 nsStylePosition::nsStylePosition(void)
1111 MOZ_COUNT_CTOR(nsStylePosition);
1112 // positioning values not inherited
1113 nsStyleCoord autoCoord(eStyleUnit_Auto);
1114 mOffset.SetLeft(autoCoord);
1115 mOffset.SetTop(autoCoord);
1116 mOffset.SetRight(autoCoord);
1117 mOffset.SetBottom(autoCoord);
1118 mWidth.SetAutoValue();
1119 mMinWidth.SetCoordValue(0);
1120 mMaxWidth.SetNoneValue();
1121 mHeight.SetAutoValue();
1122 mMinHeight.SetCoordValue(0);
1123 mMaxHeight.SetNoneValue();
1124 mBoxSizing = NS_STYLE_BOX_SIZING_CONTENT;
1125 mZIndex.SetAutoValue();
1128 nsStylePosition::~nsStylePosition(void)
1130 MOZ_COUNT_DTOR(nsStylePosition);
1133 nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
1135 MOZ_COUNT_CTOR(nsStylePosition);
1136 memcpy((nsStylePosition*)this, &aSource, sizeof(nsStylePosition));
1139 nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) const
1141 nsChangeHint hint =
1142 (mZIndex == aOther.mZIndex) ? NS_STYLE_HINT_NONE : nsChangeHint_RepaintFrame;
1144 if (mBoxSizing != aOther.mBoxSizing) {
1145 // Can affect both widths and heights; just a bad scene.
1146 return NS_CombineHint(hint, nsChangeHint_ReflowFrame);
1149 if (mHeight != aOther.mHeight ||
1150 mMinHeight != aOther.mMinHeight ||
1151 mMaxHeight != aOther.mMaxHeight) {
1152 // Height changes can affect descendant intrinsic sizes due to replaced
1153 // elements with percentage heights in descendants which also have
1154 // percentage heights. And due to our not-so-great computation of mVResize
1155 // in nsHTMLReflowState, they do need to force reflow of the whole subtree.
1156 // XXXbz due to XUL caching heights as well, height changes also need to
1157 // clear ancestor intrinsics!
1158 return NS_CombineHint(hint, nsChangeHint_ReflowFrame);
1161 if ((mWidth == aOther.mWidth) &&
1162 (mMinWidth == aOther.mMinWidth) &&
1163 (mMaxWidth == aOther.mMaxWidth)) {
1164 if (mOffset == aOther.mOffset) {
1165 return hint;
1166 } else {
1167 // Offset changes only affect positioned content, and can't affect any
1168 // intrinsic widths. They also don't need to force reflow of
1169 // descendants.
1170 return NS_CombineHint(hint, nsChangeHint_NeedReflow);
1174 // None of our width differences can affect descendant intrinsic
1175 // sizes and none of them need to force children to reflow.
1176 return
1177 NS_CombineHint(hint,
1178 NS_SubtractHint(nsChangeHint_ReflowFrame,
1179 NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
1180 nsChangeHint_NeedDirtyReflow)));
1183 #ifdef DEBUG
1184 /* static */
1185 nsChangeHint nsStylePosition::MaxDifference()
1187 return NS_STYLE_HINT_REFLOW;
1189 #endif
1191 /* static */ PRBool
1192 nsStylePosition::WidthCoordDependsOnContainer(const nsStyleCoord &aCoord)
1194 return aCoord.GetUnit() == eStyleUnit_Auto ||
1195 aCoord.HasPercent() ||
1196 (aCoord.GetUnit() == eStyleUnit_Enumerated &&
1197 (aCoord.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT ||
1198 aCoord.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE));
1201 // --------------------
1202 // nsStyleTable
1205 nsStyleTable::nsStyleTable()
1207 MOZ_COUNT_CTOR(nsStyleTable);
1208 // values not inherited
1209 mLayoutStrategy = NS_STYLE_TABLE_LAYOUT_AUTO;
1210 mCols = NS_STYLE_TABLE_COLS_NONE;
1211 mFrame = NS_STYLE_TABLE_FRAME_NONE;
1212 mRules = NS_STYLE_TABLE_RULES_NONE;
1213 mSpan = 1;
1216 nsStyleTable::~nsStyleTable(void)
1218 MOZ_COUNT_DTOR(nsStyleTable);
1221 nsStyleTable::nsStyleTable(const nsStyleTable& aSource)
1223 MOZ_COUNT_CTOR(nsStyleTable);
1224 memcpy((nsStyleTable*)this, &aSource, sizeof(nsStyleTable));
1227 nsChangeHint nsStyleTable::CalcDifference(const nsStyleTable& aOther) const
1229 // Changes in mRules may require reframing (if border-collapse stuff changes, for example).
1230 if (mRules != aOther.mRules || mSpan != aOther.mSpan ||
1231 mLayoutStrategy != aOther.mLayoutStrategy)
1232 return NS_STYLE_HINT_FRAMECHANGE;
1233 if (mFrame != aOther.mFrame || mCols != aOther.mCols)
1234 return NS_STYLE_HINT_REFLOW;
1235 return NS_STYLE_HINT_NONE;
1238 #ifdef DEBUG
1239 /* static */
1240 nsChangeHint nsStyleTable::MaxDifference()
1242 return NS_STYLE_HINT_FRAMECHANGE;
1244 #endif
1246 // -----------------------
1247 // nsStyleTableBorder
1249 nsStyleTableBorder::nsStyleTableBorder(nsPresContext* aPresContext)
1251 MOZ_COUNT_CTOR(nsStyleTableBorder);
1252 mBorderCollapse = NS_STYLE_BORDER_SEPARATE;
1254 nsCompatibility compatMode = eCompatibility_FullStandards;
1255 if (aPresContext)
1256 compatMode = aPresContext->CompatibilityMode();
1257 mEmptyCells = (compatMode == eCompatibility_NavQuirks)
1258 ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
1259 : NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
1260 mCaptionSide = NS_STYLE_CAPTION_SIDE_TOP;
1261 mBorderSpacingX = 0;
1262 mBorderSpacingY = 0;
1265 nsStyleTableBorder::~nsStyleTableBorder(void)
1267 MOZ_COUNT_DTOR(nsStyleTableBorder);
1270 nsStyleTableBorder::nsStyleTableBorder(const nsStyleTableBorder& aSource)
1272 MOZ_COUNT_CTOR(nsStyleTableBorder);
1273 memcpy((nsStyleTableBorder*)this, &aSource, sizeof(nsStyleTableBorder));
1276 nsChangeHint nsStyleTableBorder::CalcDifference(const nsStyleTableBorder& aOther) const
1278 // Border-collapse changes need a reframe, because we use a different frame
1279 // class for table cells in the collapsed border model. This is used to
1280 // conserve memory when using the separated border model (collapsed borders
1281 // require extra state to be stored).
1282 if (mBorderCollapse != aOther.mBorderCollapse) {
1283 return NS_STYLE_HINT_FRAMECHANGE;
1286 if ((mCaptionSide == aOther.mCaptionSide) &&
1287 (mBorderSpacingX == aOther.mBorderSpacingX) &&
1288 (mBorderSpacingY == aOther.mBorderSpacingY)) {
1289 if (mEmptyCells == aOther.mEmptyCells)
1290 return NS_STYLE_HINT_NONE;
1291 return NS_STYLE_HINT_VISUAL;
1293 else
1294 return NS_STYLE_HINT_REFLOW;
1297 #ifdef DEBUG
1298 /* static */
1299 nsChangeHint nsStyleTableBorder::MaxDifference()
1301 return NS_STYLE_HINT_FRAMECHANGE;
1303 #endif
1305 // --------------------
1306 // nsStyleColor
1309 nsStyleColor::nsStyleColor(nsPresContext* aPresContext)
1311 MOZ_COUNT_CTOR(nsStyleColor);
1312 mColor = aPresContext->DefaultColor();
1315 nsStyleColor::nsStyleColor(const nsStyleColor& aSource)
1317 MOZ_COUNT_CTOR(nsStyleColor);
1318 mColor = aSource.mColor;
1321 nsChangeHint nsStyleColor::CalcDifference(const nsStyleColor& aOther) const
1323 if (mColor == aOther.mColor)
1324 return NS_STYLE_HINT_NONE;
1325 return NS_STYLE_HINT_VISUAL;
1328 #ifdef DEBUG
1329 /* static */
1330 nsChangeHint nsStyleColor::MaxDifference()
1332 return NS_STYLE_HINT_VISUAL;
1334 #endif
1336 // --------------------
1337 // nsStyleGradient
1339 PRBool
1340 nsStyleGradient::operator==(const nsStyleGradient& aOther) const
1342 NS_ABORT_IF_FALSE(mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER ||
1343 mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR,
1344 "incorrect combination of shape and size");
1345 NS_ABORT_IF_FALSE(aOther.mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER ||
1346 aOther.mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR,
1347 "incorrect combination of shape and size");
1349 if (mShape != aOther.mShape ||
1350 mSize != aOther.mSize ||
1351 mRepeating != aOther.mRepeating ||
1352 mBgPosX != aOther.mBgPosX ||
1353 mBgPosY != aOther.mBgPosY ||
1354 mAngle != aOther.mAngle)
1355 return PR_FALSE;
1357 if (mStops.Length() != aOther.mStops.Length())
1358 return PR_FALSE;
1360 for (PRUint32 i = 0; i < mStops.Length(); i++) {
1361 if (mStops[i].mLocation != aOther.mStops[i].mLocation ||
1362 mStops[i].mColor != aOther.mStops[i].mColor)
1363 return PR_FALSE;
1366 return PR_TRUE;
1369 nsStyleGradient::nsStyleGradient(void)
1370 : mShape(NS_STYLE_GRADIENT_SHAPE_LINEAR)
1371 , mSize(NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)
1372 , mRepeating(PR_FALSE)
1376 PRBool
1377 nsStyleGradient::IsOpaque()
1379 for (PRUint32 i = 0; i < mStops.Length(); i++) {
1380 if (NS_GET_A(mStops[i].mColor) < 255)
1381 return PR_FALSE;
1383 return PR_TRUE;
1386 // --------------------
1387 // nsStyleImage
1390 nsStyleImage::nsStyleImage()
1391 : mType(eStyleImageType_Null)
1392 , mCropRect(nsnull)
1393 #ifdef DEBUG
1394 , mImageTracked(false)
1395 #endif
1397 MOZ_COUNT_CTOR(nsStyleImage);
1400 nsStyleImage::~nsStyleImage()
1402 MOZ_COUNT_DTOR(nsStyleImage);
1403 if (mType != eStyleImageType_Null)
1404 SetNull();
1407 nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
1408 : mType(eStyleImageType_Null)
1409 , mCropRect(nsnull)
1410 #ifdef DEBUG
1411 , mImageTracked(false)
1412 #endif
1414 // We need our own copy constructor because we don't want
1415 // to copy the reference count
1416 MOZ_COUNT_CTOR(nsStyleImage);
1417 DoCopy(aOther);
1420 nsStyleImage&
1421 nsStyleImage::operator=(const nsStyleImage& aOther)
1423 if (this != &aOther)
1424 DoCopy(aOther);
1426 return *this;
1429 void
1430 nsStyleImage::DoCopy(const nsStyleImage& aOther)
1432 SetNull();
1434 if (aOther.mType == eStyleImageType_Image)
1435 SetImageData(aOther.mImage);
1436 else if (aOther.mType == eStyleImageType_Gradient)
1437 SetGradientData(aOther.mGradient);
1438 else if (aOther.mType == eStyleImageType_Element)
1439 SetElementId(aOther.mElementId);
1441 SetCropRect(aOther.mCropRect);
1444 void
1445 nsStyleImage::SetNull()
1447 NS_ABORT_IF_FALSE(!mImageTracked,
1448 "Calling SetNull() with image tracked!");
1450 if (mType == eStyleImageType_Gradient)
1451 mGradient->Release();
1452 else if (mType == eStyleImageType_Image)
1453 NS_RELEASE(mImage);
1454 else if (mType == eStyleImageType_Element)
1455 nsCRT::free(mElementId);
1457 mType = eStyleImageType_Null;
1458 mCropRect = nsnull;
1461 void
1462 nsStyleImage::SetImageData(imgIRequest* aImage)
1464 NS_ABORT_IF_FALSE(!mImageTracked,
1465 "Setting a new image without untracking the old one!");
1467 NS_IF_ADDREF(aImage);
1469 if (mType != eStyleImageType_Null)
1470 SetNull();
1472 if (aImage) {
1473 mImage = aImage;
1474 mType = eStyleImageType_Image;
1478 void
1479 nsStyleImage::TrackImage(nsPresContext* aContext)
1481 // Sanity
1482 NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!");
1483 NS_ABORT_IF_FALSE(mType == eStyleImageType_Image,
1484 "Can't track image when there isn't one!");
1486 // Register the image with the document
1487 nsIDocument* doc = aContext->Document();
1488 if (doc)
1489 doc->AddImage(mImage);
1491 // Mark state
1492 #ifdef DEBUG
1493 mImageTracked = true;
1494 #endif
1497 void
1498 nsStyleImage::UntrackImage(nsPresContext* aContext)
1500 // Sanity
1501 NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!");
1502 NS_ABORT_IF_FALSE(mType == eStyleImageType_Image,
1503 "Can't untrack image when there isn't one!");
1505 // Unregister the image with the document
1506 nsIDocument* doc = aContext->Document();
1507 if (doc)
1508 doc->RemoveImage(mImage);
1510 // Mark state
1511 #ifdef DEBUG
1512 mImageTracked = false;
1513 #endif
1516 void
1517 nsStyleImage::SetGradientData(nsStyleGradient* aGradient)
1519 if (aGradient)
1520 aGradient->AddRef();
1522 if (mType != eStyleImageType_Null)
1523 SetNull();
1525 if (aGradient) {
1526 mGradient = aGradient;
1527 mType = eStyleImageType_Gradient;
1531 void
1532 nsStyleImage::SetElementId(const PRUnichar* aElementId)
1534 if (mType != eStyleImageType_Null)
1535 SetNull();
1537 if (aElementId) {
1538 mElementId = nsCRT::strdup(aElementId);
1539 mType = eStyleImageType_Element;
1543 void
1544 nsStyleImage::SetCropRect(nsStyleSides* aCropRect)
1546 if (aCropRect) {
1547 mCropRect = new nsStyleSides(*aCropRect);
1548 // There is really not much we can do if 'new' fails
1549 } else {
1550 mCropRect = nsnull;
1554 static PRInt32
1555 ConvertToPixelCoord(const nsStyleCoord& aCoord, PRInt32 aPercentScale)
1557 double pixelValue;
1558 switch (aCoord.GetUnit()) {
1559 case eStyleUnit_Percent:
1560 pixelValue = aCoord.GetPercentValue() * aPercentScale;
1561 break;
1562 case eStyleUnit_Factor:
1563 pixelValue = aCoord.GetFactorValue();
1564 break;
1565 default:
1566 NS_NOTREACHED("unexpected unit for image crop rect");
1567 return 0;
1569 NS_ABORT_IF_FALSE(pixelValue >= 0, "we ensured non-negative while parsing");
1570 pixelValue = NS_MIN(pixelValue, double(PR_INT32_MAX)); // avoid overflow
1571 return NS_lround(pixelValue);
1574 PRBool
1575 nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
1576 PRBool* aIsEntireImage) const
1578 if (mType != eStyleImageType_Image)
1579 return PR_FALSE;
1581 nsCOMPtr<imgIContainer> imageContainer;
1582 mImage->GetImage(getter_AddRefs(imageContainer));
1583 if (!imageContainer)
1584 return PR_FALSE;
1586 nsIntSize imageSize;
1587 imageContainer->GetWidth(&imageSize.width);
1588 imageContainer->GetHeight(&imageSize.height);
1589 if (imageSize.width <= 0 || imageSize.height <= 0)
1590 return PR_FALSE;
1592 PRInt32 left = ConvertToPixelCoord(mCropRect->GetLeft(), imageSize.width);
1593 PRInt32 top = ConvertToPixelCoord(mCropRect->GetTop(), imageSize.height);
1594 PRInt32 right = ConvertToPixelCoord(mCropRect->GetRight(), imageSize.width);
1595 PRInt32 bottom = ConvertToPixelCoord(mCropRect->GetBottom(), imageSize.height);
1597 // IntersectRect() returns an empty rect if we get negative width or height
1598 nsIntRect cropRect(left, top, right - left, bottom - top);
1599 nsIntRect imageRect(nsIntPoint(0, 0), imageSize);
1600 aActualCropRect.IntersectRect(imageRect, cropRect);
1602 if (aIsEntireImage)
1603 *aIsEntireImage = (aActualCropRect == imageRect);
1604 return PR_TRUE;
1607 nsresult
1608 nsStyleImage::RequestDecode() const
1610 if ((mType == eStyleImageType_Image) && mImage)
1611 return mImage->RequestDecode();
1612 return NS_OK;
1615 PRBool
1616 nsStyleImage::IsOpaque() const
1618 if (!IsComplete())
1619 return PR_FALSE;
1621 if (mType == eStyleImageType_Gradient)
1622 return mGradient->IsOpaque();
1624 if (mType == eStyleImageType_Element)
1625 return PR_FALSE;
1627 NS_ABORT_IF_FALSE(mType == eStyleImageType_Image, "unexpected image type");
1629 nsCOMPtr<imgIContainer> imageContainer;
1630 mImage->GetImage(getter_AddRefs(imageContainer));
1631 NS_ABORT_IF_FALSE(imageContainer, "IsComplete() said image container is ready");
1633 // Check if the crop region of the current image frame is opaque
1634 PRBool isOpaque;
1635 if (NS_SUCCEEDED(imageContainer->GetCurrentFrameIsOpaque(&isOpaque)) &&
1636 isOpaque) {
1637 if (!mCropRect)
1638 return PR_TRUE;
1640 // Must make sure if mCropRect contains at least a pixel.
1641 // XXX Is this optimization worth it? Maybe I should just return PR_FALSE.
1642 nsIntRect actualCropRect;
1643 PRBool rv = ComputeActualCropRect(actualCropRect);
1644 NS_ASSERTION(rv, "ComputeActualCropRect() can not fail here");
1645 return rv && !actualCropRect.IsEmpty();
1648 return PR_FALSE;
1651 PRBool
1652 nsStyleImage::IsComplete() const
1654 switch (mType) {
1655 case eStyleImageType_Null:
1656 return PR_FALSE;
1657 case eStyleImageType_Gradient:
1658 case eStyleImageType_Element:
1659 return PR_TRUE;
1660 case eStyleImageType_Image:
1662 PRUint32 status = imgIRequest::STATUS_ERROR;
1663 return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
1664 (status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
1665 (status & imgIRequest::STATUS_FRAME_COMPLETE);
1667 default:
1668 NS_NOTREACHED("unexpected image type");
1669 return PR_FALSE;
1673 static inline PRBool
1674 EqualRects(const nsStyleSides* aRect1, const nsStyleSides* aRect2)
1676 return aRect1 == aRect2 || /* handles null== null, and optimize */
1677 (aRect1 && aRect2 && *aRect1 == *aRect2);
1680 PRBool
1681 nsStyleImage::operator==(const nsStyleImage& aOther) const
1683 if (mType != aOther.mType)
1684 return PR_FALSE;
1686 if (!EqualRects(mCropRect, aOther.mCropRect))
1687 return PR_FALSE;
1689 if (mType == eStyleImageType_Image)
1690 return EqualImages(mImage, aOther.mImage);
1692 if (mType == eStyleImageType_Gradient)
1693 return *mGradient == *aOther.mGradient;
1695 if (mType == eStyleImageType_Element)
1696 return nsCRT::strcmp(mElementId, aOther.mElementId) == 0;
1698 return PR_TRUE;
1701 // --------------------
1702 // nsStyleBackground
1705 nsStyleBackground::nsStyleBackground()
1706 : mAttachmentCount(1)
1707 , mClipCount(1)
1708 , mOriginCount(1)
1709 , mRepeatCount(1)
1710 , mPositionCount(1)
1711 , mImageCount(1)
1712 , mSizeCount(1)
1713 , mBackgroundColor(NS_RGBA(0, 0, 0, 0))
1714 , mBackgroundInlinePolicy(NS_STYLE_BG_INLINE_POLICY_CONTINUOUS)
1716 MOZ_COUNT_CTOR(nsStyleBackground);
1717 Layer *onlyLayer = mLayers.AppendElement();
1718 NS_ASSERTION(onlyLayer, "auto array must have room for 1 element");
1719 onlyLayer->SetInitialValues();
1722 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
1723 : mAttachmentCount(aSource.mAttachmentCount)
1724 , mClipCount(aSource.mClipCount)
1725 , mOriginCount(aSource.mOriginCount)
1726 , mRepeatCount(aSource.mRepeatCount)
1727 , mPositionCount(aSource.mPositionCount)
1728 , mImageCount(aSource.mImageCount)
1729 , mSizeCount(aSource.mSizeCount)
1730 , mLayers(aSource.mLayers) // deep copy
1731 , mBackgroundColor(aSource.mBackgroundColor)
1732 , mBackgroundInlinePolicy(aSource.mBackgroundInlinePolicy)
1734 MOZ_COUNT_CTOR(nsStyleBackground);
1735 // If the deep copy of mLayers failed, truncate the counts.
1736 PRUint32 count = mLayers.Length();
1737 if (count != aSource.mLayers.Length()) {
1738 NS_WARNING("truncating counts due to out-of-memory");
1739 mAttachmentCount = NS_MAX(mAttachmentCount, count);
1740 mClipCount = NS_MAX(mClipCount, count);
1741 mOriginCount = NS_MAX(mOriginCount, count);
1742 mRepeatCount = NS_MAX(mRepeatCount, count);
1743 mPositionCount = NS_MAX(mPositionCount, count);
1744 mImageCount = NS_MAX(mImageCount, count);
1745 mSizeCount = NS_MAX(mSizeCount, count);
1749 nsStyleBackground::~nsStyleBackground()
1751 MOZ_COUNT_DTOR(nsStyleBackground);
1754 void
1755 nsStyleBackground::Destroy(nsPresContext* aContext)
1757 // Untrack all the images stored in our layers
1758 for (PRUint32 i = 0; i < mImageCount; ++i)
1759 mLayers[i].UntrackImages(aContext);
1761 this->~nsStyleBackground();
1762 aContext->FreeToShell(sizeof(nsStyleBackground), this);
1765 nsChangeHint nsStyleBackground::CalcDifference(const nsStyleBackground& aOther) const
1767 const nsStyleBackground* moreLayers =
1768 mImageCount > aOther.mImageCount ? this : &aOther;
1769 const nsStyleBackground* lessLayers =
1770 mImageCount > aOther.mImageCount ? &aOther : this;
1772 bool hasVisualDifference = false;
1774 NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, moreLayers) {
1775 if (i < lessLayers->mImageCount) {
1776 if (moreLayers->mLayers[i] != lessLayers->mLayers[i]) {
1777 if ((moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) ||
1778 (lessLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element))
1779 return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
1780 hasVisualDifference = true;
1782 } else {
1783 if (moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element)
1784 return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
1785 hasVisualDifference = true;
1789 if (hasVisualDifference ||
1790 mBackgroundColor != aOther.mBackgroundColor ||
1791 mBackgroundInlinePolicy != aOther.mBackgroundInlinePolicy)
1792 return NS_STYLE_HINT_VISUAL;
1794 return NS_STYLE_HINT_NONE;
1797 #ifdef DEBUG
1798 /* static */
1799 nsChangeHint nsStyleBackground::MaxDifference()
1801 return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
1803 #endif
1805 PRBool nsStyleBackground::HasFixedBackground() const
1807 NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, this) {
1808 const Layer &layer = mLayers[i];
1809 if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
1810 !layer.mImage.IsEmpty()) {
1811 return PR_TRUE;
1814 return PR_FALSE;
1817 PRBool nsStyleBackground::IsTransparent() const
1819 return BottomLayer().mImage.IsEmpty() &&
1820 mImageCount == 1 &&
1821 NS_GET_A(mBackgroundColor) == 0;
1824 void
1825 nsStyleBackground::Position::SetInitialValues()
1827 mXPosition.mPercent = 0.0f;
1828 mXPosition.mLength = 0;
1829 mYPosition.mPercent = 0.0f;
1830 mYPosition.mLength = 0;
1833 void
1834 nsStyleBackground::Size::SetInitialValues()
1836 mWidthType = mHeightType = eAuto;
1839 bool
1840 nsStyleBackground::Size::operator==(const Size& aOther) const
1842 NS_ABORT_IF_FALSE(mWidthType < eDimensionType_COUNT,
1843 "bad mWidthType for this");
1844 NS_ABORT_IF_FALSE(mHeightType < eDimensionType_COUNT,
1845 "bad mHeightType for this");
1846 NS_ABORT_IF_FALSE(aOther.mWidthType < eDimensionType_COUNT,
1847 "bad mWidthType for aOther");
1848 NS_ABORT_IF_FALSE(aOther.mHeightType < eDimensionType_COUNT,
1849 "bad mHeightType for aOther");
1851 return mWidthType == aOther.mWidthType &&
1852 mHeightType == aOther.mHeightType &&
1853 (mWidthType != eLengthPercentage || mWidth == aOther.mWidth) &&
1854 (mHeightType != eLengthPercentage || mHeight == aOther.mHeight);
1857 nsStyleBackground::Layer::Layer()
1861 nsStyleBackground::Layer::~Layer()
1865 void
1866 nsStyleBackground::Layer::SetInitialValues()
1868 mAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL;
1869 mClip = NS_STYLE_BG_CLIP_BORDER;
1870 mOrigin = NS_STYLE_BG_ORIGIN_PADDING;
1871 mRepeat = NS_STYLE_BG_REPEAT_XY;
1872 mPosition.SetInitialValues();
1873 mSize.SetInitialValues();
1874 mImage.SetNull();
1877 PRBool
1878 nsStyleBackground::Layer::RenderingMightDependOnFrameSize() const
1880 // Do we even have an image?
1881 if (mImage.IsEmpty()) {
1882 return PR_FALSE;
1885 // Does our position or size depend on frame size?
1886 if (mPosition.DependsOnFrameSize() ||
1887 mSize.DependsOnFrameSize(mImage.GetType())) {
1888 return PR_TRUE;
1891 // Are we an SVG image with a viewBox attribute?
1892 if (mImage.GetType() == eStyleImageType_Image) {
1893 nsCOMPtr<imgIContainer> imageContainer;
1894 mImage.GetImageData()->GetImage(getter_AddRefs(imageContainer));
1895 if (imageContainer &&
1896 imageContainer->GetType() == imgIContainer::TYPE_VECTOR) {
1897 nsIFrame* rootFrame = imageContainer->GetRootLayoutFrame();
1898 if (rootFrame &&
1899 nsSVGUtils::RootSVGElementHasViewbox(rootFrame->GetContent())) {
1900 return PR_TRUE;
1905 return PR_FALSE;
1908 PRBool
1909 nsStyleBackground::Layer::operator==(const Layer& aOther) const
1911 return mAttachment == aOther.mAttachment &&
1912 mClip == aOther.mClip &&
1913 mOrigin == aOther.mOrigin &&
1914 mRepeat == aOther.mRepeat &&
1915 mPosition == aOther.mPosition &&
1916 mSize == aOther.mSize &&
1917 mImage == aOther.mImage;
1920 // --------------------
1921 // nsStyleDisplay
1923 void nsTimingFunction::AssignFromKeyword(PRInt32 aTimingFunctionType)
1925 PR_STATIC_ASSERT(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE == 0);
1926 PR_STATIC_ASSERT(NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR == 1);
1927 PR_STATIC_ASSERT(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN == 2);
1928 PR_STATIC_ASSERT(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT == 3);
1929 PR_STATIC_ASSERT(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT == 4);
1931 static const float timingFunctionValues[5][4] = {
1932 { 0.25, 0.10, 0.25, 1.00 }, // ease
1933 { 0.00, 0.00, 1.00, 1.00 }, // linear
1934 { 0.42, 0.00, 1.00, 1.00 }, // ease-in
1935 { 0.00, 0.00, 0.58, 1.00 }, // ease-out
1936 { 0.42, 0.00, 0.58, 1.00 } // ease-in-out
1939 NS_ABORT_IF_FALSE(0 <= aTimingFunctionType && aTimingFunctionType < 5,
1940 "keyword out of range");
1941 mX1 = timingFunctionValues[aTimingFunctionType][0];
1942 mY1 = timingFunctionValues[aTimingFunctionType][1];
1943 mX2 = timingFunctionValues[aTimingFunctionType][2];
1944 mY2 = timingFunctionValues[aTimingFunctionType][3];
1947 nsTransition::nsTransition(const nsTransition& aCopy)
1948 : mTimingFunction(aCopy.mTimingFunction)
1949 , mDuration(aCopy.mDuration)
1950 , mDelay(aCopy.mDelay)
1951 , mProperty(aCopy.mProperty)
1952 , mUnknownProperty(aCopy.mUnknownProperty)
1956 void nsTransition::SetInitialValues()
1958 mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
1959 mDuration = 0.0;
1960 mDelay = 0.0;
1961 mProperty = eCSSPropertyExtra_all_properties;
1964 void nsTransition::SetUnknownProperty(const nsAString& aUnknownProperty)
1966 NS_ASSERTION(nsCSSProps::LookupProperty(aUnknownProperty) ==
1967 eCSSProperty_UNKNOWN,
1968 "should be unknown property");
1969 mProperty = eCSSProperty_UNKNOWN;
1970 mUnknownProperty = do_GetAtom(aUnknownProperty);
1973 nsStyleDisplay::nsStyleDisplay()
1975 MOZ_COUNT_CTOR(nsStyleDisplay);
1976 mAppearance = NS_THEME_NONE;
1977 mDisplay = NS_STYLE_DISPLAY_INLINE;
1978 mOriginalDisplay = NS_STYLE_DISPLAY_NONE;
1979 mPosition = NS_STYLE_POSITION_STATIC;
1980 mFloats = NS_STYLE_FLOAT_NONE;
1981 mBreakType = NS_STYLE_CLEAR_NONE;
1982 mBreakBefore = PR_FALSE;
1983 mBreakAfter = PR_FALSE;
1984 mOverflowX = NS_STYLE_OVERFLOW_VISIBLE;
1985 mOverflowY = NS_STYLE_OVERFLOW_VISIBLE;
1986 mResize = NS_STYLE_RESIZE_NONE;
1987 mClipFlags = NS_STYLE_CLIP_AUTO;
1988 mClip.SetRect(0,0,0,0);
1989 mOpacity = 1.0f;
1990 mSpecifiedTransform = nsnull;
1991 mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin
1992 mTransformOrigin[1].SetPercentValue(0.5f);
1993 mTransitions.AppendElement();
1994 NS_ABORT_IF_FALSE(mTransitions.Length() == 1,
1995 "appending within auto buffer should never fail");
1996 mTransitions[0].SetInitialValues();
1997 mTransitionTimingFunctionCount = 1;
1998 mTransitionDurationCount = 1;
1999 mTransitionDelayCount = 1;
2000 mTransitionPropertyCount = 1;
2003 nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
2004 : mTransitions(aSource.mTransitions)
2005 , mTransitionTimingFunctionCount(aSource.mTransitionTimingFunctionCount)
2006 , mTransitionDurationCount(aSource.mTransitionDurationCount)
2007 , mTransitionDelayCount(aSource.mTransitionDelayCount)
2008 , mTransitionPropertyCount(aSource.mTransitionPropertyCount)
2010 MOZ_COUNT_CTOR(nsStyleDisplay);
2011 mAppearance = aSource.mAppearance;
2012 mDisplay = aSource.mDisplay;
2013 mOriginalDisplay = aSource.mOriginalDisplay;
2014 mBinding = aSource.mBinding;
2015 mPosition = aSource.mPosition;
2016 mFloats = aSource.mFloats;
2017 mBreakType = aSource.mBreakType;
2018 mBreakBefore = aSource.mBreakBefore;
2019 mBreakAfter = aSource.mBreakAfter;
2020 mOverflowX = aSource.mOverflowX;
2021 mOverflowY = aSource.mOverflowY;
2022 mResize = aSource.mResize;
2023 mClipFlags = aSource.mClipFlags;
2024 mClip = aSource.mClip;
2025 mOpacity = aSource.mOpacity;
2027 /* Copy over the transformation information. */
2028 mSpecifiedTransform = aSource.mSpecifiedTransform;
2029 if (mSpecifiedTransform)
2030 mTransform = aSource.mTransform;
2032 /* Copy over transform origin. */
2033 mTransformOrigin[0] = aSource.mTransformOrigin[0];
2034 mTransformOrigin[1] = aSource.mTransformOrigin[1];
2037 nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
2039 nsChangeHint hint = nsChangeHint(0);
2041 if (!EqualURIs(mBinding, aOther.mBinding)
2042 || mPosition != aOther.mPosition
2043 || mDisplay != aOther.mDisplay
2044 || (mFloats == NS_STYLE_FLOAT_NONE) != (aOther.mFloats == NS_STYLE_FLOAT_NONE)
2045 || mOverflowX != aOther.mOverflowX
2046 || mOverflowY != aOther.mOverflowY
2047 || mResize != aOther.mResize)
2048 NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
2050 if (mFloats != aOther.mFloats) {
2051 // Changing which side we float on doesn't affect descendants directly
2052 NS_UpdateHint(hint,
2053 NS_SubtractHint(nsChangeHint_ReflowFrame,
2054 NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
2055 nsChangeHint_NeedDirtyReflow)));
2058 // XXX the following is conservative, for now: changing float breaking shouldn't
2059 // necessarily require a repaint, reflow should suffice.
2060 if (mBreakType != aOther.mBreakType
2061 || mBreakBefore != aOther.mBreakBefore
2062 || mBreakAfter != aOther.mBreakAfter
2063 || mAppearance != aOther.mAppearance
2064 || mClipFlags != aOther.mClipFlags || mClip != aOther.mClip)
2065 NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame, nsChangeHint_RepaintFrame));
2067 if (mOpacity != aOther.mOpacity) {
2068 NS_UpdateHint(hint, nsChangeHint_UpdateOpacityLayer);
2071 /* If we've added or removed the transform property, we need to reconstruct the frame to add
2072 * or remove the view object, and also to handle abs-pos and fixed-pos containers.
2074 if (HasTransform() != aOther.HasTransform()) {
2075 NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
2077 else if (HasTransform()) {
2078 /* Otherwise, if we've kept the property lying around and we already had a
2079 * transform, we need to see whether or not we've changed the transform.
2080 * If so, we need to do a reflow and a repaint. The reflow is to recompute
2081 * the overflow rect (which probably changed if the transform changed)
2082 * and to redraw within the bounds of that new overflow rect.
2084 if (mTransform != aOther.mTransform)
2085 NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame,
2086 nsChangeHint_UpdateTransformLayer));
2088 for (PRUint8 index = 0; index < 2; ++index)
2089 if (mTransformOrigin[index] != aOther.mTransformOrigin[index]) {
2090 NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame,
2091 nsChangeHint_RepaintFrame));
2092 break;
2096 // Note: Our current behavior for handling changes to the
2097 // transition-duration, transition-delay, and transition-timing-function
2098 // properties is to do nothing. In other words, the transition
2099 // property that matters is what it is when the transition begins, and
2100 // we don't stop a transition later because the transition property
2101 // changed.
2102 // We do handle changes to transition-property, but we don't need to
2103 // bother with anything here, since the transition manager is notified
2104 // of any style context change anyway.
2106 return hint;
2109 #ifdef DEBUG
2110 /* static */
2111 nsChangeHint nsStyleDisplay::MaxDifference()
2113 // All the parts of FRAMECHANGE are present above in CalcDifference.
2114 return nsChangeHint(NS_STYLE_HINT_FRAMECHANGE | nsChangeHint_UpdateOpacityLayer |
2115 nsChangeHint_UpdateTransformLayer);
2117 #endif
2119 // --------------------
2120 // nsStyleVisibility
2123 nsStyleVisibility::nsStyleVisibility(nsPresContext* aPresContext)
2125 MOZ_COUNT_CTOR(nsStyleVisibility);
2126 PRUint32 bidiOptions = aPresContext->GetBidi();
2127 if (GET_BIDI_OPTION_DIRECTION(bidiOptions) == IBMBIDI_TEXTDIRECTION_RTL)
2128 mDirection = NS_STYLE_DIRECTION_RTL;
2129 else
2130 mDirection = NS_STYLE_DIRECTION_LTR;
2132 nsAutoString language;
2133 aPresContext->Document()->GetContentLanguage(language);
2134 language.StripWhitespace();
2136 // Content-Language may be a comma-separated list of language codes,
2137 // in which case the HTML5 spec says to treat it as unknown
2138 if (!language.IsEmpty() &&
2139 language.FindChar(PRUnichar(',')) == kNotFound) {
2140 mLanguage = do_GetAtom(language);
2141 } else {
2142 // we didn't find a (usable) Content-Language, so we fall back
2143 // to whatever the presContext guessed from the charset
2144 mLanguage = aPresContext->GetLanguageFromCharset();
2147 mVisible = NS_STYLE_VISIBILITY_VISIBLE;
2148 mPointerEvents = NS_STYLE_POINTER_EVENTS_AUTO;
2151 nsStyleVisibility::nsStyleVisibility(const nsStyleVisibility& aSource)
2153 MOZ_COUNT_CTOR(nsStyleVisibility);
2154 mDirection = aSource.mDirection;
2155 mVisible = aSource.mVisible;
2156 mLanguage = aSource.mLanguage;
2157 mPointerEvents = aSource.mPointerEvents;
2160 nsChangeHint nsStyleVisibility::CalcDifference(const nsStyleVisibility& aOther) const
2162 nsChangeHint hint = nsChangeHint(0);
2164 if (mDirection != aOther.mDirection) {
2165 NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
2166 } else if (mLanguage == aOther.mLanguage) {
2167 if (mVisible != aOther.mVisible) {
2168 if ((NS_STYLE_VISIBILITY_COLLAPSE == mVisible) ||
2169 (NS_STYLE_VISIBILITY_COLLAPSE == aOther.mVisible)) {
2170 NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
2171 } else {
2172 NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL);
2175 } else {
2176 NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
2178 return hint;
2181 #ifdef DEBUG
2182 /* static */
2183 nsChangeHint nsStyleVisibility::MaxDifference()
2185 return NS_STYLE_HINT_FRAMECHANGE;
2187 #endif
2189 nsStyleContentData::~nsStyleContentData()
2191 NS_ABORT_IF_FALSE(!mImageTracked,
2192 "nsStyleContentData being destroyed while still tracking image!");
2193 if (mType == eStyleContentType_Image) {
2194 NS_IF_RELEASE(mContent.mImage);
2195 } else if (mType == eStyleContentType_Counter ||
2196 mType == eStyleContentType_Counters) {
2197 mContent.mCounters->Release();
2198 } else if (mContent.mString) {
2199 NS_Free(mContent.mString);
2203 nsStyleContentData& nsStyleContentData::operator=(const nsStyleContentData& aOther)
2205 if (this == &aOther)
2206 return *this;
2207 this->~nsStyleContentData();
2208 new (this) nsStyleContentData();
2210 mType = aOther.mType;
2211 if (mType == eStyleContentType_Image) {
2212 mContent.mImage = aOther.mContent.mImage;
2213 NS_IF_ADDREF(mContent.mImage);
2214 } else if (mType == eStyleContentType_Counter ||
2215 mType == eStyleContentType_Counters) {
2216 mContent.mCounters = aOther.mContent.mCounters;
2217 mContent.mCounters->AddRef();
2218 } else if (aOther.mContent.mString) {
2219 mContent.mString = NS_strdup(aOther.mContent.mString);
2220 } else {
2221 mContent.mString = nsnull;
2223 return *this;
2226 PRBool nsStyleContentData::operator==(const nsStyleContentData& aOther) const
2228 if (mType != aOther.mType)
2229 return PR_FALSE;
2230 if (mType == eStyleContentType_Image) {
2231 if (!mContent.mImage || !aOther.mContent.mImage)
2232 return mContent.mImage == aOther.mContent.mImage;
2233 PRBool eq;
2234 nsCOMPtr<nsIURI> thisURI, otherURI;
2235 mContent.mImage->GetURI(getter_AddRefs(thisURI));
2236 aOther.mContent.mImage->GetURI(getter_AddRefs(otherURI));
2237 return thisURI == otherURI || // handles null==null
2238 (thisURI && otherURI &&
2239 NS_SUCCEEDED(thisURI->Equals(otherURI, &eq)) &&
2240 eq);
2242 if (mType == eStyleContentType_Counter ||
2243 mType == eStyleContentType_Counters)
2244 return *mContent.mCounters == *aOther.mContent.mCounters;
2245 return nsCRT::strcmp(mContent.mString, aOther.mContent.mString) == 0;
2248 void
2249 nsStyleContentData::TrackImage(nsPresContext* aContext)
2251 // Sanity
2252 NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!");
2253 NS_ABORT_IF_FALSE(mType == eStyleContentType_Image,
2254 "Tryingto do image tracking on non-image!");
2255 NS_ABORT_IF_FALSE(mContent.mImage,
2256 "Can't track image when there isn't one!");
2258 // Register the image with the document
2259 nsIDocument* doc = aContext->Document();
2260 if (doc)
2261 doc->AddImage(mContent.mImage);
2263 // Mark state
2264 #ifdef DEBUG
2265 mImageTracked = true;
2266 #endif
2269 void
2270 nsStyleContentData::UntrackImage(nsPresContext* aContext)
2272 // Sanity
2273 NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!");
2274 NS_ABORT_IF_FALSE(mType == eStyleContentType_Image,
2275 "Trying to do image tracking on non-image!");
2276 NS_ABORT_IF_FALSE(mContent.mImage,
2277 "Can't untrack image when there isn't one!");
2279 // Unregister the image with the document
2280 nsIDocument* doc = aContext->Document();
2281 if (doc)
2282 doc->RemoveImage(mContent.mImage);
2284 // Mark state
2285 #ifdef DEBUG
2286 mImageTracked = false;
2287 #endif
2291 //-----------------------
2292 // nsStyleContent
2295 nsStyleContent::nsStyleContent(void)
2296 : mMarkerOffset(),
2297 mContents(nsnull),
2298 mIncrements(nsnull),
2299 mResets(nsnull),
2300 mContentCount(0),
2301 mIncrementCount(0),
2302 mResetCount(0)
2304 MOZ_COUNT_CTOR(nsStyleContent);
2305 mMarkerOffset.SetAutoValue();
2308 nsStyleContent::~nsStyleContent(void)
2310 MOZ_COUNT_DTOR(nsStyleContent);
2311 DELETE_ARRAY_IF(mContents);
2312 DELETE_ARRAY_IF(mIncrements);
2313 DELETE_ARRAY_IF(mResets);
2316 void
2317 nsStyleContent::Destroy(nsPresContext* aContext)
2319 // Unregister any images we might have with the document.
2320 for (PRUint32 i = 0; i < mContentCount; ++i) {
2321 if ((mContents[i].mType == eStyleContentType_Image) &&
2322 mContents[i].mContent.mImage) {
2323 mContents[i].UntrackImage(aContext);
2327 this->~nsStyleContent();
2328 aContext->FreeToShell(sizeof(nsStyleContent), this);
2331 nsStyleContent::nsStyleContent(const nsStyleContent& aSource)
2332 :mMarkerOffset(),
2333 mContents(nsnull),
2334 mIncrements(nsnull),
2335 mResets(nsnull),
2336 mContentCount(0),
2337 mIncrementCount(0),
2338 mResetCount(0)
2341 MOZ_COUNT_CTOR(nsStyleContent);
2342 mMarkerOffset = aSource.mMarkerOffset;
2344 PRUint32 index;
2345 if (NS_SUCCEEDED(AllocateContents(aSource.ContentCount()))) {
2346 for (index = 0; index < mContentCount; index++) {
2347 ContentAt(index) = aSource.ContentAt(index);
2351 if (NS_SUCCEEDED(AllocateCounterIncrements(aSource.CounterIncrementCount()))) {
2352 for (index = 0; index < mIncrementCount; index++) {
2353 const nsStyleCounterData *data = aSource.GetCounterIncrementAt(index);
2354 mIncrements[index].mCounter = data->mCounter;
2355 mIncrements[index].mValue = data->mValue;
2359 if (NS_SUCCEEDED(AllocateCounterResets(aSource.CounterResetCount()))) {
2360 for (index = 0; index < mResetCount; index++) {
2361 const nsStyleCounterData *data = aSource.GetCounterResetAt(index);
2362 mResets[index].mCounter = data->mCounter;
2363 mResets[index].mValue = data->mValue;
2368 nsChangeHint nsStyleContent::CalcDifference(const nsStyleContent& aOther) const
2370 // In ReResolveStyleContext we assume that if there's no existing
2371 // ::before or ::after and we don't have to restyle children of the
2372 // node then we can't end up with a ::before or ::after due to the
2373 // restyle of the node itself. That's not quite true, but the only
2374 // exception to the above is when the 'content' property of the node
2375 // changes and the pseudo-element inherits the changed value. Since
2376 // the code here triggers a frame change on the node in that case,
2377 // the optimization in ReResolveStyleContext is ok. But if we ever
2378 // change this code to not reconstruct frames on changes to the
2379 // 'content' property, then we will need to revisit the optimization
2380 // in ReResolveStyleContext.
2382 if (mContentCount != aOther.mContentCount ||
2383 mIncrementCount != aOther.mIncrementCount ||
2384 mResetCount != aOther.mResetCount) {
2385 return NS_STYLE_HINT_FRAMECHANGE;
2388 PRUint32 ix = mContentCount;
2389 while (0 < ix--) {
2390 if (mContents[ix] != aOther.mContents[ix]) {
2391 // Unfortunately we need to reframe here; a simple reflow
2392 // will not pick up different text or different image URLs,
2393 // since we set all that up in the CSSFrameConstructor
2394 return NS_STYLE_HINT_FRAMECHANGE;
2397 ix = mIncrementCount;
2398 while (0 < ix--) {
2399 if ((mIncrements[ix].mValue != aOther.mIncrements[ix].mValue) ||
2400 (mIncrements[ix].mCounter != aOther.mIncrements[ix].mCounter)) {
2401 return NS_STYLE_HINT_FRAMECHANGE;
2404 ix = mResetCount;
2405 while (0 < ix--) {
2406 if ((mResets[ix].mValue != aOther.mResets[ix].mValue) ||
2407 (mResets[ix].mCounter != aOther.mResets[ix].mCounter)) {
2408 return NS_STYLE_HINT_FRAMECHANGE;
2411 if (mMarkerOffset != aOther.mMarkerOffset) {
2412 return NS_STYLE_HINT_REFLOW;
2414 return NS_STYLE_HINT_NONE;
2417 #ifdef DEBUG
2418 /* static */
2419 nsChangeHint nsStyleContent::MaxDifference()
2421 return NS_STYLE_HINT_FRAMECHANGE;
2423 #endif
2425 nsresult nsStyleContent::AllocateContents(PRUint32 aCount)
2427 // We need to run the destructors of the elements of mContents, so we
2428 // delete and reallocate even if aCount == mContentCount. (If
2429 // nsStyleContentData had its members private and managed their
2430 // ownership on setting, we wouldn't need this, but that seems
2431 // unnecessary at this point.)
2432 DELETE_ARRAY_IF(mContents);
2433 if (aCount) {
2434 mContents = new nsStyleContentData[aCount];
2435 if (! mContents) {
2436 mContentCount = 0;
2437 return NS_ERROR_OUT_OF_MEMORY;
2440 mContentCount = aCount;
2441 return NS_OK;
2444 // ---------------------
2445 // nsStyleQuotes
2448 nsStyleQuotes::nsStyleQuotes(void)
2449 : mQuotesCount(0),
2450 mQuotes(nsnull)
2452 MOZ_COUNT_CTOR(nsStyleQuotes);
2453 SetInitial();
2456 nsStyleQuotes::~nsStyleQuotes(void)
2458 MOZ_COUNT_DTOR(nsStyleQuotes);
2459 DELETE_ARRAY_IF(mQuotes);
2462 nsStyleQuotes::nsStyleQuotes(const nsStyleQuotes& aSource)
2463 : mQuotesCount(0),
2464 mQuotes(nsnull)
2466 MOZ_COUNT_CTOR(nsStyleQuotes);
2467 CopyFrom(aSource);
2470 void
2471 nsStyleQuotes::SetInitial()
2473 // The initial value for quotes is the en-US typographic convention:
2474 // outermost are LEFT and RIGHT DOUBLE QUOTATION MARK, alternating
2475 // with LEFT and RIGHT SINGLE QUOTATION MARK.
2476 static const PRUnichar initialQuotes[8] = {
2477 0x201C, 0, 0x201D, 0, 0x2018, 0, 0x2019, 0
2480 if (NS_SUCCEEDED(AllocateQuotes(2))) {
2481 SetQuotesAt(0,
2482 nsDependentString(&initialQuotes[0], 1),
2483 nsDependentString(&initialQuotes[2], 1));
2484 SetQuotesAt(1,
2485 nsDependentString(&initialQuotes[4], 1),
2486 nsDependentString(&initialQuotes[6], 1));
2490 void
2491 nsStyleQuotes::CopyFrom(const nsStyleQuotes& aSource)
2493 if (NS_SUCCEEDED(AllocateQuotes(aSource.QuotesCount()))) {
2494 PRUint32 count = (mQuotesCount * 2);
2495 for (PRUint32 index = 0; index < count; index += 2) {
2496 aSource.GetQuotesAt(index, mQuotes[index], mQuotes[index + 1]);
2501 nsChangeHint nsStyleQuotes::CalcDifference(const nsStyleQuotes& aOther) const
2503 // If the quotes implementation is ever going to change we might not need
2504 // a framechange here and a reflow should be sufficient. See bug 35768.
2505 if (mQuotesCount == aOther.mQuotesCount) {
2506 PRUint32 ix = (mQuotesCount * 2);
2507 while (0 < ix--) {
2508 if (mQuotes[ix] != aOther.mQuotes[ix]) {
2509 return NS_STYLE_HINT_FRAMECHANGE;
2513 return NS_STYLE_HINT_NONE;
2515 return NS_STYLE_HINT_FRAMECHANGE;
2518 #ifdef DEBUG
2519 /* static */
2520 nsChangeHint nsStyleQuotes::MaxDifference()
2522 return NS_STYLE_HINT_FRAMECHANGE;
2524 #endif
2526 // --------------------
2527 // nsStyleTextReset
2530 nsStyleTextReset::nsStyleTextReset(void)
2532 MOZ_COUNT_CTOR(nsStyleTextReset);
2533 mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE, eStyleUnit_Enumerated);
2534 mTextDecoration = NS_STYLE_TEXT_DECORATION_NONE;
2535 mUnicodeBidi = NS_STYLE_UNICODE_BIDI_NORMAL;
2538 nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource)
2540 MOZ_COUNT_CTOR(nsStyleTextReset);
2541 memcpy((nsStyleTextReset*)this, &aSource, sizeof(nsStyleTextReset));
2544 nsStyleTextReset::~nsStyleTextReset(void)
2546 MOZ_COUNT_DTOR(nsStyleTextReset);
2549 nsChangeHint nsStyleTextReset::CalcDifference(const nsStyleTextReset& aOther) const
2551 if (mVerticalAlign == aOther.mVerticalAlign
2552 && mUnicodeBidi == aOther.mUnicodeBidi) {
2553 if (mTextDecoration != aOther.mTextDecoration) {
2554 // Reflow for blink changes, repaint for others
2555 return
2556 (mTextDecoration & NS_STYLE_TEXT_DECORATION_BLINK) ==
2557 (aOther.mTextDecoration & NS_STYLE_TEXT_DECORATION_BLINK) ?
2558 NS_STYLE_HINT_VISUAL : NS_STYLE_HINT_REFLOW;
2561 return NS_STYLE_HINT_NONE;
2563 return NS_STYLE_HINT_REFLOW;
2566 #ifdef DEBUG
2567 /* static */
2568 nsChangeHint nsStyleTextReset::MaxDifference()
2570 return NS_STYLE_HINT_REFLOW;
2572 #endif
2574 // Allowed to return one of NS_STYLE_HINT_NONE, NS_STYLE_HINT_REFLOW
2575 // or NS_STYLE_HINT_VISUAL. Currently we just return NONE or REFLOW, though.
2576 // XXXbz can this not return a more specific hint? If that's ever
2577 // changed, nsStyleBorder::CalcDifference will need changing too.
2578 static nsChangeHint
2579 CalcShadowDifference(nsCSSShadowArray* lhs,
2580 nsCSSShadowArray* rhs)
2582 if (lhs == rhs)
2583 return NS_STYLE_HINT_NONE;
2585 if (!lhs || !rhs || lhs->Length() != rhs->Length())
2586 return NS_STYLE_HINT_REFLOW;
2588 for (PRUint32 i = 0; i < lhs->Length(); ++i) {
2589 if (*lhs->ShadowAt(i) != *rhs->ShadowAt(i))
2590 return NS_STYLE_HINT_REFLOW;
2592 return NS_STYLE_HINT_NONE;
2595 // --------------------
2596 // nsStyleText
2599 nsStyleText::nsStyleText(void)
2601 MOZ_COUNT_CTOR(nsStyleText);
2602 mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
2603 mTextTransform = NS_STYLE_TEXT_TRANSFORM_NONE;
2604 mWhiteSpace = NS_STYLE_WHITESPACE_NORMAL;
2605 mWordWrap = NS_STYLE_WORDWRAP_NORMAL;
2607 mLetterSpacing.SetNormalValue();
2608 mLineHeight.SetNormalValue();
2609 mTextIndent.SetCoordValue(0);
2610 mWordSpacing = 0;
2612 mTextShadow = nsnull;
2613 mTabSize = NS_STYLE_TABSIZE_INITIAL;
2616 nsStyleText::nsStyleText(const nsStyleText& aSource)
2617 : mTextAlign(aSource.mTextAlign),
2618 mTextTransform(aSource.mTextTransform),
2619 mWhiteSpace(aSource.mWhiteSpace),
2620 mWordWrap(aSource.mWordWrap),
2621 mTabSize(aSource.mTabSize),
2622 mLetterSpacing(aSource.mLetterSpacing),
2623 mLineHeight(aSource.mLineHeight),
2624 mTextIndent(aSource.mTextIndent),
2625 mWordSpacing(aSource.mWordSpacing),
2626 mTextShadow(aSource.mTextShadow)
2628 MOZ_COUNT_CTOR(nsStyleText);
2631 nsStyleText::~nsStyleText(void)
2633 MOZ_COUNT_DTOR(nsStyleText);
2636 nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aOther) const
2638 if (NewlineIsSignificant() != aOther.NewlineIsSignificant()) {
2639 // This may require construction of suppressed text frames
2640 return NS_STYLE_HINT_FRAMECHANGE;
2643 if ((mTextAlign != aOther.mTextAlign) ||
2644 (mTextTransform != aOther.mTextTransform) ||
2645 (mWhiteSpace != aOther.mWhiteSpace) ||
2646 (mWordWrap != aOther.mWordWrap) ||
2647 (mLetterSpacing != aOther.mLetterSpacing) ||
2648 (mLineHeight != aOther.mLineHeight) ||
2649 (mTextIndent != aOther.mTextIndent) ||
2650 (mWordSpacing != aOther.mWordSpacing) ||
2651 (mTabSize != aOther.mTabSize))
2652 return NS_STYLE_HINT_REFLOW;
2654 return CalcShadowDifference(mTextShadow, aOther.mTextShadow);
2657 #ifdef DEBUG
2658 /* static */
2659 nsChangeHint nsStyleText::MaxDifference()
2661 return NS_STYLE_HINT_FRAMECHANGE;
2663 #endif
2665 //-----------------------
2666 // nsStyleUserInterface
2669 nsCursorImage::nsCursorImage()
2670 : mHaveHotspot(PR_FALSE)
2671 , mHotspotX(0.0f)
2672 , mHotspotY(0.0f)
2676 nsCursorImage::nsCursorImage(const nsCursorImage& aOther)
2677 : mHaveHotspot(aOther.mHaveHotspot)
2678 , mHotspotX(aOther.mHotspotX)
2679 , mHotspotY(aOther.mHotspotY)
2681 SetImage(aOther.GetImage());
2684 nsCursorImage::~nsCursorImage()
2686 SetImage(nsnull);
2689 nsCursorImage&
2690 nsCursorImage::operator=(const nsCursorImage& aOther)
2692 if (this != &aOther) {
2693 mHaveHotspot = aOther.mHaveHotspot;
2694 mHotspotX = aOther.mHotspotX;
2695 mHotspotY = aOther.mHotspotY;
2696 SetImage(aOther.GetImage());
2699 return *this;
2702 nsStyleUserInterface::nsStyleUserInterface(void)
2704 MOZ_COUNT_CTOR(nsStyleUserInterface);
2705 mUserInput = NS_STYLE_USER_INPUT_AUTO;
2706 mUserModify = NS_STYLE_USER_MODIFY_READ_ONLY;
2707 mUserFocus = NS_STYLE_USER_FOCUS_NONE;
2709 mCursor = NS_STYLE_CURSOR_AUTO; // fix for bugzilla bug 51113
2711 mCursorArrayLength = 0;
2712 mCursorArray = nsnull;
2715 nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource) :
2716 mUserInput(aSource.mUserInput),
2717 mUserModify(aSource.mUserModify),
2718 mUserFocus(aSource.mUserFocus),
2719 mCursor(aSource.mCursor)
2721 MOZ_COUNT_CTOR(nsStyleUserInterface);
2722 CopyCursorArrayFrom(aSource);
2725 nsStyleUserInterface::~nsStyleUserInterface(void)
2727 MOZ_COUNT_DTOR(nsStyleUserInterface);
2728 delete [] mCursorArray;
2731 nsChangeHint nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aOther) const
2733 nsChangeHint hint = nsChangeHint(0);
2734 if (mCursor != aOther.mCursor)
2735 NS_UpdateHint(hint, nsChangeHint_UpdateCursor);
2737 // We could do better. But it wouldn't be worth it, URL-specified cursors are
2738 // rare.
2739 if (mCursorArrayLength > 0 || aOther.mCursorArrayLength > 0)
2740 NS_UpdateHint(hint, nsChangeHint_UpdateCursor);
2742 if (mUserModify != aOther.mUserModify)
2743 NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL);
2745 if ((mUserInput != aOther.mUserInput) &&
2746 ((NS_STYLE_USER_INPUT_NONE == mUserInput) ||
2747 (NS_STYLE_USER_INPUT_NONE == aOther.mUserInput))) {
2748 NS_UpdateHint(hint, NS_STYLE_HINT_FRAMECHANGE);
2751 // ignore mUserFocus
2753 return hint;
2756 #ifdef DEBUG
2757 /* static */
2758 nsChangeHint nsStyleUserInterface::MaxDifference()
2760 return nsChangeHint(nsChangeHint_UpdateCursor | NS_STYLE_HINT_FRAMECHANGE);
2762 #endif
2764 void
2765 nsStyleUserInterface::CopyCursorArrayFrom(const nsStyleUserInterface& aSource)
2767 mCursorArray = nsnull;
2768 mCursorArrayLength = 0;
2769 if (aSource.mCursorArrayLength) {
2770 mCursorArray = new nsCursorImage[aSource.mCursorArrayLength];
2771 if (mCursorArray) {
2772 mCursorArrayLength = aSource.mCursorArrayLength;
2773 for (PRUint32 i = 0; i < mCursorArrayLength; ++i)
2774 mCursorArray[i] = aSource.mCursorArray[i];
2779 //-----------------------
2780 // nsStyleUIReset
2783 nsStyleUIReset::nsStyleUIReset(void)
2785 MOZ_COUNT_CTOR(nsStyleUIReset);
2786 mUserSelect = NS_STYLE_USER_SELECT_AUTO;
2787 mForceBrokenImageIcon = 0;
2788 mIMEMode = NS_STYLE_IME_MODE_AUTO;
2789 mWindowShadow = NS_STYLE_WINDOW_SHADOW_DEFAULT;
2792 nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource)
2794 MOZ_COUNT_CTOR(nsStyleUIReset);
2795 mUserSelect = aSource.mUserSelect;
2796 mForceBrokenImageIcon = aSource.mForceBrokenImageIcon;
2797 mIMEMode = aSource.mIMEMode;
2798 mWindowShadow = aSource.mWindowShadow;
2801 nsStyleUIReset::~nsStyleUIReset(void)
2803 MOZ_COUNT_DTOR(nsStyleUIReset);
2806 nsChangeHint nsStyleUIReset::CalcDifference(const nsStyleUIReset& aOther) const
2808 // ignore mIMEMode
2809 if (mForceBrokenImageIcon != aOther.mForceBrokenImageIcon)
2810 return NS_STYLE_HINT_FRAMECHANGE;
2811 if (mWindowShadow != aOther.mWindowShadow) {
2812 // We really need just an nsChangeHint_SyncFrameView, except
2813 // on an ancestor of the frame, so we get that by doing a
2814 // reflow.
2815 return NS_STYLE_HINT_REFLOW;
2817 if (mUserSelect != aOther.mUserSelect)
2818 return NS_STYLE_HINT_VISUAL;
2819 return NS_STYLE_HINT_NONE;
2822 #ifdef DEBUG
2823 /* static */
2824 nsChangeHint nsStyleUIReset::MaxDifference()
2826 return NS_STYLE_HINT_FRAMECHANGE;
2828 #endif