mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
c9f84b3f17
Ideally we'd make this property inaccessible to Web content style sheets, but that seems hard since view-source and plain text documents seem to load in a context that's very similar to Web content as far as the style system is concerned. It doesn't matter much since it's quite safe and unlikely to be discovered or used by anyone. --HG-- extra : rebase_source : 009aafc992afd07fd76a9026afe0f6994b4b214a
3220 lines
99 KiB
C++
3220 lines
99 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/*
|
|
* structs that contain the data provided by nsStyleContext, the
|
|
* internal API for computed style data for an element
|
|
*/
|
|
|
|
#include "nsStyleStruct.h"
|
|
#include "nsStyleStructInlines.h"
|
|
#include "nsStyleConsts.h"
|
|
#include "nsThemeConstants.h"
|
|
#include "nsString.h"
|
|
#include "nsPresContext.h"
|
|
#include "nsIWidget.h"
|
|
#include "nsCRTGlue.h"
|
|
#include "nsCSSProps.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsBidiUtils.h"
|
|
#include "nsLayoutUtils.h"
|
|
|
|
#include "imgIRequest.h"
|
|
#include "imgIContainer.h"
|
|
|
|
#include "mozilla/Likely.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIDocument.h"
|
|
#include <algorithm>
|
|
|
|
static_assert((((1 << nsStyleStructID_Length) - 1) &
|
|
~(NS_STYLE_INHERIT_MASK)) == 0,
|
|
"Not enough bits in NS_STYLE_INHERIT_MASK");
|
|
|
|
inline bool IsFixedUnit(const nsStyleCoord& aCoord, bool aEnumOK)
|
|
{
|
|
return aCoord.ConvertsToLength() ||
|
|
(aEnumOK && aCoord.GetUnit() == eStyleUnit_Enumerated);
|
|
}
|
|
|
|
static bool EqualURIs(nsIURI *aURI1, nsIURI *aURI2)
|
|
{
|
|
bool eq;
|
|
return aURI1 == aURI2 || // handle null==null, and optimize
|
|
(aURI1 && aURI2 &&
|
|
NS_SUCCEEDED(aURI1->Equals(aURI2, &eq)) && // not equal on fail
|
|
eq);
|
|
}
|
|
|
|
static bool EqualURIs(mozilla::css::URLValue *aURI1, mozilla::css::URLValue *aURI2)
|
|
{
|
|
return aURI1 == aURI2 || // handle null==null, and optimize
|
|
(aURI1 && aURI2 && aURI1->URIEquals(*aURI2));
|
|
}
|
|
|
|
static bool EqualImages(imgIRequest *aImage1, imgIRequest* aImage2)
|
|
{
|
|
if (aImage1 == aImage2) {
|
|
return true;
|
|
}
|
|
|
|
if (!aImage1 || !aImage2) {
|
|
return false;
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> uri1, uri2;
|
|
aImage1->GetURI(getter_AddRefs(uri1));
|
|
aImage2->GetURI(getter_AddRefs(uri2));
|
|
return EqualURIs(uri1, uri2);
|
|
}
|
|
|
|
// A nullsafe wrapper for strcmp. We depend on null-safety.
|
|
static int safe_strcmp(const char16_t* a, const char16_t* b)
|
|
{
|
|
if (!a || !b) {
|
|
return (int)(a - b);
|
|
}
|
|
return NS_strcmp(a, b);
|
|
}
|
|
|
|
static nsChangeHint CalcShadowDifference(nsCSSShadowArray* lhs,
|
|
nsCSSShadowArray* rhs);
|
|
|
|
// --------------------
|
|
// nsStyleFont
|
|
//
|
|
nsStyleFont::nsStyleFont(const nsFont& aFont, nsPresContext *aPresContext)
|
|
: mFont(aFont)
|
|
, mGenericID(kGenericFont_NONE)
|
|
, mExplicitLanguage(false)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleFont);
|
|
Init(aPresContext);
|
|
}
|
|
|
|
nsStyleFont::nsStyleFont(const nsStyleFont& aSrc)
|
|
: mFont(aSrc.mFont)
|
|
, mSize(aSrc.mSize)
|
|
, mGenericID(aSrc.mGenericID)
|
|
, mScriptLevel(aSrc.mScriptLevel)
|
|
, mMathVariant(aSrc.mMathVariant)
|
|
, mMathDisplay(aSrc.mMathDisplay)
|
|
, mExplicitLanguage(aSrc.mExplicitLanguage)
|
|
, mAllowZoom(aSrc.mAllowZoom)
|
|
, mScriptUnconstrainedSize(aSrc.mScriptUnconstrainedSize)
|
|
, mScriptMinSize(aSrc.mScriptMinSize)
|
|
, mScriptSizeMultiplier(aSrc.mScriptSizeMultiplier)
|
|
, mLanguage(aSrc.mLanguage)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleFont);
|
|
}
|
|
|
|
nsStyleFont::nsStyleFont(nsPresContext* aPresContext)
|
|
// passing nullptr to GetDefaultFont make it use the doc language
|
|
: mFont(*(aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
|
|
nullptr)))
|
|
, mGenericID(kGenericFont_NONE)
|
|
, mExplicitLanguage(false)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleFont);
|
|
Init(aPresContext);
|
|
}
|
|
|
|
void
|
|
nsStyleFont::Init(nsPresContext* aPresContext)
|
|
{
|
|
mSize = mFont.size = nsStyleFont::ZoomText(aPresContext, mFont.size);
|
|
mScriptUnconstrainedSize = mSize;
|
|
mScriptMinSize = aPresContext->CSSTwipsToAppUnits(
|
|
NS_POINTS_TO_TWIPS(NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT));
|
|
mScriptLevel = 0;
|
|
mScriptSizeMultiplier = NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER;
|
|
mMathVariant = NS_MATHML_MATHVARIANT_NONE;
|
|
mMathDisplay = NS_MATHML_DISPLAYSTYLE_INLINE;
|
|
mAllowZoom = true;
|
|
|
|
nsAutoString language;
|
|
aPresContext->Document()->GetContentLanguage(language);
|
|
language.StripWhitespace();
|
|
|
|
// Content-Language may be a comma-separated list of language codes,
|
|
// in which case the HTML5 spec says to treat it as unknown
|
|
if (!language.IsEmpty() &&
|
|
language.FindChar(char16_t(',')) == kNotFound) {
|
|
mLanguage = do_GetAtom(language);
|
|
// NOTE: This does *not* count as an explicit language; in other
|
|
// words, it doesn't trigger language-specific hyphenation.
|
|
} else {
|
|
// we didn't find a (usable) Content-Language, so we fall back
|
|
// to whatever the presContext guessed from the charset
|
|
mLanguage = aPresContext->GetLanguageFromCharset();
|
|
}
|
|
}
|
|
|
|
void*
|
|
nsStyleFont::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
|
|
void* result = aContext->AllocateFromShell(sz);
|
|
if (result)
|
|
memset(result, 0, sz);
|
|
return result;
|
|
}
|
|
|
|
void
|
|
nsStyleFont::Destroy(nsPresContext* aContext) {
|
|
this->~nsStyleFont();
|
|
aContext->FreeToShell(sizeof(nsStyleFont), this);
|
|
}
|
|
|
|
void
|
|
nsStyleFont::EnableZoom(nsPresContext* aContext, bool aEnable)
|
|
{
|
|
if (mAllowZoom == aEnable) {
|
|
return;
|
|
}
|
|
mAllowZoom = aEnable;
|
|
if (mAllowZoom) {
|
|
mSize = nsStyleFont::ZoomText(aContext, mSize);
|
|
mFont.size = nsStyleFont::ZoomText(aContext, mFont.size);
|
|
mScriptUnconstrainedSize =
|
|
nsStyleFont::ZoomText(aContext, mScriptUnconstrainedSize);
|
|
} else {
|
|
mSize = nsStyleFont::UnZoomText(aContext, mSize);
|
|
mFont.size = nsStyleFont::UnZoomText(aContext, mFont.size);
|
|
mScriptUnconstrainedSize =
|
|
nsStyleFont::UnZoomText(aContext, mScriptUnconstrainedSize);
|
|
}
|
|
}
|
|
|
|
nsChangeHint nsStyleFont::CalcDifference(const nsStyleFont& aOther) const
|
|
{
|
|
MOZ_ASSERT(mAllowZoom == aOther.mAllowZoom,
|
|
"expected mAllowZoom to be the same on both nsStyleFonts");
|
|
if (mSize != aOther.mSize ||
|
|
mLanguage != aOther.mLanguage ||
|
|
mExplicitLanguage != aOther.mExplicitLanguage ||
|
|
mMathVariant != aOther.mMathVariant ||
|
|
mMathDisplay != aOther.mMathDisplay) {
|
|
return NS_STYLE_HINT_REFLOW;
|
|
}
|
|
return CalcFontDifference(mFont, aOther.mFont);
|
|
}
|
|
|
|
/* static */ nscoord
|
|
nsStyleFont::ZoomText(nsPresContext *aPresContext, nscoord aSize)
|
|
{
|
|
return nscoord(float(aSize) * aPresContext->TextZoom());
|
|
}
|
|
|
|
/* static */ nscoord
|
|
nsStyleFont::UnZoomText(nsPresContext *aPresContext, nscoord aSize)
|
|
{
|
|
return nscoord(float(aSize) / aPresContext->TextZoom());
|
|
}
|
|
|
|
nsChangeHint nsStyleFont::CalcFontDifference(const nsFont& aFont1, const nsFont& aFont2)
|
|
{
|
|
if ((aFont1.size == aFont2.size) &&
|
|
(aFont1.sizeAdjust == aFont2.sizeAdjust) &&
|
|
(aFont1.style == aFont2.style) &&
|
|
(aFont1.variant == aFont2.variant) &&
|
|
(aFont1.weight == aFont2.weight) &&
|
|
(aFont1.stretch == aFont2.stretch) &&
|
|
(aFont1.smoothing == aFont2.smoothing) &&
|
|
(aFont1.name == aFont2.name) &&
|
|
(aFont1.kerning == aFont2.kerning) &&
|
|
(aFont1.synthesis == aFont2.synthesis) &&
|
|
(aFont1.variantAlternates == aFont2.variantAlternates) &&
|
|
(aFont1.alternateValues == aFont2.alternateValues) &&
|
|
(aFont1.featureValueLookup == aFont2.featureValueLookup) &&
|
|
(aFont1.variantCaps == aFont2.variantCaps) &&
|
|
(aFont1.variantEastAsian == aFont2.variantEastAsian) &&
|
|
(aFont1.variantLigatures == aFont2.variantLigatures) &&
|
|
(aFont1.variantNumeric == aFont2.variantNumeric) &&
|
|
(aFont1.variantPosition == aFont2.variantPosition) &&
|
|
(aFont1.fontFeatureSettings == aFont2.fontFeatureSettings) &&
|
|
(aFont1.languageOverride == aFont2.languageOverride) &&
|
|
(aFont1.systemFont == aFont2.systemFont)) {
|
|
if ((aFont1.decorations == aFont2.decorations)) {
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
return NS_STYLE_HINT_VISUAL;
|
|
}
|
|
return NS_STYLE_HINT_REFLOW;
|
|
}
|
|
|
|
static bool IsFixedData(const nsStyleSides& aSides, bool aEnumOK)
|
|
{
|
|
NS_FOR_CSS_SIDES(side) {
|
|
if (!IsFixedUnit(aSides.Get(side), aEnumOK))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static nscoord CalcCoord(const nsStyleCoord& aCoord,
|
|
const nscoord* aEnumTable,
|
|
int32_t aNumEnums)
|
|
{
|
|
if (aCoord.GetUnit() == eStyleUnit_Enumerated) {
|
|
NS_ABORT_IF_FALSE(aEnumTable, "must have enum table");
|
|
int32_t value = aCoord.GetIntValue();
|
|
if (0 <= value && value < aNumEnums) {
|
|
return aEnumTable[aCoord.GetIntValue()];
|
|
}
|
|
NS_NOTREACHED("unexpected enum value");
|
|
return 0;
|
|
}
|
|
NS_ABORT_IF_FALSE(aCoord.ConvertsToLength(), "unexpected unit");
|
|
return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
|
|
}
|
|
|
|
nsStyleMargin::nsStyleMargin() {
|
|
MOZ_COUNT_CTOR(nsStyleMargin);
|
|
nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
|
|
NS_FOR_CSS_SIDES(side) {
|
|
mMargin.Set(side, zero);
|
|
}
|
|
mHasCachedMargin = false;
|
|
}
|
|
|
|
nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc) {
|
|
MOZ_COUNT_CTOR(nsStyleMargin);
|
|
mMargin = aSrc.mMargin;
|
|
mHasCachedMargin = false;
|
|
}
|
|
|
|
void*
|
|
nsStyleMargin::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
|
|
void* result = aContext->AllocateFromShell(sz);
|
|
if (result)
|
|
memset(result, 0, sz);
|
|
return result;
|
|
}
|
|
|
|
void
|
|
nsStyleMargin::Destroy(nsPresContext* aContext) {
|
|
this->~nsStyleMargin();
|
|
aContext->FreeToShell(sizeof(nsStyleMargin), this);
|
|
}
|
|
|
|
|
|
void nsStyleMargin::RecalcData()
|
|
{
|
|
if (IsFixedData(mMargin, false)) {
|
|
NS_FOR_CSS_SIDES(side) {
|
|
mCachedMargin.Side(side) = CalcCoord(mMargin.Get(side), nullptr, 0);
|
|
}
|
|
mHasCachedMargin = true;
|
|
}
|
|
else
|
|
mHasCachedMargin = false;
|
|
}
|
|
|
|
nsChangeHint nsStyleMargin::CalcDifference(const nsStyleMargin& aOther) const
|
|
{
|
|
if (mMargin == aOther.mMargin) {
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
// Margin differences can't affect descendant intrinsic sizes and
|
|
// don't need to force children to reflow.
|
|
return NS_CombineHint(nsChangeHint_NeedReflow,
|
|
nsChangeHint_ClearAncestorIntrinsics);
|
|
}
|
|
|
|
nsStylePadding::nsStylePadding() {
|
|
MOZ_COUNT_CTOR(nsStylePadding);
|
|
nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
|
|
NS_FOR_CSS_SIDES(side) {
|
|
mPadding.Set(side, zero);
|
|
}
|
|
mHasCachedPadding = false;
|
|
}
|
|
|
|
nsStylePadding::nsStylePadding(const nsStylePadding& aSrc) {
|
|
MOZ_COUNT_CTOR(nsStylePadding);
|
|
mPadding = aSrc.mPadding;
|
|
mHasCachedPadding = false;
|
|
}
|
|
|
|
void*
|
|
nsStylePadding::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
|
|
void* result = aContext->AllocateFromShell(sz);
|
|
if (result)
|
|
memset(result, 0, sz);
|
|
return result;
|
|
}
|
|
|
|
void
|
|
nsStylePadding::Destroy(nsPresContext* aContext) {
|
|
this->~nsStylePadding();
|
|
aContext->FreeToShell(sizeof(nsStylePadding), this);
|
|
}
|
|
|
|
void nsStylePadding::RecalcData()
|
|
{
|
|
if (IsFixedData(mPadding, false)) {
|
|
NS_FOR_CSS_SIDES(side) {
|
|
// Clamp negative calc() to 0.
|
|
mCachedPadding.Side(side) =
|
|
std::max(CalcCoord(mPadding.Get(side), nullptr, 0), 0);
|
|
}
|
|
mHasCachedPadding = true;
|
|
}
|
|
else
|
|
mHasCachedPadding = false;
|
|
}
|
|
|
|
nsChangeHint nsStylePadding::CalcDifference(const nsStylePadding& aOther) const
|
|
{
|
|
if (mPadding == aOther.mPadding) {
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
// Padding differences can't affect descendant intrinsic sizes, but do need
|
|
// to force children to reflow so that we can reposition them, since their
|
|
// offsets are from our frame bounds but our content rect's position within
|
|
// those bounds is moving.
|
|
return NS_SubtractHint(NS_STYLE_HINT_REFLOW,
|
|
nsChangeHint_ClearDescendantIntrinsics);
|
|
}
|
|
|
|
nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext)
|
|
: mBorderColors(nullptr),
|
|
mBoxShadow(nullptr),
|
|
mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL),
|
|
mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
|
|
mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
|
|
mFloatEdge(NS_STYLE_FLOAT_EDGE_CONTENT),
|
|
mComputedBorder(0, 0, 0, 0)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleBorder);
|
|
|
|
NS_FOR_CSS_HALF_CORNERS (corner) {
|
|
mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
|
|
}
|
|
|
|
nscoord medium =
|
|
(aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
|
|
NS_FOR_CSS_SIDES(side) {
|
|
mBorderImageSlice.Set(side, nsStyleCoord(1.0f, eStyleUnit_Percent));
|
|
mBorderImageWidth.Set(side, nsStyleCoord(1.0f, eStyleUnit_Factor));
|
|
mBorderImageOutset.Set(side, nsStyleCoord(0.0f, eStyleUnit_Factor));
|
|
|
|
mBorder.Side(side) = medium;
|
|
mBorderStyle[side] = NS_STYLE_BORDER_STYLE_NONE | BORDER_COLOR_FOREGROUND;
|
|
mBorderColor[side] = NS_RGB(0, 0, 0);
|
|
}
|
|
|
|
mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
|
|
}
|
|
|
|
nsBorderColors::~nsBorderColors()
|
|
{
|
|
NS_CSS_DELETE_LIST_MEMBER(nsBorderColors, this, mNext);
|
|
}
|
|
|
|
nsBorderColors*
|
|
nsBorderColors::Clone(bool aDeep) const
|
|
{
|
|
nsBorderColors* result = new nsBorderColors(mColor);
|
|
if (MOZ_UNLIKELY(!result))
|
|
return result;
|
|
if (aDeep)
|
|
NS_CSS_CLONE_LIST_MEMBER(nsBorderColors, this, mNext, result, (false));
|
|
return result;
|
|
}
|
|
|
|
nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
|
|
: mBorderColors(nullptr),
|
|
mBoxShadow(aSrc.mBoxShadow),
|
|
mBorderRadius(aSrc.mBorderRadius),
|
|
mBorderImageSource(aSrc.mBorderImageSource),
|
|
mBorderImageSlice(aSrc.mBorderImageSlice),
|
|
mBorderImageWidth(aSrc.mBorderImageWidth),
|
|
mBorderImageOutset(aSrc.mBorderImageOutset),
|
|
mBorderImageFill(aSrc.mBorderImageFill),
|
|
mBorderImageRepeatH(aSrc.mBorderImageRepeatH),
|
|
mBorderImageRepeatV(aSrc.mBorderImageRepeatV),
|
|
mFloatEdge(aSrc.mFloatEdge),
|
|
mComputedBorder(aSrc.mComputedBorder),
|
|
mBorder(aSrc.mBorder),
|
|
mTwipsPerPixel(aSrc.mTwipsPerPixel)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleBorder);
|
|
if (aSrc.mBorderColors) {
|
|
EnsureBorderColors();
|
|
for (int32_t i = 0; i < 4; i++)
|
|
if (aSrc.mBorderColors[i])
|
|
mBorderColors[i] = aSrc.mBorderColors[i]->Clone();
|
|
else
|
|
mBorderColors[i] = nullptr;
|
|
}
|
|
|
|
NS_FOR_CSS_SIDES(side) {
|
|
mBorderStyle[side] = aSrc.mBorderStyle[side];
|
|
mBorderColor[side] = aSrc.mBorderColor[side];
|
|
}
|
|
}
|
|
|
|
nsStyleBorder::~nsStyleBorder()
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleBorder);
|
|
if (mBorderColors) {
|
|
for (int32_t i = 0; i < 4; i++)
|
|
delete mBorderColors[i];
|
|
delete [] mBorderColors;
|
|
}
|
|
}
|
|
|
|
void*
|
|
nsStyleBorder::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
|
|
void* result = aContext->AllocateFromShell(sz);
|
|
if (result)
|
|
memset(result, 0, sz);
|
|
return result;
|
|
}
|
|
|
|
nsMargin
|
|
nsStyleBorder::GetImageOutset() const
|
|
{
|
|
// We don't check whether there is a border-image (which is OK since
|
|
// the initial values yields 0 outset) so that we don't have to
|
|
// reflow to update overflow areas when an image loads.
|
|
nsMargin outset;
|
|
NS_FOR_CSS_SIDES(s) {
|
|
nsStyleCoord coord = mBorderImageOutset.Get(s);
|
|
nscoord value;
|
|
switch (coord.GetUnit()) {
|
|
case eStyleUnit_Coord:
|
|
value = coord.GetCoordValue();
|
|
break;
|
|
case eStyleUnit_Factor:
|
|
value = coord.GetFactorValue() * mComputedBorder.Side(s);
|
|
break;
|
|
default:
|
|
NS_NOTREACHED("unexpected CSS unit for image outset");
|
|
value = 0;
|
|
break;
|
|
}
|
|
outset.Side(s) = value;
|
|
}
|
|
return outset;
|
|
}
|
|
|
|
void
|
|
nsStyleBorder::Destroy(nsPresContext* aContext) {
|
|
UntrackImage(aContext);
|
|
this->~nsStyleBorder();
|
|
aContext->FreeToShell(sizeof(nsStyleBorder), this);
|
|
}
|
|
|
|
nsChangeHint nsStyleBorder::CalcDifference(const nsStyleBorder& aOther) const
|
|
{
|
|
nsChangeHint shadowDifference =
|
|
CalcShadowDifference(mBoxShadow, aOther.mBoxShadow);
|
|
NS_ABORT_IF_FALSE(shadowDifference == unsigned(NS_STYLE_HINT_REFLOW) ||
|
|
shadowDifference == unsigned(NS_STYLE_HINT_VISUAL) ||
|
|
shadowDifference == unsigned(NS_STYLE_HINT_NONE),
|
|
"should do more with shadowDifference");
|
|
|
|
// Note that differences in mBorder don't affect rendering (which should only
|
|
// use mComputedBorder), so don't need to be tested for here.
|
|
// XXXbz we should be able to return a more specific change hint for
|
|
// at least GetComputedBorder() differences...
|
|
if (mTwipsPerPixel != aOther.mTwipsPerPixel ||
|
|
GetComputedBorder() != aOther.GetComputedBorder() ||
|
|
mFloatEdge != aOther.mFloatEdge ||
|
|
mBorderImageOutset != aOther.mBorderImageOutset ||
|
|
(shadowDifference & nsChangeHint_NeedReflow))
|
|
return NS_STYLE_HINT_REFLOW;
|
|
|
|
NS_FOR_CSS_SIDES(ix) {
|
|
// See the explanation in nsChangeHint.h of
|
|
// nsChangeHint_BorderStyleNoneChange .
|
|
// Furthermore, even though we know *this* side is 0 width, just
|
|
// assume a visual hint for some other change rather than bother
|
|
// tracking this result through the rest of the function.
|
|
if (HasVisibleStyle(ix) != aOther.HasVisibleStyle(ix)) {
|
|
return NS_CombineHint(NS_STYLE_HINT_VISUAL,
|
|
nsChangeHint_BorderStyleNoneChange);
|
|
}
|
|
}
|
|
|
|
// Note that mBorderStyle stores not only the border style but also
|
|
// color-related flags. Given that we've already done an mComputedBorder
|
|
// comparison, border-style differences can only lead to a VISUAL hint. So
|
|
// it's OK to just compare the values directly -- if either the actual
|
|
// style or the color flags differ we want to repaint.
|
|
NS_FOR_CSS_SIDES(ix) {
|
|
if (mBorderStyle[ix] != aOther.mBorderStyle[ix] ||
|
|
mBorderColor[ix] != aOther.mBorderColor[ix])
|
|
return NS_STYLE_HINT_VISUAL;
|
|
}
|
|
|
|
if (mBorderRadius != aOther.mBorderRadius ||
|
|
!mBorderColors != !aOther.mBorderColors)
|
|
return NS_STYLE_HINT_VISUAL;
|
|
|
|
if (IsBorderImageLoaded() || aOther.IsBorderImageLoaded()) {
|
|
if (mBorderImageSource != aOther.mBorderImageSource ||
|
|
mBorderImageRepeatH != aOther.mBorderImageRepeatH ||
|
|
mBorderImageRepeatV != aOther.mBorderImageRepeatV ||
|
|
mBorderImageSlice != aOther.mBorderImageSlice ||
|
|
mBorderImageFill != aOther.mBorderImageFill ||
|
|
mBorderImageWidth != aOther.mBorderImageWidth ||
|
|
mBorderImageOutset != aOther.mBorderImageOutset)
|
|
return NS_STYLE_HINT_VISUAL;
|
|
}
|
|
|
|
// Note that at this point if mBorderColors is non-null so is
|
|
// aOther.mBorderColors
|
|
if (mBorderColors) {
|
|
NS_FOR_CSS_SIDES(ix) {
|
|
if (!nsBorderColors::Equal(mBorderColors[ix],
|
|
aOther.mBorderColors[ix]))
|
|
return NS_STYLE_HINT_VISUAL;
|
|
}
|
|
}
|
|
|
|
return shadowDifference;
|
|
}
|
|
|
|
nsStyleOutline::nsStyleOutline(nsPresContext* aPresContext)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleOutline);
|
|
// spacing values not inherited
|
|
nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
|
|
NS_FOR_CSS_HALF_CORNERS(corner) {
|
|
mOutlineRadius.Set(corner, zero);
|
|
}
|
|
|
|
mOutlineOffset = 0;
|
|
|
|
mOutlineWidth = nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
|
|
mOutlineStyle = NS_STYLE_BORDER_STYLE_NONE;
|
|
mOutlineColor = NS_RGB(0, 0, 0);
|
|
|
|
mHasCachedOutline = false;
|
|
mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
|
|
}
|
|
|
|
nsStyleOutline::nsStyleOutline(const nsStyleOutline& aSrc) {
|
|
MOZ_COUNT_CTOR(nsStyleOutline);
|
|
memcpy((nsStyleOutline*)this, &aSrc, sizeof(nsStyleOutline));
|
|
}
|
|
|
|
void
|
|
nsStyleOutline::RecalcData(nsPresContext* aContext)
|
|
{
|
|
if (NS_STYLE_BORDER_STYLE_NONE == GetOutlineStyle()) {
|
|
mCachedOutlineWidth = 0;
|
|
mHasCachedOutline = true;
|
|
} else if (IsFixedUnit(mOutlineWidth, true)) {
|
|
// Clamp negative calc() to 0.
|
|
mCachedOutlineWidth =
|
|
std::max(CalcCoord(mOutlineWidth, aContext->GetBorderWidthTable(), 3), 0);
|
|
mCachedOutlineWidth =
|
|
NS_ROUND_BORDER_TO_PIXELS(mCachedOutlineWidth, mTwipsPerPixel);
|
|
mHasCachedOutline = true;
|
|
}
|
|
else
|
|
mHasCachedOutline = false;
|
|
}
|
|
|
|
nsChangeHint nsStyleOutline::CalcDifference(const nsStyleOutline& aOther) const
|
|
{
|
|
bool outlineWasVisible =
|
|
mCachedOutlineWidth > 0 && mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE;
|
|
bool outlineIsVisible =
|
|
aOther.mCachedOutlineWidth > 0 && aOther.mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE;
|
|
if (outlineWasVisible != outlineIsVisible ||
|
|
(outlineIsVisible && (mOutlineOffset != aOther.mOutlineOffset ||
|
|
mOutlineWidth != aOther.mOutlineWidth ||
|
|
mTwipsPerPixel != aOther.mTwipsPerPixel))) {
|
|
return NS_CombineHint(nsChangeHint_AllReflowHints,
|
|
nsChangeHint_RepaintFrame);
|
|
}
|
|
if ((mOutlineStyle != aOther.mOutlineStyle) ||
|
|
(mOutlineColor != aOther.mOutlineColor) ||
|
|
(mOutlineRadius != aOther.mOutlineRadius)) {
|
|
return nsChangeHint_RepaintFrame;
|
|
}
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleList
|
|
//
|
|
nsStyleList::nsStyleList()
|
|
: mListStyleType(NS_STYLE_LIST_STYLE_DISC),
|
|
mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleList);
|
|
}
|
|
|
|
nsStyleList::~nsStyleList()
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleList);
|
|
}
|
|
|
|
nsStyleList::nsStyleList(const nsStyleList& aSource)
|
|
: mListStyleType(aSource.mListStyleType),
|
|
mListStylePosition(aSource.mListStylePosition),
|
|
mImageRegion(aSource.mImageRegion)
|
|
{
|
|
SetListStyleImage(aSource.GetListStyleImage());
|
|
MOZ_COUNT_CTOR(nsStyleList);
|
|
}
|
|
|
|
nsChangeHint nsStyleList::CalcDifference(const nsStyleList& aOther) const
|
|
{
|
|
if (mListStylePosition != aOther.mListStylePosition)
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
if (EqualImages(mListStyleImage, aOther.mListStyleImage) &&
|
|
mListStyleType == aOther.mListStyleType) {
|
|
if (mImageRegion.IsEqualInterior(aOther.mImageRegion))
|
|
return NS_STYLE_HINT_NONE;
|
|
if (mImageRegion.width == aOther.mImageRegion.width &&
|
|
mImageRegion.height == aOther.mImageRegion.height)
|
|
return NS_STYLE_HINT_VISUAL;
|
|
}
|
|
return NS_STYLE_HINT_REFLOW;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleXUL
|
|
//
|
|
nsStyleXUL::nsStyleXUL()
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleXUL);
|
|
mBoxAlign = NS_STYLE_BOX_ALIGN_STRETCH;
|
|
mBoxDirection = NS_STYLE_BOX_DIRECTION_NORMAL;
|
|
mBoxFlex = 0.0f;
|
|
mBoxOrient = NS_STYLE_BOX_ORIENT_HORIZONTAL;
|
|
mBoxPack = NS_STYLE_BOX_PACK_START;
|
|
mBoxOrdinal = 1;
|
|
mStretchStack = true;
|
|
}
|
|
|
|
nsStyleXUL::~nsStyleXUL()
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleXUL);
|
|
}
|
|
|
|
nsStyleXUL::nsStyleXUL(const nsStyleXUL& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleXUL);
|
|
memcpy((nsStyleXUL*)this, &aSource, sizeof(nsStyleXUL));
|
|
}
|
|
|
|
nsChangeHint nsStyleXUL::CalcDifference(const nsStyleXUL& aOther) const
|
|
{
|
|
if (mBoxAlign == aOther.mBoxAlign &&
|
|
mBoxDirection == aOther.mBoxDirection &&
|
|
mBoxFlex == aOther.mBoxFlex &&
|
|
mBoxOrient == aOther.mBoxOrient &&
|
|
mBoxPack == aOther.mBoxPack &&
|
|
mBoxOrdinal == aOther.mBoxOrdinal &&
|
|
mStretchStack == aOther.mStretchStack)
|
|
return NS_STYLE_HINT_NONE;
|
|
if (mBoxOrdinal != aOther.mBoxOrdinal)
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
return NS_STYLE_HINT_REFLOW;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleColumn
|
|
//
|
|
/* static */ const uint32_t nsStyleColumn::kMaxColumnCount = 1000;
|
|
|
|
nsStyleColumn::nsStyleColumn(nsPresContext* aPresContext)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleColumn);
|
|
mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
|
|
mColumnWidth.SetAutoValue();
|
|
mColumnGap.SetNormalValue();
|
|
mColumnFill = NS_STYLE_COLUMN_FILL_BALANCE;
|
|
|
|
mColumnRuleWidth = (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
|
|
mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
|
|
mColumnRuleColor = NS_RGB(0, 0, 0);
|
|
mColumnRuleColorIsForeground = true;
|
|
|
|
mTwipsPerPixel = aPresContext->AppUnitsPerDevPixel();
|
|
}
|
|
|
|
nsStyleColumn::~nsStyleColumn()
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleColumn);
|
|
}
|
|
|
|
nsStyleColumn::nsStyleColumn(const nsStyleColumn& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleColumn);
|
|
memcpy((nsStyleColumn*)this, &aSource, sizeof(nsStyleColumn));
|
|
}
|
|
|
|
nsChangeHint nsStyleColumn::CalcDifference(const nsStyleColumn& aOther) const
|
|
{
|
|
if ((mColumnWidth.GetUnit() == eStyleUnit_Auto)
|
|
!= (aOther.mColumnWidth.GetUnit() == eStyleUnit_Auto) ||
|
|
mColumnCount != aOther.mColumnCount)
|
|
// We force column count changes to do a reframe, because it's tricky to handle
|
|
// some edge cases where the column count gets smaller and content overflows.
|
|
// XXX not ideal
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
|
|
if (mColumnWidth != aOther.mColumnWidth ||
|
|
mColumnGap != aOther.mColumnGap ||
|
|
mColumnFill != aOther.mColumnFill)
|
|
return NS_STYLE_HINT_REFLOW;
|
|
|
|
if (GetComputedColumnRuleWidth() != aOther.GetComputedColumnRuleWidth() ||
|
|
mColumnRuleStyle != aOther.mColumnRuleStyle ||
|
|
mColumnRuleColor != aOther.mColumnRuleColor ||
|
|
mColumnRuleColorIsForeground != aOther.mColumnRuleColorIsForeground)
|
|
return NS_STYLE_HINT_VISUAL;
|
|
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleSVG
|
|
//
|
|
nsStyleSVG::nsStyleSVG()
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleSVG);
|
|
mFill.mType = eStyleSVGPaintType_Color;
|
|
mFill.mPaint.mColor = NS_RGB(0,0,0);
|
|
mFill.mFallbackColor = NS_RGB(0,0,0);
|
|
mStroke.mType = eStyleSVGPaintType_None;
|
|
mStroke.mPaint.mColor = NS_RGB(0,0,0);
|
|
mStroke.mFallbackColor = NS_RGB(0,0,0);
|
|
mStrokeDasharray = nullptr;
|
|
|
|
mStrokeDashoffset.SetCoordValue(0);
|
|
mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
|
|
|
|
mFillOpacity = 1.0f;
|
|
mStrokeMiterlimit = 4.0f;
|
|
mStrokeOpacity = 1.0f;
|
|
|
|
mStrokeDasharrayLength = 0;
|
|
mClipRule = NS_STYLE_FILL_RULE_NONZERO;
|
|
mColorInterpolation = NS_STYLE_COLOR_INTERPOLATION_SRGB;
|
|
mColorInterpolationFilters = NS_STYLE_COLOR_INTERPOLATION_LINEARRGB;
|
|
mFillRule = NS_STYLE_FILL_RULE_NONZERO;
|
|
mImageRendering = NS_STYLE_IMAGE_RENDERING_AUTO;
|
|
mPaintOrder = NS_STYLE_PAINT_ORDER_NORMAL;
|
|
mShapeRendering = NS_STYLE_SHAPE_RENDERING_AUTO;
|
|
mStrokeLinecap = NS_STYLE_STROKE_LINECAP_BUTT;
|
|
mStrokeLinejoin = NS_STYLE_STROKE_LINEJOIN_MITER;
|
|
mTextAnchor = NS_STYLE_TEXT_ANCHOR_START;
|
|
mTextRendering = NS_STYLE_TEXT_RENDERING_AUTO;
|
|
mFillOpacitySource = eStyleSVGOpacitySource_Normal;
|
|
mStrokeOpacitySource = eStyleSVGOpacitySource_Normal;
|
|
mStrokeDasharrayFromObject = false;
|
|
mStrokeDashoffsetFromObject = false;
|
|
mStrokeWidthFromObject = false;
|
|
}
|
|
|
|
nsStyleSVG::~nsStyleSVG()
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleSVG);
|
|
delete [] mStrokeDasharray;
|
|
}
|
|
|
|
nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleSVG);
|
|
mFill = aSource.mFill;
|
|
mStroke = aSource.mStroke;
|
|
|
|
mMarkerEnd = aSource.mMarkerEnd;
|
|
mMarkerMid = aSource.mMarkerMid;
|
|
mMarkerStart = aSource.mMarkerStart;
|
|
|
|
mStrokeDasharrayLength = aSource.mStrokeDasharrayLength;
|
|
if (aSource.mStrokeDasharray) {
|
|
mStrokeDasharray = new nsStyleCoord[mStrokeDasharrayLength];
|
|
if (mStrokeDasharray)
|
|
memcpy(mStrokeDasharray,
|
|
aSource.mStrokeDasharray,
|
|
mStrokeDasharrayLength * sizeof(nsStyleCoord));
|
|
else
|
|
mStrokeDasharrayLength = 0;
|
|
} else {
|
|
mStrokeDasharray = nullptr;
|
|
}
|
|
|
|
mStrokeDashoffset = aSource.mStrokeDashoffset;
|
|
mStrokeWidth = aSource.mStrokeWidth;
|
|
|
|
mFillOpacity = aSource.mFillOpacity;
|
|
mStrokeMiterlimit = aSource.mStrokeMiterlimit;
|
|
mStrokeOpacity = aSource.mStrokeOpacity;
|
|
|
|
mClipRule = aSource.mClipRule;
|
|
mColorInterpolation = aSource.mColorInterpolation;
|
|
mColorInterpolationFilters = aSource.mColorInterpolationFilters;
|
|
mFillRule = aSource.mFillRule;
|
|
mImageRendering = aSource.mImageRendering;
|
|
mPaintOrder = aSource.mPaintOrder;
|
|
mShapeRendering = aSource.mShapeRendering;
|
|
mStrokeLinecap = aSource.mStrokeLinecap;
|
|
mStrokeLinejoin = aSource.mStrokeLinejoin;
|
|
mTextAnchor = aSource.mTextAnchor;
|
|
mTextRendering = aSource.mTextRendering;
|
|
mFillOpacitySource = aSource.mFillOpacitySource;
|
|
mStrokeOpacitySource = aSource.mStrokeOpacitySource;
|
|
mStrokeDasharrayFromObject = aSource.mStrokeDasharrayFromObject;
|
|
mStrokeDashoffsetFromObject = aSource.mStrokeDashoffsetFromObject;
|
|
mStrokeWidthFromObject = aSource.mStrokeWidthFromObject;
|
|
}
|
|
|
|
static bool PaintURIChanged(const nsStyleSVGPaint& aPaint1,
|
|
const nsStyleSVGPaint& aPaint2)
|
|
{
|
|
if (aPaint1.mType != aPaint2.mType) {
|
|
return aPaint1.mType == eStyleSVGPaintType_Server ||
|
|
aPaint2.mType == eStyleSVGPaintType_Server;
|
|
}
|
|
return aPaint1.mType == eStyleSVGPaintType_Server &&
|
|
!EqualURIs(aPaint1.mPaint.mPaintServer, aPaint2.mPaint.mPaintServer);
|
|
}
|
|
|
|
nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aOther) const
|
|
{
|
|
nsChangeHint hint = nsChangeHint(0);
|
|
|
|
if (!EqualURIs(mMarkerEnd, aOther.mMarkerEnd) ||
|
|
!EqualURIs(mMarkerMid, aOther.mMarkerMid) ||
|
|
!EqualURIs(mMarkerStart, aOther.mMarkerStart)) {
|
|
// Markers currently contribute to nsSVGPathGeometryFrame::mRect,
|
|
// so we need a reflow as well as a repaint. No intrinsic sizes need
|
|
// to change, so nsChangeHint_NeedReflow is sufficient.
|
|
NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
|
|
NS_UpdateHint(hint, nsChangeHint_NeedReflow);
|
|
NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
|
|
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
|
return hint;
|
|
}
|
|
|
|
if (mFill != aOther.mFill ||
|
|
mStroke != aOther.mStroke ||
|
|
mFillOpacity != aOther.mFillOpacity ||
|
|
mStrokeOpacity != aOther.mStrokeOpacity) {
|
|
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
|
if (HasStroke() != aOther.HasStroke() ||
|
|
(!HasStroke() && HasFill() != aOther.HasFill())) {
|
|
// Frame bounds and overflow rects depend on whether we "have" fill or
|
|
// stroke. Whether we have stroke or not just changed, or else we have no
|
|
// stroke (in which case whether we have fill or not is significant to frame
|
|
// bounds) and whether we have fill or not just changed. In either case we
|
|
// need to reflow so the frame rect is updated.
|
|
// XXXperf this is a waste on non nsSVGPathGeometryFrames.
|
|
NS_UpdateHint(hint, nsChangeHint_NeedReflow);
|
|
NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
|
|
}
|
|
if (PaintURIChanged(mFill, aOther.mFill) ||
|
|
PaintURIChanged(mStroke, aOther.mStroke)) {
|
|
NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
|
|
}
|
|
}
|
|
|
|
// Stroke currently contributes to nsSVGPathGeometryFrame::mRect, so
|
|
// we need a reflow here. No intrinsic sizes need to change, so
|
|
// nsChangeHint_NeedReflow is sufficient.
|
|
// Note that stroke-dashoffset does not affect nsSVGPathGeometryFrame::mRect.
|
|
// text-anchor and text-rendering changes also require a reflow since they
|
|
// change frames' rects.
|
|
if (mStrokeWidth != aOther.mStrokeWidth ||
|
|
mStrokeMiterlimit != aOther.mStrokeMiterlimit ||
|
|
mStrokeLinecap != aOther.mStrokeLinecap ||
|
|
mStrokeLinejoin != aOther.mStrokeLinejoin ||
|
|
mTextAnchor != aOther.mTextAnchor ||
|
|
mTextRendering != aOther.mTextRendering) {
|
|
NS_UpdateHint(hint, nsChangeHint_NeedReflow);
|
|
NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
|
|
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
|
return hint;
|
|
}
|
|
|
|
if (hint & nsChangeHint_RepaintFrame) {
|
|
return hint; // we don't add anything else below
|
|
}
|
|
|
|
if ( mStrokeDashoffset != aOther.mStrokeDashoffset ||
|
|
mClipRule != aOther.mClipRule ||
|
|
mColorInterpolation != aOther.mColorInterpolation ||
|
|
mColorInterpolationFilters != aOther.mColorInterpolationFilters ||
|
|
mFillRule != aOther.mFillRule ||
|
|
mImageRendering != aOther.mImageRendering ||
|
|
mPaintOrder != aOther.mPaintOrder ||
|
|
mShapeRendering != aOther.mShapeRendering ||
|
|
mStrokeDasharrayLength != aOther.mStrokeDasharrayLength ||
|
|
mFillOpacitySource != aOther.mFillOpacitySource ||
|
|
mStrokeOpacitySource != aOther.mStrokeOpacitySource ||
|
|
mStrokeDasharrayFromObject != aOther.mStrokeDasharrayFromObject ||
|
|
mStrokeDashoffsetFromObject != aOther.mStrokeDashoffsetFromObject ||
|
|
mStrokeWidthFromObject != aOther.mStrokeWidthFromObject) {
|
|
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
|
return hint;
|
|
}
|
|
|
|
// length of stroke dasharrays are the same (tested above) - check entries
|
|
for (uint32_t i=0; i<mStrokeDasharrayLength; i++)
|
|
if (mStrokeDasharray[i] != aOther.mStrokeDasharray[i]) {
|
|
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
|
return hint;
|
|
}
|
|
|
|
return hint;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleFilter
|
|
//
|
|
nsStyleFilter::nsStyleFilter()
|
|
: mType(NS_STYLE_FILTER_NONE)
|
|
, mDropShadow(nullptr)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleFilter);
|
|
}
|
|
|
|
nsStyleFilter::nsStyleFilter(const nsStyleFilter& aSource)
|
|
: mType(NS_STYLE_FILTER_NONE)
|
|
, mDropShadow(nullptr)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleFilter);
|
|
if (aSource.mType == NS_STYLE_FILTER_URL) {
|
|
SetURL(aSource.mURL);
|
|
} else if (aSource.mType == NS_STYLE_FILTER_DROP_SHADOW) {
|
|
SetDropShadow(aSource.mDropShadow);
|
|
} else if (aSource.mType != NS_STYLE_FILTER_NONE) {
|
|
SetFilterParameter(aSource.mFilterParameter, aSource.mType);
|
|
}
|
|
}
|
|
|
|
nsStyleFilter::~nsStyleFilter()
|
|
{
|
|
ReleaseRef();
|
|
MOZ_COUNT_DTOR(nsStyleFilter);
|
|
}
|
|
|
|
nsStyleFilter&
|
|
nsStyleFilter::operator=(const nsStyleFilter& aOther)
|
|
{
|
|
if (this == &aOther)
|
|
return *this;
|
|
|
|
if (aOther.mType == NS_STYLE_FILTER_URL) {
|
|
SetURL(aOther.mURL);
|
|
} else if (aOther.mType == NS_STYLE_FILTER_DROP_SHADOW) {
|
|
SetDropShadow(aOther.mDropShadow);
|
|
} else if (aOther.mType != NS_STYLE_FILTER_NONE) {
|
|
SetFilterParameter(aOther.mFilterParameter, aOther.mType);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
bool
|
|
nsStyleFilter::operator==(const nsStyleFilter& aOther) const
|
|
{
|
|
if (mType != aOther.mType) {
|
|
return false;
|
|
}
|
|
|
|
if (mType == NS_STYLE_FILTER_URL) {
|
|
return EqualURIs(mURL, aOther.mURL);
|
|
} else if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
|
|
return *mDropShadow == *aOther.mDropShadow;
|
|
} else if (mType != NS_STYLE_FILTER_NONE) {
|
|
return mFilterParameter == aOther.mFilterParameter;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
nsStyleFilter::ReleaseRef()
|
|
{
|
|
if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
|
|
NS_ASSERTION(mDropShadow, "expected pointer");
|
|
mDropShadow->Release();
|
|
} else if (mType == NS_STYLE_FILTER_URL) {
|
|
NS_ASSERTION(mURL, "expected pointer");
|
|
mURL->Release();
|
|
}
|
|
}
|
|
|
|
void
|
|
nsStyleFilter::SetFilterParameter(const nsStyleCoord& aFilterParameter,
|
|
int32_t aType)
|
|
{
|
|
ReleaseRef();
|
|
mFilterParameter = aFilterParameter;
|
|
mType = aType;
|
|
}
|
|
|
|
void
|
|
nsStyleFilter::SetURL(nsIURI* aURL)
|
|
{
|
|
NS_ASSERTION(aURL, "expected pointer");
|
|
ReleaseRef();
|
|
mURL = aURL;
|
|
mURL->AddRef();
|
|
mType = NS_STYLE_FILTER_URL;
|
|
}
|
|
|
|
void
|
|
nsStyleFilter::SetDropShadow(nsCSSShadowArray* aDropShadow)
|
|
{
|
|
NS_ASSERTION(aDropShadow, "expected pointer");
|
|
ReleaseRef();
|
|
mDropShadow = aDropShadow;
|
|
mDropShadow->AddRef();
|
|
mType = NS_STYLE_FILTER_DROP_SHADOW;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleSVGReset
|
|
//
|
|
nsStyleSVGReset::nsStyleSVGReset()
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleSVGReset);
|
|
mStopColor = NS_RGB(0,0,0);
|
|
mFloodColor = NS_RGB(0,0,0);
|
|
mLightingColor = NS_RGB(255,255,255);
|
|
mClipPath = nullptr;
|
|
mMask = nullptr;
|
|
mStopOpacity = 1.0f;
|
|
mFloodOpacity = 1.0f;
|
|
mDominantBaseline = NS_STYLE_DOMINANT_BASELINE_AUTO;
|
|
mVectorEffect = NS_STYLE_VECTOR_EFFECT_NONE;
|
|
mMaskType = NS_STYLE_MASK_TYPE_LUMINANCE;
|
|
}
|
|
|
|
nsStyleSVGReset::~nsStyleSVGReset()
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleSVGReset);
|
|
}
|
|
|
|
nsStyleSVGReset::nsStyleSVGReset(const nsStyleSVGReset& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleSVGReset);
|
|
mStopColor = aSource.mStopColor;
|
|
mFloodColor = aSource.mFloodColor;
|
|
mLightingColor = aSource.mLightingColor;
|
|
mClipPath = aSource.mClipPath;
|
|
mFilters = aSource.mFilters;
|
|
mMask = aSource.mMask;
|
|
mStopOpacity = aSource.mStopOpacity;
|
|
mFloodOpacity = aSource.mFloodOpacity;
|
|
mDominantBaseline = aSource.mDominantBaseline;
|
|
mVectorEffect = aSource.mVectorEffect;
|
|
mMaskType = aSource.mMaskType;
|
|
}
|
|
|
|
nsChangeHint nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aOther) const
|
|
{
|
|
nsChangeHint hint = nsChangeHint(0);
|
|
|
|
bool equalFilters = (mFilters == aOther.mFilters);
|
|
|
|
if (!equalFilters) {
|
|
NS_UpdateHint(hint, nsChangeHint_UpdateOverflow);
|
|
}
|
|
|
|
if (!EqualURIs(mClipPath, aOther.mClipPath) ||
|
|
!EqualURIs(mMask, aOther.mMask) ||
|
|
!equalFilters) {
|
|
NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
|
|
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
|
}
|
|
|
|
if (mDominantBaseline != aOther.mDominantBaseline) {
|
|
// XXXjwatt: why NS_STYLE_HINT_REFLOW? Isn't that excessive?
|
|
NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
|
|
} else if (mVectorEffect != aOther.mVectorEffect) {
|
|
// Stroke currently affects nsSVGPathGeometryFrame::mRect, and
|
|
// vector-effect affect stroke. As a result we need to reflow if
|
|
// vector-effect changes in order to have nsSVGPathGeometryFrame::
|
|
// ReflowSVG called to update its mRect. No intrinsic sizes need
|
|
// to change so nsChangeHint_NeedReflow is sufficient.
|
|
NS_UpdateHint(hint, nsChangeHint_NeedReflow);
|
|
NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
|
|
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
|
} else if (mStopColor != aOther.mStopColor ||
|
|
mFloodColor != aOther.mFloodColor ||
|
|
mLightingColor != aOther.mLightingColor ||
|
|
mStopOpacity != aOther.mStopOpacity ||
|
|
mFloodOpacity != aOther.mFloodOpacity ||
|
|
mMaskType != aOther.mMaskType) {
|
|
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
|
}
|
|
|
|
return hint;
|
|
}
|
|
|
|
// nsStyleSVGPaint implementation
|
|
nsStyleSVGPaint::~nsStyleSVGPaint()
|
|
{
|
|
if (mType == eStyleSVGPaintType_Server) {
|
|
NS_IF_RELEASE(mPaint.mPaintServer);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsStyleSVGPaint::SetType(nsStyleSVGPaintType aType)
|
|
{
|
|
if (mType == eStyleSVGPaintType_Server) {
|
|
this->~nsStyleSVGPaint();
|
|
new (this) nsStyleSVGPaint();
|
|
}
|
|
mType = aType;
|
|
}
|
|
|
|
nsStyleSVGPaint& nsStyleSVGPaint::operator=(const nsStyleSVGPaint& aOther)
|
|
{
|
|
if (this == &aOther)
|
|
return *this;
|
|
|
|
SetType(aOther.mType);
|
|
|
|
mFallbackColor = aOther.mFallbackColor;
|
|
if (mType == eStyleSVGPaintType_Server) {
|
|
mPaint.mPaintServer = aOther.mPaint.mPaintServer;
|
|
NS_IF_ADDREF(mPaint.mPaintServer);
|
|
} else {
|
|
mPaint.mColor = aOther.mPaint.mColor;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool nsStyleSVGPaint::operator==(const nsStyleSVGPaint& aOther) const
|
|
{
|
|
if (mType != aOther.mType)
|
|
return false;
|
|
if (mType == eStyleSVGPaintType_Server)
|
|
return EqualURIs(mPaint.mPaintServer, aOther.mPaint.mPaintServer) &&
|
|
mFallbackColor == aOther.mFallbackColor;
|
|
if (mType == eStyleSVGPaintType_Color)
|
|
return mPaint.mColor == aOther.mPaint.mColor;
|
|
return true;
|
|
}
|
|
|
|
|
|
// --------------------
|
|
// nsStylePosition
|
|
//
|
|
nsStylePosition::nsStylePosition(void)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStylePosition);
|
|
// positioning values not inherited
|
|
nsStyleCoord autoCoord(eStyleUnit_Auto);
|
|
mOffset.SetLeft(autoCoord);
|
|
mOffset.SetTop(autoCoord);
|
|
mOffset.SetRight(autoCoord);
|
|
mOffset.SetBottom(autoCoord);
|
|
mWidth.SetAutoValue();
|
|
mMinWidth.SetCoordValue(0);
|
|
mMaxWidth.SetNoneValue();
|
|
mHeight.SetAutoValue();
|
|
mMinHeight.SetCoordValue(0);
|
|
mMaxHeight.SetNoneValue();
|
|
mFlexBasis.SetAutoValue();
|
|
mBoxSizing = NS_STYLE_BOX_SIZING_CONTENT;
|
|
mAlignContent = NS_STYLE_ALIGN_CONTENT_STRETCH;
|
|
mAlignItems = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
|
|
mAlignSelf = NS_STYLE_ALIGN_SELF_AUTO;
|
|
mFlexDirection = NS_STYLE_FLEX_DIRECTION_ROW;
|
|
mFlexWrap = NS_STYLE_FLEX_WRAP_NOWRAP;
|
|
mJustifyContent = NS_STYLE_JUSTIFY_CONTENT_FLEX_START;
|
|
mOrder = NS_STYLE_ORDER_INITIAL;
|
|
mFlexGrow = 0.0f;
|
|
mFlexShrink = 1.0f;
|
|
mZIndex.SetAutoValue();
|
|
}
|
|
|
|
nsStylePosition::~nsStylePosition(void)
|
|
{
|
|
MOZ_COUNT_DTOR(nsStylePosition);
|
|
}
|
|
|
|
nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStylePosition);
|
|
memcpy((nsStylePosition*)this, &aSource, sizeof(nsStylePosition));
|
|
}
|
|
|
|
static bool
|
|
IsAutonessEqual(const nsStyleSides& aSides1, const nsStyleSides& aSides2)
|
|
{
|
|
NS_FOR_CSS_SIDES(side) {
|
|
if ((aSides1.GetUnit(side) == eStyleUnit_Auto) !=
|
|
(aSides2.GetUnit(side) == eStyleUnit_Auto)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) const
|
|
{
|
|
nsChangeHint hint =
|
|
(mZIndex == aOther.mZIndex) ? NS_STYLE_HINT_NONE : nsChangeHint_RepaintFrame;
|
|
|
|
if (mBoxSizing != aOther.mBoxSizing) {
|
|
// Can affect both widths and heights; just a bad scene.
|
|
return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
|
|
}
|
|
|
|
// Properties that apply to flex items:
|
|
// NOTE: Changes to "order" on a flex item may trigger some repositioning.
|
|
// If we're in a multi-line flex container, it also may affect our size
|
|
// (and that of our container & siblings) by shuffling items between lines.
|
|
if (mAlignSelf != aOther.mAlignSelf ||
|
|
mFlexBasis != aOther.mFlexBasis ||
|
|
mFlexGrow != aOther.mFlexGrow ||
|
|
mFlexShrink != aOther.mFlexShrink ||
|
|
mOrder != aOther.mOrder) {
|
|
return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
|
|
}
|
|
|
|
// Properties that apply to flex containers:
|
|
// - flex-direction can swap a flex container between vertical & horizontal.
|
|
// - align-items can change the sizing of a flex container & the positioning
|
|
// of its children.
|
|
// - flex-wrap changes whether a flex container's children are wrapped, which
|
|
// impacts their sizing/positioning and hence impacts the container's size.
|
|
if (mAlignItems != aOther.mAlignItems ||
|
|
mFlexDirection != aOther.mFlexDirection ||
|
|
mFlexWrap != aOther.mFlexWrap) {
|
|
return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
|
|
}
|
|
|
|
|
|
// Changing justify-content on a flexbox might affect the positioning of its
|
|
// children, but it won't affect any sizing.
|
|
if (mJustifyContent != aOther.mJustifyContent) {
|
|
NS_UpdateHint(hint, nsChangeHint_NeedReflow);
|
|
}
|
|
|
|
// Properties that apply only to multi-line flex containers:
|
|
// 'align-content' can change the positioning & sizing of a multi-line flex
|
|
// container's children when there's extra space in the cross axis, but it
|
|
// shouldn't affect the container's own sizing.
|
|
//
|
|
// NOTE: If we get here, we know that mFlexWrap == aOther.mFlexWrap
|
|
// (otherwise, we would've returned earlier). So it doesn't matter which one
|
|
// of those we check to see if we're multi-line.
|
|
if (mFlexWrap != NS_STYLE_FLEX_WRAP_NOWRAP &&
|
|
mAlignContent != aOther.mAlignContent) {
|
|
NS_UpdateHint(hint, nsChangeHint_NeedReflow);
|
|
}
|
|
|
|
if (mHeight != aOther.mHeight ||
|
|
mMinHeight != aOther.mMinHeight ||
|
|
mMaxHeight != aOther.mMaxHeight) {
|
|
// Height changes can affect descendant intrinsic sizes due to replaced
|
|
// elements with percentage heights in descendants which also have
|
|
// percentage heights. And due to our not-so-great computation of mVResize
|
|
// in nsHTMLReflowState, they do need to force reflow of the whole subtree.
|
|
// XXXbz due to XUL caching heights as well, height changes also need to
|
|
// clear ancestor intrinsics!
|
|
return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
|
|
}
|
|
|
|
if (mWidth != aOther.mWidth ||
|
|
mMinWidth != aOther.mMinWidth ||
|
|
mMaxWidth != aOther.mMaxWidth) {
|
|
// None of our width differences can affect descendant intrinsic
|
|
// sizes and none of them need to force children to reflow.
|
|
return
|
|
NS_CombineHint(hint,
|
|
NS_SubtractHint(nsChangeHint_AllReflowHints,
|
|
NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
|
|
nsChangeHint_NeedDirtyReflow)));
|
|
}
|
|
|
|
// If width and height have not changed, but any of the offsets have changed,
|
|
// then return the respective hints so that we would hopefully be able to
|
|
// avoid reflowing.
|
|
// Note that it is possible that we'll need to reflow when processing
|
|
// restyles, but we don't have enough information to make a good decision
|
|
// right now.
|
|
// Don't try to handle changes between "auto" and non-auto efficiently;
|
|
// that's tricky to do and will hardly ever be able to avoid a reflow.
|
|
if (mOffset != aOther.mOffset) {
|
|
if (IsAutonessEqual(mOffset, aOther.mOffset)) {
|
|
NS_UpdateHint(hint, nsChangeHint(nsChangeHint_RecomputePosition |
|
|
nsChangeHint_UpdateOverflow));
|
|
} else {
|
|
return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
|
|
}
|
|
}
|
|
return hint;
|
|
}
|
|
|
|
/* static */ bool
|
|
nsStylePosition::WidthCoordDependsOnContainer(const nsStyleCoord &aCoord)
|
|
{
|
|
return aCoord.GetUnit() == eStyleUnit_Auto ||
|
|
aCoord.HasPercent() ||
|
|
(aCoord.GetUnit() == eStyleUnit_Enumerated &&
|
|
(aCoord.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT ||
|
|
aCoord.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE));
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleTable
|
|
//
|
|
|
|
nsStyleTable::nsStyleTable()
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleTable);
|
|
// values not inherited
|
|
mLayoutStrategy = NS_STYLE_TABLE_LAYOUT_AUTO;
|
|
mFrame = NS_STYLE_TABLE_FRAME_NONE;
|
|
mRules = NS_STYLE_TABLE_RULES_NONE;
|
|
mSpan = 1;
|
|
}
|
|
|
|
nsStyleTable::~nsStyleTable(void)
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleTable);
|
|
}
|
|
|
|
nsStyleTable::nsStyleTable(const nsStyleTable& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleTable);
|
|
memcpy((nsStyleTable*)this, &aSource, sizeof(nsStyleTable));
|
|
}
|
|
|
|
nsChangeHint nsStyleTable::CalcDifference(const nsStyleTable& aOther) const
|
|
{
|
|
// Changes in mRules may require reframing (if border-collapse stuff changes, for example).
|
|
if (mRules != aOther.mRules || mSpan != aOther.mSpan ||
|
|
mLayoutStrategy != aOther.mLayoutStrategy)
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
if (mFrame != aOther.mFrame)
|
|
return NS_STYLE_HINT_REFLOW;
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
|
|
// -----------------------
|
|
// nsStyleTableBorder
|
|
|
|
nsStyleTableBorder::nsStyleTableBorder(nsPresContext* aPresContext)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleTableBorder);
|
|
mBorderCollapse = NS_STYLE_BORDER_SEPARATE;
|
|
|
|
nsCompatibility compatMode = eCompatibility_FullStandards;
|
|
if (aPresContext)
|
|
compatMode = aPresContext->CompatibilityMode();
|
|
mEmptyCells = (compatMode == eCompatibility_NavQuirks)
|
|
? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
|
|
: NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
|
|
mCaptionSide = NS_STYLE_CAPTION_SIDE_TOP;
|
|
mBorderSpacingX = 0;
|
|
mBorderSpacingY = 0;
|
|
}
|
|
|
|
nsStyleTableBorder::~nsStyleTableBorder(void)
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleTableBorder);
|
|
}
|
|
|
|
nsStyleTableBorder::nsStyleTableBorder(const nsStyleTableBorder& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleTableBorder);
|
|
memcpy((nsStyleTableBorder*)this, &aSource, sizeof(nsStyleTableBorder));
|
|
}
|
|
|
|
nsChangeHint nsStyleTableBorder::CalcDifference(const nsStyleTableBorder& aOther) const
|
|
{
|
|
// Border-collapse changes need a reframe, because we use a different frame
|
|
// class for table cells in the collapsed border model. This is used to
|
|
// conserve memory when using the separated border model (collapsed borders
|
|
// require extra state to be stored).
|
|
if (mBorderCollapse != aOther.mBorderCollapse) {
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
}
|
|
|
|
if ((mCaptionSide == aOther.mCaptionSide) &&
|
|
(mBorderSpacingX == aOther.mBorderSpacingX) &&
|
|
(mBorderSpacingY == aOther.mBorderSpacingY)) {
|
|
if (mEmptyCells == aOther.mEmptyCells)
|
|
return NS_STYLE_HINT_NONE;
|
|
return NS_STYLE_HINT_VISUAL;
|
|
}
|
|
else
|
|
return NS_STYLE_HINT_REFLOW;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleColor
|
|
//
|
|
|
|
nsStyleColor::nsStyleColor(nsPresContext* aPresContext)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleColor);
|
|
mColor = aPresContext->DefaultColor();
|
|
}
|
|
|
|
nsStyleColor::nsStyleColor(const nsStyleColor& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleColor);
|
|
mColor = aSource.mColor;
|
|
}
|
|
|
|
nsChangeHint nsStyleColor::CalcDifference(const nsStyleColor& aOther) const
|
|
{
|
|
if (mColor == aOther.mColor)
|
|
return NS_STYLE_HINT_NONE;
|
|
return NS_STYLE_HINT_VISUAL;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleGradient
|
|
//
|
|
bool
|
|
nsStyleGradient::operator==(const nsStyleGradient& aOther) const
|
|
{
|
|
NS_ABORT_IF_FALSE(mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER ||
|
|
mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR,
|
|
"incorrect combination of shape and size");
|
|
NS_ABORT_IF_FALSE(aOther.mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER ||
|
|
aOther.mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR,
|
|
"incorrect combination of shape and size");
|
|
|
|
if (mShape != aOther.mShape ||
|
|
mSize != aOther.mSize ||
|
|
mRepeating != aOther.mRepeating ||
|
|
mLegacySyntax != aOther.mLegacySyntax ||
|
|
mBgPosX != aOther.mBgPosX ||
|
|
mBgPosY != aOther.mBgPosY ||
|
|
mAngle != aOther.mAngle ||
|
|
mRadiusX != aOther.mRadiusX ||
|
|
mRadiusY != aOther.mRadiusY)
|
|
return false;
|
|
|
|
if (mStops.Length() != aOther.mStops.Length())
|
|
return false;
|
|
|
|
for (uint32_t i = 0; i < mStops.Length(); i++) {
|
|
if (mStops[i].mLocation != aOther.mStops[i].mLocation ||
|
|
mStops[i].mColor != aOther.mStops[i].mColor)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
nsStyleGradient::nsStyleGradient(void)
|
|
: mShape(NS_STYLE_GRADIENT_SHAPE_LINEAR)
|
|
, mSize(NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)
|
|
, mRepeating(false)
|
|
, mLegacySyntax(false)
|
|
{
|
|
}
|
|
|
|
bool
|
|
nsStyleGradient::IsOpaque()
|
|
{
|
|
for (uint32_t i = 0; i < mStops.Length(); i++) {
|
|
if (NS_GET_A(mStops[i].mColor) < 255)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
nsStyleGradient::HasCalc()
|
|
{
|
|
for (uint32_t i = 0; i < mStops.Length(); i++) {
|
|
if (mStops[i].mLocation.IsCalcUnit())
|
|
return true;
|
|
}
|
|
return mBgPosX.IsCalcUnit() || mBgPosY.IsCalcUnit() || mAngle.IsCalcUnit() ||
|
|
mRadiusX.IsCalcUnit() || mRadiusX.IsCalcUnit();
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleImage
|
|
//
|
|
|
|
nsStyleImage::nsStyleImage()
|
|
: mType(eStyleImageType_Null)
|
|
, mCropRect(nullptr)
|
|
#ifdef DEBUG
|
|
, mImageTracked(false)
|
|
#endif
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleImage);
|
|
}
|
|
|
|
nsStyleImage::~nsStyleImage()
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleImage);
|
|
if (mType != eStyleImageType_Null)
|
|
SetNull();
|
|
}
|
|
|
|
nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
|
|
: mType(eStyleImageType_Null)
|
|
, mCropRect(nullptr)
|
|
#ifdef DEBUG
|
|
, mImageTracked(false)
|
|
#endif
|
|
{
|
|
// We need our own copy constructor because we don't want
|
|
// to copy the reference count
|
|
MOZ_COUNT_CTOR(nsStyleImage);
|
|
DoCopy(aOther);
|
|
}
|
|
|
|
nsStyleImage&
|
|
nsStyleImage::operator=(const nsStyleImage& aOther)
|
|
{
|
|
if (this != &aOther)
|
|
DoCopy(aOther);
|
|
|
|
return *this;
|
|
}
|
|
|
|
void
|
|
nsStyleImage::DoCopy(const nsStyleImage& aOther)
|
|
{
|
|
SetNull();
|
|
|
|
if (aOther.mType == eStyleImageType_Image)
|
|
SetImageData(aOther.mImage);
|
|
else if (aOther.mType == eStyleImageType_Gradient)
|
|
SetGradientData(aOther.mGradient);
|
|
else if (aOther.mType == eStyleImageType_Element)
|
|
SetElementId(aOther.mElementId);
|
|
|
|
SetCropRect(aOther.mCropRect);
|
|
}
|
|
|
|
void
|
|
nsStyleImage::SetNull()
|
|
{
|
|
NS_ABORT_IF_FALSE(!mImageTracked,
|
|
"Calling SetNull() with image tracked!");
|
|
|
|
if (mType == eStyleImageType_Gradient)
|
|
mGradient->Release();
|
|
else if (mType == eStyleImageType_Image)
|
|
NS_RELEASE(mImage);
|
|
else if (mType == eStyleImageType_Element)
|
|
NS_Free(mElementId);
|
|
|
|
mType = eStyleImageType_Null;
|
|
mCropRect = nullptr;
|
|
}
|
|
|
|
void
|
|
nsStyleImage::SetImageData(imgIRequest* aImage)
|
|
{
|
|
NS_ABORT_IF_FALSE(!mImageTracked,
|
|
"Setting a new image without untracking the old one!");
|
|
|
|
NS_IF_ADDREF(aImage);
|
|
|
|
if (mType != eStyleImageType_Null)
|
|
SetNull();
|
|
|
|
if (aImage) {
|
|
mImage = aImage;
|
|
mType = eStyleImageType_Image;
|
|
}
|
|
mSubImages.Clear();
|
|
}
|
|
|
|
void
|
|
nsStyleImage::TrackImage(nsPresContext* aContext)
|
|
{
|
|
// Sanity
|
|
NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!");
|
|
NS_ABORT_IF_FALSE(mType == eStyleImageType_Image,
|
|
"Can't track image when there isn't one!");
|
|
|
|
// Register the image with the document
|
|
nsIDocument* doc = aContext->Document();
|
|
if (doc)
|
|
doc->AddImage(mImage);
|
|
|
|
// Mark state
|
|
#ifdef DEBUG
|
|
mImageTracked = true;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
nsStyleImage::UntrackImage(nsPresContext* aContext)
|
|
{
|
|
// Sanity
|
|
NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!");
|
|
NS_ABORT_IF_FALSE(mType == eStyleImageType_Image,
|
|
"Can't untrack image when there isn't one!");
|
|
|
|
// Unregister the image with the document
|
|
nsIDocument* doc = aContext->Document();
|
|
if (doc)
|
|
doc->RemoveImage(mImage, nsIDocument::REQUEST_DISCARD);
|
|
|
|
// Mark state
|
|
#ifdef DEBUG
|
|
mImageTracked = false;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
nsStyleImage::SetGradientData(nsStyleGradient* aGradient)
|
|
{
|
|
if (aGradient)
|
|
aGradient->AddRef();
|
|
|
|
if (mType != eStyleImageType_Null)
|
|
SetNull();
|
|
|
|
if (aGradient) {
|
|
mGradient = aGradient;
|
|
mType = eStyleImageType_Gradient;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsStyleImage::SetElementId(const char16_t* aElementId)
|
|
{
|
|
if (mType != eStyleImageType_Null)
|
|
SetNull();
|
|
|
|
if (aElementId) {
|
|
mElementId = NS_strdup(aElementId);
|
|
mType = eStyleImageType_Element;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsStyleImage::SetCropRect(nsStyleSides* aCropRect)
|
|
{
|
|
if (aCropRect) {
|
|
mCropRect = new nsStyleSides(*aCropRect);
|
|
// There is really not much we can do if 'new' fails
|
|
} else {
|
|
mCropRect = nullptr;
|
|
}
|
|
}
|
|
|
|
static int32_t
|
|
ConvertToPixelCoord(const nsStyleCoord& aCoord, int32_t aPercentScale)
|
|
{
|
|
double pixelValue;
|
|
switch (aCoord.GetUnit()) {
|
|
case eStyleUnit_Percent:
|
|
pixelValue = aCoord.GetPercentValue() * aPercentScale;
|
|
break;
|
|
case eStyleUnit_Factor:
|
|
pixelValue = aCoord.GetFactorValue();
|
|
break;
|
|
default:
|
|
NS_NOTREACHED("unexpected unit for image crop rect");
|
|
return 0;
|
|
}
|
|
NS_ABORT_IF_FALSE(pixelValue >= 0, "we ensured non-negative while parsing");
|
|
pixelValue = std::min(pixelValue, double(INT32_MAX)); // avoid overflow
|
|
return NS_lround(pixelValue);
|
|
}
|
|
|
|
bool
|
|
nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
|
|
bool* aIsEntireImage) const
|
|
{
|
|
if (mType != eStyleImageType_Image)
|
|
return false;
|
|
|
|
nsCOMPtr<imgIContainer> imageContainer;
|
|
mImage->GetImage(getter_AddRefs(imageContainer));
|
|
if (!imageContainer)
|
|
return false;
|
|
|
|
nsIntSize imageSize;
|
|
imageContainer->GetWidth(&imageSize.width);
|
|
imageContainer->GetHeight(&imageSize.height);
|
|
if (imageSize.width <= 0 || imageSize.height <= 0)
|
|
return false;
|
|
|
|
int32_t left = ConvertToPixelCoord(mCropRect->GetLeft(), imageSize.width);
|
|
int32_t top = ConvertToPixelCoord(mCropRect->GetTop(), imageSize.height);
|
|
int32_t right = ConvertToPixelCoord(mCropRect->GetRight(), imageSize.width);
|
|
int32_t bottom = ConvertToPixelCoord(mCropRect->GetBottom(), imageSize.height);
|
|
|
|
// IntersectRect() returns an empty rect if we get negative width or height
|
|
nsIntRect cropRect(left, top, right - left, bottom - top);
|
|
nsIntRect imageRect(nsIntPoint(0, 0), imageSize);
|
|
aActualCropRect.IntersectRect(imageRect, cropRect);
|
|
|
|
if (aIsEntireImage)
|
|
*aIsEntireImage = aActualCropRect.IsEqualInterior(imageRect);
|
|
return true;
|
|
}
|
|
|
|
nsresult
|
|
nsStyleImage::StartDecoding() const
|
|
{
|
|
if ((mType == eStyleImageType_Image) && mImage)
|
|
return mImage->StartDecoding();
|
|
return NS_OK;
|
|
}
|
|
|
|
bool
|
|
nsStyleImage::IsOpaque() const
|
|
{
|
|
if (!IsComplete())
|
|
return false;
|
|
|
|
if (mType == eStyleImageType_Gradient)
|
|
return mGradient->IsOpaque();
|
|
|
|
if (mType == eStyleImageType_Element)
|
|
return false;
|
|
|
|
NS_ABORT_IF_FALSE(mType == eStyleImageType_Image, "unexpected image type");
|
|
|
|
nsCOMPtr<imgIContainer> imageContainer;
|
|
mImage->GetImage(getter_AddRefs(imageContainer));
|
|
NS_ABORT_IF_FALSE(imageContainer, "IsComplete() said image container is ready");
|
|
|
|
// Check if the crop region of the current image frame is opaque.
|
|
if (imageContainer->FrameIsOpaque(imgIContainer::FRAME_CURRENT)) {
|
|
if (!mCropRect)
|
|
return true;
|
|
|
|
// Must make sure if mCropRect contains at least a pixel.
|
|
// XXX Is this optimization worth it? Maybe I should just return false.
|
|
nsIntRect actualCropRect;
|
|
bool rv = ComputeActualCropRect(actualCropRect);
|
|
NS_ASSERTION(rv, "ComputeActualCropRect() can not fail here");
|
|
return rv && !actualCropRect.IsEmpty();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
nsStyleImage::IsComplete() const
|
|
{
|
|
switch (mType) {
|
|
case eStyleImageType_Null:
|
|
return false;
|
|
case eStyleImageType_Gradient:
|
|
case eStyleImageType_Element:
|
|
return true;
|
|
case eStyleImageType_Image:
|
|
{
|
|
uint32_t status = imgIRequest::STATUS_ERROR;
|
|
return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
|
|
(status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
|
|
(status & imgIRequest::STATUS_FRAME_COMPLETE);
|
|
}
|
|
default:
|
|
NS_NOTREACHED("unexpected image type");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool
|
|
nsStyleImage::IsLoaded() const
|
|
{
|
|
switch (mType) {
|
|
case eStyleImageType_Null:
|
|
return false;
|
|
case eStyleImageType_Gradient:
|
|
case eStyleImageType_Element:
|
|
return true;
|
|
case eStyleImageType_Image:
|
|
{
|
|
uint32_t status = imgIRequest::STATUS_ERROR;
|
|
return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
|
|
!(status & imgIRequest::STATUS_ERROR) &&
|
|
(status & imgIRequest::STATUS_LOAD_COMPLETE);
|
|
}
|
|
default:
|
|
NS_NOTREACHED("unexpected image type");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static inline bool
|
|
EqualRects(const nsStyleSides* aRect1, const nsStyleSides* aRect2)
|
|
{
|
|
return aRect1 == aRect2 || /* handles null== null, and optimize */
|
|
(aRect1 && aRect2 && *aRect1 == *aRect2);
|
|
}
|
|
|
|
bool
|
|
nsStyleImage::operator==(const nsStyleImage& aOther) const
|
|
{
|
|
if (mType != aOther.mType)
|
|
return false;
|
|
|
|
if (!EqualRects(mCropRect, aOther.mCropRect))
|
|
return false;
|
|
|
|
if (mType == eStyleImageType_Image)
|
|
return EqualImages(mImage, aOther.mImage);
|
|
|
|
if (mType == eStyleImageType_Gradient)
|
|
return *mGradient == *aOther.mGradient;
|
|
|
|
if (mType == eStyleImageType_Element)
|
|
return NS_strcmp(mElementId, aOther.mElementId) == 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleBackground
|
|
//
|
|
|
|
nsStyleBackground::nsStyleBackground()
|
|
: mAttachmentCount(1)
|
|
, mClipCount(1)
|
|
, mOriginCount(1)
|
|
, mRepeatCount(1)
|
|
, mPositionCount(1)
|
|
, mImageCount(1)
|
|
, mSizeCount(1)
|
|
, mBlendModeCount(1)
|
|
, mBackgroundColor(NS_RGBA(0, 0, 0, 0))
|
|
, mBackgroundInlinePolicy(NS_STYLE_BG_INLINE_POLICY_CONTINUOUS)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleBackground);
|
|
Layer *onlyLayer = mLayers.AppendElement();
|
|
NS_ASSERTION(onlyLayer, "auto array must have room for 1 element");
|
|
onlyLayer->SetInitialValues();
|
|
}
|
|
|
|
nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
|
|
: mAttachmentCount(aSource.mAttachmentCount)
|
|
, mClipCount(aSource.mClipCount)
|
|
, mOriginCount(aSource.mOriginCount)
|
|
, mRepeatCount(aSource.mRepeatCount)
|
|
, mPositionCount(aSource.mPositionCount)
|
|
, mImageCount(aSource.mImageCount)
|
|
, mSizeCount(aSource.mSizeCount)
|
|
, mBlendModeCount(aSource.mBlendModeCount)
|
|
, mLayers(aSource.mLayers) // deep copy
|
|
, mBackgroundColor(aSource.mBackgroundColor)
|
|
, mBackgroundInlinePolicy(aSource.mBackgroundInlinePolicy)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleBackground);
|
|
// If the deep copy of mLayers failed, truncate the counts.
|
|
uint32_t count = mLayers.Length();
|
|
if (count != aSource.mLayers.Length()) {
|
|
NS_WARNING("truncating counts due to out-of-memory");
|
|
mAttachmentCount = std::max(mAttachmentCount, count);
|
|
mClipCount = std::max(mClipCount, count);
|
|
mOriginCount = std::max(mOriginCount, count);
|
|
mRepeatCount = std::max(mRepeatCount, count);
|
|
mPositionCount = std::max(mPositionCount, count);
|
|
mImageCount = std::max(mImageCount, count);
|
|
mSizeCount = std::max(mSizeCount, count);
|
|
mBlendModeCount = std::max(mSizeCount, count);
|
|
}
|
|
}
|
|
|
|
nsStyleBackground::~nsStyleBackground()
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleBackground);
|
|
}
|
|
|
|
void
|
|
nsStyleBackground::Destroy(nsPresContext* aContext)
|
|
{
|
|
// Untrack all the images stored in our layers
|
|
for (uint32_t i = 0; i < mImageCount; ++i)
|
|
mLayers[i].UntrackImages(aContext);
|
|
|
|
this->~nsStyleBackground();
|
|
aContext->FreeToShell(sizeof(nsStyleBackground), this);
|
|
}
|
|
|
|
nsChangeHint nsStyleBackground::CalcDifference(const nsStyleBackground& aOther) const
|
|
{
|
|
const nsStyleBackground* moreLayers =
|
|
mImageCount > aOther.mImageCount ? this : &aOther;
|
|
const nsStyleBackground* lessLayers =
|
|
mImageCount > aOther.mImageCount ? &aOther : this;
|
|
|
|
bool hasVisualDifference = false;
|
|
|
|
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, moreLayers) {
|
|
if (i < lessLayers->mImageCount) {
|
|
if (moreLayers->mLayers[i] != lessLayers->mLayers[i]) {
|
|
if ((moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) ||
|
|
(lessLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element))
|
|
return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
|
|
hasVisualDifference = true;
|
|
}
|
|
} else {
|
|
if (moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element)
|
|
return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
|
|
hasVisualDifference = true;
|
|
}
|
|
}
|
|
|
|
if (hasVisualDifference ||
|
|
mBackgroundColor != aOther.mBackgroundColor ||
|
|
mBackgroundInlinePolicy != aOther.mBackgroundInlinePolicy)
|
|
return NS_STYLE_HINT_VISUAL;
|
|
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
|
|
bool nsStyleBackground::HasFixedBackground() const
|
|
{
|
|
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, this) {
|
|
const Layer &layer = mLayers[i];
|
|
if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
|
|
!layer.mImage.IsEmpty()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool nsStyleBackground::IsTransparent() const
|
|
{
|
|
return BottomLayer().mImage.IsEmpty() &&
|
|
mImageCount == 1 &&
|
|
NS_GET_A(mBackgroundColor) == 0;
|
|
}
|
|
|
|
void
|
|
nsStyleBackground::Position::SetInitialValues()
|
|
{
|
|
// Initial value is "0% 0%"
|
|
mXPosition.mPercent = 0.0f;
|
|
mXPosition.mLength = 0;
|
|
mXPosition.mHasPercent = true;
|
|
mYPosition.mPercent = 0.0f;
|
|
mYPosition.mLength = 0;
|
|
mYPosition.mHasPercent = true;
|
|
}
|
|
|
|
bool
|
|
nsStyleBackground::Size::DependsOnPositioningAreaSize(const nsStyleImage& aImage) const
|
|
{
|
|
NS_ABORT_IF_FALSE(aImage.GetType() != eStyleImageType_Null,
|
|
"caller should have handled this");
|
|
|
|
// If either dimension contains a non-zero percentage, rendering for that
|
|
// dimension straightforwardly depends on frame size.
|
|
if ((mWidthType == eLengthPercentage && mWidth.mPercent != 0.0f) ||
|
|
(mHeightType == eLengthPercentage && mHeight.mPercent != 0.0f)) {
|
|
return true;
|
|
}
|
|
|
|
// So too for contain and cover.
|
|
if (mWidthType == eContain || mWidthType == eCover) {
|
|
return true;
|
|
}
|
|
|
|
// If both dimensions are fixed lengths, there's no dependency.
|
|
if (mWidthType == eLengthPercentage && mHeightType == eLengthPercentage) {
|
|
return false;
|
|
}
|
|
|
|
NS_ABORT_IF_FALSE((mWidthType == eLengthPercentage && mHeightType == eAuto) ||
|
|
(mWidthType == eAuto && mHeightType == eLengthPercentage) ||
|
|
(mWidthType == eAuto && mHeightType == eAuto),
|
|
"logic error");
|
|
|
|
nsStyleImageType type = aImage.GetType();
|
|
|
|
// Gradient rendering depends on frame size when auto is involved because
|
|
// gradients have no intrinsic ratio or dimensions, and therefore the relevant
|
|
// dimension is "treat[ed] as 100%".
|
|
if (type == eStyleImageType_Gradient) {
|
|
return true;
|
|
}
|
|
|
|
// XXX Element rendering for auto or fixed length doesn't depend on frame size
|
|
// according to the spec. However, we don't implement the spec yet, so
|
|
// for now we bail and say element() plus auto affects ultimate size.
|
|
if (type == eStyleImageType_Element) {
|
|
return true;
|
|
}
|
|
|
|
if (type == eStyleImageType_Image) {
|
|
nsCOMPtr<imgIContainer> imgContainer;
|
|
aImage.GetImageData()->GetImage(getter_AddRefs(imgContainer));
|
|
if (imgContainer) {
|
|
nsIntSize imageSize;
|
|
nsSize imageRatio;
|
|
bool hasWidth, hasHeight;
|
|
nsLayoutUtils::ComputeSizeForDrawing(imgContainer, imageSize, imageRatio,
|
|
hasWidth, hasHeight);
|
|
|
|
// If the image has a fixed width and height, rendering never depends on
|
|
// the frame size.
|
|
if (hasWidth && hasHeight) {
|
|
return false;
|
|
}
|
|
|
|
// If the image has an intrinsic ratio, rendering will depend on frame
|
|
// size when background-size is all auto.
|
|
if (imageRatio != nsSize(0, 0)) {
|
|
return mWidthType == mHeightType;
|
|
}
|
|
|
|
// Otherwise, rendering depends on frame size when the image dimensions
|
|
// and background-size don't complement each other.
|
|
return !(hasWidth && mHeightType == eLengthPercentage) &&
|
|
!(hasHeight && mWidthType == eLengthPercentage);
|
|
}
|
|
} else {
|
|
NS_NOTREACHED("missed an enum value");
|
|
}
|
|
|
|
// Passed the gauntlet: no dependency.
|
|
return false;
|
|
}
|
|
|
|
void
|
|
nsStyleBackground::Size::SetInitialValues()
|
|
{
|
|
mWidthType = mHeightType = eAuto;
|
|
}
|
|
|
|
bool
|
|
nsStyleBackground::Size::operator==(const Size& aOther) const
|
|
{
|
|
NS_ABORT_IF_FALSE(mWidthType < eDimensionType_COUNT,
|
|
"bad mWidthType for this");
|
|
NS_ABORT_IF_FALSE(mHeightType < eDimensionType_COUNT,
|
|
"bad mHeightType for this");
|
|
NS_ABORT_IF_FALSE(aOther.mWidthType < eDimensionType_COUNT,
|
|
"bad mWidthType for aOther");
|
|
NS_ABORT_IF_FALSE(aOther.mHeightType < eDimensionType_COUNT,
|
|
"bad mHeightType for aOther");
|
|
|
|
return mWidthType == aOther.mWidthType &&
|
|
mHeightType == aOther.mHeightType &&
|
|
(mWidthType != eLengthPercentage || mWidth == aOther.mWidth) &&
|
|
(mHeightType != eLengthPercentage || mHeight == aOther.mHeight);
|
|
}
|
|
|
|
void
|
|
nsStyleBackground::Repeat::SetInitialValues()
|
|
{
|
|
mXRepeat = NS_STYLE_BG_REPEAT_REPEAT;
|
|
mYRepeat = NS_STYLE_BG_REPEAT_REPEAT;
|
|
}
|
|
|
|
nsStyleBackground::Layer::Layer()
|
|
{
|
|
}
|
|
|
|
nsStyleBackground::Layer::~Layer()
|
|
{
|
|
}
|
|
|
|
void
|
|
nsStyleBackground::Layer::SetInitialValues()
|
|
{
|
|
mAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL;
|
|
mClip = NS_STYLE_BG_CLIP_BORDER;
|
|
mOrigin = NS_STYLE_BG_ORIGIN_PADDING;
|
|
mRepeat.SetInitialValues();
|
|
mBlendMode = NS_STYLE_BLEND_NORMAL;
|
|
mPosition.SetInitialValues();
|
|
mSize.SetInitialValues();
|
|
mImage.SetNull();
|
|
}
|
|
|
|
bool
|
|
nsStyleBackground::Layer::RenderingMightDependOnPositioningAreaSizeChange() const
|
|
{
|
|
// Do we even have an image?
|
|
if (mImage.IsEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
return mPosition.DependsOnPositioningAreaSize() ||
|
|
mSize.DependsOnPositioningAreaSize(mImage);
|
|
}
|
|
|
|
bool
|
|
nsStyleBackground::Layer::operator==(const Layer& aOther) const
|
|
{
|
|
return mAttachment == aOther.mAttachment &&
|
|
mClip == aOther.mClip &&
|
|
mOrigin == aOther.mOrigin &&
|
|
mRepeat == aOther.mRepeat &&
|
|
mBlendMode == aOther.mBlendMode &&
|
|
mPosition == aOther.mPosition &&
|
|
mSize == aOther.mSize &&
|
|
mImage == aOther.mImage;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleDisplay
|
|
//
|
|
void nsTimingFunction::AssignFromKeyword(int32_t aTimingFunctionType)
|
|
{
|
|
switch (aTimingFunctionType) {
|
|
case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START:
|
|
mType = StepStart;
|
|
mSteps = 1;
|
|
return;
|
|
case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END:
|
|
mType = StepEnd;
|
|
mSteps = 1;
|
|
return;
|
|
default:
|
|
mType = Function;
|
|
break;
|
|
}
|
|
|
|
static_assert(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE == 0 &&
|
|
NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR == 1 &&
|
|
NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN == 2 &&
|
|
NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT == 3 &&
|
|
NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT == 4,
|
|
"transition timing function constants not as expected");
|
|
|
|
static const float timingFunctionValues[5][4] = {
|
|
{ 0.25f, 0.10f, 0.25f, 1.00f }, // ease
|
|
{ 0.00f, 0.00f, 1.00f, 1.00f }, // linear
|
|
{ 0.42f, 0.00f, 1.00f, 1.00f }, // ease-in
|
|
{ 0.00f, 0.00f, 0.58f, 1.00f }, // ease-out
|
|
{ 0.42f, 0.00f, 0.58f, 1.00f } // ease-in-out
|
|
};
|
|
|
|
NS_ABORT_IF_FALSE(0 <= aTimingFunctionType && aTimingFunctionType < 5,
|
|
"keyword out of range");
|
|
mFunc.mX1 = timingFunctionValues[aTimingFunctionType][0];
|
|
mFunc.mY1 = timingFunctionValues[aTimingFunctionType][1];
|
|
mFunc.mX2 = timingFunctionValues[aTimingFunctionType][2];
|
|
mFunc.mY2 = timingFunctionValues[aTimingFunctionType][3];
|
|
}
|
|
|
|
nsTransition::nsTransition(const nsTransition& aCopy)
|
|
: mTimingFunction(aCopy.mTimingFunction)
|
|
, mDuration(aCopy.mDuration)
|
|
, mDelay(aCopy.mDelay)
|
|
, mProperty(aCopy.mProperty)
|
|
, mUnknownProperty(aCopy.mUnknownProperty)
|
|
{
|
|
}
|
|
|
|
void nsTransition::SetInitialValues()
|
|
{
|
|
mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
|
|
mDuration = 0.0;
|
|
mDelay = 0.0;
|
|
mProperty = eCSSPropertyExtra_all_properties;
|
|
}
|
|
|
|
void nsTransition::SetUnknownProperty(const nsAString& aUnknownProperty)
|
|
{
|
|
NS_ASSERTION(nsCSSProps::LookupProperty(aUnknownProperty,
|
|
nsCSSProps::eEnabled) ==
|
|
eCSSProperty_UNKNOWN,
|
|
"should be unknown property");
|
|
mProperty = eCSSProperty_UNKNOWN;
|
|
mUnknownProperty = do_GetAtom(aUnknownProperty);
|
|
}
|
|
|
|
nsAnimation::nsAnimation(const nsAnimation& aCopy)
|
|
: mTimingFunction(aCopy.mTimingFunction)
|
|
, mDuration(aCopy.mDuration)
|
|
, mDelay(aCopy.mDelay)
|
|
, mName(aCopy.mName)
|
|
, mDirection(aCopy.mDirection)
|
|
, mFillMode(aCopy.mFillMode)
|
|
, mPlayState(aCopy.mPlayState)
|
|
, mIterationCount(aCopy.mIterationCount)
|
|
{
|
|
}
|
|
|
|
void
|
|
nsAnimation::SetInitialValues()
|
|
{
|
|
mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
|
|
mDuration = 0.0;
|
|
mDelay = 0.0;
|
|
mName = EmptyString();
|
|
mDirection = NS_STYLE_ANIMATION_DIRECTION_NORMAL;
|
|
mFillMode = NS_STYLE_ANIMATION_FILL_MODE_NONE;
|
|
mPlayState = NS_STYLE_ANIMATION_PLAY_STATE_RUNNING;
|
|
mIterationCount = 1.0f;
|
|
}
|
|
|
|
nsStyleDisplay::nsStyleDisplay()
|
|
: mWillChangeBitField(0)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleDisplay);
|
|
mAppearance = NS_THEME_NONE;
|
|
mDisplay = NS_STYLE_DISPLAY_INLINE;
|
|
mOriginalDisplay = mDisplay;
|
|
mPosition = NS_STYLE_POSITION_STATIC;
|
|
mFloats = NS_STYLE_FLOAT_NONE;
|
|
mOriginalFloats = mFloats;
|
|
mBreakType = NS_STYLE_CLEAR_NONE;
|
|
mBreakInside = NS_STYLE_PAGE_BREAK_AUTO;
|
|
mBreakBefore = false;
|
|
mBreakAfter = false;
|
|
mOverflowX = NS_STYLE_OVERFLOW_VISIBLE;
|
|
mOverflowY = NS_STYLE_OVERFLOW_VISIBLE;
|
|
mResize = NS_STYLE_RESIZE_NONE;
|
|
mClipFlags = NS_STYLE_CLIP_AUTO;
|
|
mClip.SetRect(0,0,0,0);
|
|
mOpacity = 1.0f;
|
|
mSpecifiedTransform = nullptr;
|
|
mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin
|
|
mTransformOrigin[1].SetPercentValue(0.5f);
|
|
mTransformOrigin[2].SetCoordValue(0);
|
|
mPerspectiveOrigin[0].SetPercentValue(0.5f);
|
|
mPerspectiveOrigin[1].SetPercentValue(0.5f);
|
|
mChildPerspective.SetCoordValue(0);
|
|
mBackfaceVisibility = NS_STYLE_BACKFACE_VISIBILITY_VISIBLE;
|
|
mTransformStyle = NS_STYLE_TRANSFORM_STYLE_FLAT;
|
|
mOrient = NS_STYLE_ORIENT_AUTO;
|
|
mMixBlendMode = NS_STYLE_BLEND_NORMAL;
|
|
mTouchAction = NS_STYLE_TOUCH_ACTION_AUTO;
|
|
|
|
mTransitions.AppendElement();
|
|
NS_ABORT_IF_FALSE(mTransitions.Length() == 1,
|
|
"appending within auto buffer should never fail");
|
|
mTransitions[0].SetInitialValues();
|
|
mTransitionTimingFunctionCount = 1;
|
|
mTransitionDurationCount = 1;
|
|
mTransitionDelayCount = 1;
|
|
mTransitionPropertyCount = 1;
|
|
|
|
mAnimations.AppendElement();
|
|
NS_ABORT_IF_FALSE(mAnimations.Length() == 1,
|
|
"appending within auto buffer should never fail");
|
|
mAnimations[0].SetInitialValues();
|
|
mAnimationTimingFunctionCount = 1;
|
|
mAnimationDurationCount = 1;
|
|
mAnimationDelayCount = 1;
|
|
mAnimationNameCount = 1;
|
|
mAnimationDirectionCount = 1;
|
|
mAnimationFillModeCount = 1;
|
|
mAnimationPlayStateCount = 1;
|
|
mAnimationIterationCountCount = 1;
|
|
}
|
|
|
|
nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
|
|
: mBinding(aSource.mBinding)
|
|
, mClip(aSource.mClip)
|
|
, mOpacity(aSource.mOpacity)
|
|
, mDisplay(aSource.mDisplay)
|
|
, mOriginalDisplay(aSource.mOriginalDisplay)
|
|
, mAppearance(aSource.mAppearance)
|
|
, mPosition(aSource.mPosition)
|
|
, mFloats(aSource.mFloats)
|
|
, mOriginalFloats(aSource.mOriginalFloats)
|
|
, mBreakType(aSource.mBreakType)
|
|
, mBreakInside(aSource.mBreakInside)
|
|
, mBreakBefore(aSource.mBreakBefore)
|
|
, mBreakAfter(aSource.mBreakAfter)
|
|
, mOverflowX(aSource.mOverflowX)
|
|
, mOverflowY(aSource.mOverflowY)
|
|
, mResize(aSource.mResize)
|
|
, mClipFlags(aSource.mClipFlags)
|
|
, mOrient(aSource.mOrient)
|
|
, mMixBlendMode(aSource.mMixBlendMode)
|
|
, mWillChangeBitField(aSource.mWillChangeBitField)
|
|
, mWillChange(aSource.mWillChange)
|
|
, mTouchAction(aSource.mTouchAction)
|
|
, mBackfaceVisibility(aSource.mBackfaceVisibility)
|
|
, mTransformStyle(aSource.mTransformStyle)
|
|
, mSpecifiedTransform(aSource.mSpecifiedTransform)
|
|
, mChildPerspective(aSource.mChildPerspective)
|
|
, mTransitions(aSource.mTransitions)
|
|
, mTransitionTimingFunctionCount(aSource.mTransitionTimingFunctionCount)
|
|
, mTransitionDurationCount(aSource.mTransitionDurationCount)
|
|
, mTransitionDelayCount(aSource.mTransitionDelayCount)
|
|
, mTransitionPropertyCount(aSource.mTransitionPropertyCount)
|
|
, mAnimations(aSource.mAnimations)
|
|
, mAnimationTimingFunctionCount(aSource.mAnimationTimingFunctionCount)
|
|
, mAnimationDurationCount(aSource.mAnimationDurationCount)
|
|
, mAnimationDelayCount(aSource.mAnimationDelayCount)
|
|
, mAnimationNameCount(aSource.mAnimationNameCount)
|
|
, mAnimationDirectionCount(aSource.mAnimationDirectionCount)
|
|
, mAnimationFillModeCount(aSource.mAnimationFillModeCount)
|
|
, mAnimationPlayStateCount(aSource.mAnimationPlayStateCount)
|
|
, mAnimationIterationCountCount(aSource.mAnimationIterationCountCount)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleDisplay);
|
|
|
|
/* Copy over transform origin. */
|
|
mTransformOrigin[0] = aSource.mTransformOrigin[0];
|
|
mTransformOrigin[1] = aSource.mTransformOrigin[1];
|
|
mTransformOrigin[2] = aSource.mTransformOrigin[2];
|
|
mPerspectiveOrigin[0] = aSource.mPerspectiveOrigin[0];
|
|
mPerspectiveOrigin[1] = aSource.mPerspectiveOrigin[1];
|
|
}
|
|
|
|
nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
|
|
{
|
|
nsChangeHint hint = nsChangeHint(0);
|
|
|
|
if (!EqualURIs(mBinding, aOther.mBinding)
|
|
|| mPosition != aOther.mPosition
|
|
|| mDisplay != aOther.mDisplay
|
|
|| (mFloats == NS_STYLE_FLOAT_NONE) != (aOther.mFloats == NS_STYLE_FLOAT_NONE)
|
|
|| mOverflowX != aOther.mOverflowX
|
|
|| mOverflowY != aOther.mOverflowY
|
|
|| mResize != aOther.mResize)
|
|
NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
|
|
|
|
if ((mAppearance == NS_THEME_TEXTFIELD &&
|
|
aOther.mAppearance != NS_THEME_TEXTFIELD) ||
|
|
(mAppearance != NS_THEME_TEXTFIELD &&
|
|
aOther.mAppearance == NS_THEME_TEXTFIELD)) {
|
|
// This is for <input type=number> where we allow authors to specify a
|
|
// |-moz-appearance:textfield| to get a control without a spinner. (The
|
|
// spinner is present for |-moz-appearance:number-input| but also other
|
|
// values such as 'none'.) We need to reframe since we want to use
|
|
// nsTextControlFrame instead of nsNumberControlFrame if the author
|
|
// specifies 'textfield'.
|
|
return nsChangeHint_ReconstructFrame;
|
|
}
|
|
|
|
if (mFloats != aOther.mFloats) {
|
|
// Changing which side we float on doesn't affect descendants directly
|
|
NS_UpdateHint(hint,
|
|
NS_SubtractHint(nsChangeHint_AllReflowHints,
|
|
NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
|
|
nsChangeHint_NeedDirtyReflow)));
|
|
}
|
|
|
|
// XXX the following is conservative, for now: changing float breaking shouldn't
|
|
// necessarily require a repaint, reflow should suffice.
|
|
if (mBreakType != aOther.mBreakType
|
|
|| mBreakInside != aOther.mBreakInside
|
|
|| mBreakBefore != aOther.mBreakBefore
|
|
|| mBreakAfter != aOther.mBreakAfter
|
|
|| mAppearance != aOther.mAppearance
|
|
|| mOrient != aOther.mOrient
|
|
|| mClipFlags != aOther.mClipFlags || !mClip.IsEqualInterior(aOther.mClip))
|
|
NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AllReflowHints,
|
|
nsChangeHint_RepaintFrame));
|
|
|
|
if (mOpacity != aOther.mOpacity) {
|
|
NS_UpdateHint(hint, nsChangeHint_UpdateOpacityLayer);
|
|
}
|
|
|
|
/* If we've added or removed the transform property, we need to reconstruct the frame to add
|
|
* or remove the view object, and also to handle abs-pos and fixed-pos containers.
|
|
*/
|
|
if (HasTransformStyle() != aOther.HasTransformStyle()) {
|
|
// We do not need to apply nsChangeHint_UpdateTransformLayer since
|
|
// nsChangeHint_RepaintFrame will forcibly invalidate the frame area and
|
|
// ensure layers are rebuilt (or removed).
|
|
NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AddOrRemoveTransform,
|
|
NS_CombineHint(nsChangeHint_UpdateOverflow,
|
|
nsChangeHint_RepaintFrame)));
|
|
}
|
|
else if (HasTransformStyle()) {
|
|
/* Otherwise, if we've kept the property lying around and we already had a
|
|
* transform, we need to see whether or not we've changed the transform.
|
|
* If so, we need to recompute its overflow rect (which probably changed
|
|
* if the transform changed) and to redraw within the bounds of that new
|
|
* overflow rect.
|
|
*/
|
|
if (!mSpecifiedTransform != !aOther.mSpecifiedTransform ||
|
|
(mSpecifiedTransform &&
|
|
*mSpecifiedTransform != *aOther.mSpecifiedTransform)) {
|
|
NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_UpdateOverflow,
|
|
nsChangeHint_UpdateTransformLayer));
|
|
}
|
|
|
|
const nsChangeHint kUpdateOverflowAndRepaintHint =
|
|
NS_CombineHint(nsChangeHint_UpdateOverflow, nsChangeHint_RepaintFrame);
|
|
for (uint8_t index = 0; index < 3; ++index)
|
|
if (mTransformOrigin[index] != aOther.mTransformOrigin[index]) {
|
|
NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint);
|
|
break;
|
|
}
|
|
|
|
for (uint8_t index = 0; index < 2; ++index)
|
|
if (mPerspectiveOrigin[index] != aOther.mPerspectiveOrigin[index]) {
|
|
NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint);
|
|
break;
|
|
}
|
|
|
|
if (mChildPerspective != aOther.mChildPerspective ||
|
|
mTransformStyle != aOther.mTransformStyle)
|
|
NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint);
|
|
|
|
if (mBackfaceVisibility != aOther.mBackfaceVisibility)
|
|
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
|
}
|
|
|
|
if (mWillChangeBitField != aOther.mWillChangeBitField) {
|
|
NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
|
|
}
|
|
|
|
// Note: Our current behavior for handling changes to the
|
|
// transition-duration, transition-delay, and transition-timing-function
|
|
// properties is to do nothing. In other words, the transition
|
|
// property that matters is what it is when the transition begins, and
|
|
// we don't stop a transition later because the transition property
|
|
// changed.
|
|
// We do handle changes to transition-property, but we don't need to
|
|
// bother with anything here, since the transition manager is notified
|
|
// of any style context change anyway.
|
|
|
|
// Note: Likewise, for animation-*, the animation manager gets
|
|
// notified about every new style context constructed, and it uses
|
|
// that opportunity to handle dynamic changes appropriately.
|
|
|
|
return hint;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleVisibility
|
|
//
|
|
|
|
nsStyleVisibility::nsStyleVisibility(nsPresContext* aPresContext)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleVisibility);
|
|
uint32_t bidiOptions = aPresContext->GetBidi();
|
|
if (GET_BIDI_OPTION_DIRECTION(bidiOptions) == IBMBIDI_TEXTDIRECTION_RTL)
|
|
mDirection = NS_STYLE_DIRECTION_RTL;
|
|
else
|
|
mDirection = NS_STYLE_DIRECTION_LTR;
|
|
|
|
mVisible = NS_STYLE_VISIBILITY_VISIBLE;
|
|
mPointerEvents = NS_STYLE_POINTER_EVENTS_AUTO;
|
|
mWritingMode = NS_STYLE_WRITING_MODE_HORIZONTAL_TB;
|
|
}
|
|
|
|
nsStyleVisibility::nsStyleVisibility(const nsStyleVisibility& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleVisibility);
|
|
mImageOrientation = aSource.mImageOrientation;
|
|
mDirection = aSource.mDirection;
|
|
mVisible = aSource.mVisible;
|
|
mPointerEvents = aSource.mPointerEvents;
|
|
mWritingMode = aSource.mWritingMode;
|
|
}
|
|
|
|
nsChangeHint nsStyleVisibility::CalcDifference(const nsStyleVisibility& aOther) const
|
|
{
|
|
nsChangeHint hint = nsChangeHint(0);
|
|
|
|
if (mDirection != aOther.mDirection || mWritingMode != aOther.mWritingMode) {
|
|
NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
|
|
} else {
|
|
if ((mImageOrientation != aOther.mImageOrientation)) {
|
|
NS_UpdateHint(hint, nsChangeHint_AllReflowHints);
|
|
}
|
|
if (mVisible != aOther.mVisible) {
|
|
if ((NS_STYLE_VISIBILITY_COLLAPSE == mVisible) ||
|
|
(NS_STYLE_VISIBILITY_COLLAPSE == aOther.mVisible)) {
|
|
NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
|
|
} else {
|
|
NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL);
|
|
}
|
|
}
|
|
if (mPointerEvents != aOther.mPointerEvents) {
|
|
// nsSVGPathGeometryFrame's mRect depends on stroke _and_ on the value
|
|
// of pointer-events. See nsSVGPathGeometryFrame::ReflowSVG's use of
|
|
// GetHitTestFlags. (Only a reflow, no visual change.)
|
|
NS_UpdateHint(hint, nsChangeHint_NeedReflow);
|
|
NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
|
|
}
|
|
}
|
|
return hint;
|
|
}
|
|
|
|
nsStyleContentData::~nsStyleContentData()
|
|
{
|
|
NS_ABORT_IF_FALSE(!mImageTracked,
|
|
"nsStyleContentData being destroyed while still tracking image!");
|
|
if (mType == eStyleContentType_Image) {
|
|
NS_IF_RELEASE(mContent.mImage);
|
|
} else if (mType == eStyleContentType_Counter ||
|
|
mType == eStyleContentType_Counters) {
|
|
mContent.mCounters->Release();
|
|
} else if (mContent.mString) {
|
|
NS_Free(mContent.mString);
|
|
}
|
|
}
|
|
|
|
nsStyleContentData& nsStyleContentData::operator=(const nsStyleContentData& aOther)
|
|
{
|
|
if (this == &aOther)
|
|
return *this;
|
|
this->~nsStyleContentData();
|
|
new (this) nsStyleContentData();
|
|
|
|
mType = aOther.mType;
|
|
if (mType == eStyleContentType_Image) {
|
|
mContent.mImage = aOther.mContent.mImage;
|
|
NS_IF_ADDREF(mContent.mImage);
|
|
} else if (mType == eStyleContentType_Counter ||
|
|
mType == eStyleContentType_Counters) {
|
|
mContent.mCounters = aOther.mContent.mCounters;
|
|
mContent.mCounters->AddRef();
|
|
} else if (aOther.mContent.mString) {
|
|
mContent.mString = NS_strdup(aOther.mContent.mString);
|
|
} else {
|
|
mContent.mString = nullptr;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool nsStyleContentData::operator==(const nsStyleContentData& aOther) const
|
|
{
|
|
if (mType != aOther.mType)
|
|
return false;
|
|
if (mType == eStyleContentType_Image) {
|
|
if (!mContent.mImage || !aOther.mContent.mImage)
|
|
return mContent.mImage == aOther.mContent.mImage;
|
|
bool eq;
|
|
nsCOMPtr<nsIURI> thisURI, otherURI;
|
|
mContent.mImage->GetURI(getter_AddRefs(thisURI));
|
|
aOther.mContent.mImage->GetURI(getter_AddRefs(otherURI));
|
|
return thisURI == otherURI || // handles null==null
|
|
(thisURI && otherURI &&
|
|
NS_SUCCEEDED(thisURI->Equals(otherURI, &eq)) &&
|
|
eq);
|
|
}
|
|
if (mType == eStyleContentType_Counter ||
|
|
mType == eStyleContentType_Counters)
|
|
return *mContent.mCounters == *aOther.mContent.mCounters;
|
|
return safe_strcmp(mContent.mString, aOther.mContent.mString) == 0;
|
|
}
|
|
|
|
void
|
|
nsStyleContentData::TrackImage(nsPresContext* aContext)
|
|
{
|
|
// Sanity
|
|
NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!");
|
|
NS_ABORT_IF_FALSE(mType == eStyleContentType_Image,
|
|
"Trying to do image tracking on non-image!");
|
|
NS_ABORT_IF_FALSE(mContent.mImage,
|
|
"Can't track image when there isn't one!");
|
|
|
|
// Register the image with the document
|
|
nsIDocument* doc = aContext->Document();
|
|
if (doc)
|
|
doc->AddImage(mContent.mImage);
|
|
|
|
// Mark state
|
|
#ifdef DEBUG
|
|
mImageTracked = true;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
nsStyleContentData::UntrackImage(nsPresContext* aContext)
|
|
{
|
|
// Sanity
|
|
NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!");
|
|
NS_ABORT_IF_FALSE(mType == eStyleContentType_Image,
|
|
"Trying to do image tracking on non-image!");
|
|
NS_ABORT_IF_FALSE(mContent.mImage,
|
|
"Can't untrack image when there isn't one!");
|
|
|
|
// Unregister the image with the document
|
|
nsIDocument* doc = aContext->Document();
|
|
if (doc)
|
|
doc->RemoveImage(mContent.mImage, nsIDocument::REQUEST_DISCARD);
|
|
|
|
// Mark state
|
|
#ifdef DEBUG
|
|
mImageTracked = false;
|
|
#endif
|
|
}
|
|
|
|
|
|
//-----------------------
|
|
// nsStyleContent
|
|
//
|
|
|
|
nsStyleContent::nsStyleContent(void)
|
|
: mMarkerOffset(),
|
|
mContents(nullptr),
|
|
mIncrements(nullptr),
|
|
mResets(nullptr),
|
|
mContentCount(0),
|
|
mIncrementCount(0),
|
|
mResetCount(0)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleContent);
|
|
mMarkerOffset.SetAutoValue();
|
|
}
|
|
|
|
nsStyleContent::~nsStyleContent(void)
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleContent);
|
|
DELETE_ARRAY_IF(mContents);
|
|
DELETE_ARRAY_IF(mIncrements);
|
|
DELETE_ARRAY_IF(mResets);
|
|
}
|
|
|
|
void
|
|
nsStyleContent::Destroy(nsPresContext* aContext)
|
|
{
|
|
// Unregister any images we might have with the document.
|
|
for (uint32_t i = 0; i < mContentCount; ++i) {
|
|
if ((mContents[i].mType == eStyleContentType_Image) &&
|
|
mContents[i].mContent.mImage) {
|
|
mContents[i].UntrackImage(aContext);
|
|
}
|
|
}
|
|
|
|
this->~nsStyleContent();
|
|
aContext->FreeToShell(sizeof(nsStyleContent), this);
|
|
}
|
|
|
|
nsStyleContent::nsStyleContent(const nsStyleContent& aSource)
|
|
:mMarkerOffset(),
|
|
mContents(nullptr),
|
|
mIncrements(nullptr),
|
|
mResets(nullptr),
|
|
mContentCount(0),
|
|
mIncrementCount(0),
|
|
mResetCount(0)
|
|
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleContent);
|
|
mMarkerOffset = aSource.mMarkerOffset;
|
|
|
|
uint32_t index;
|
|
if (NS_SUCCEEDED(AllocateContents(aSource.ContentCount()))) {
|
|
for (index = 0; index < mContentCount; index++) {
|
|
ContentAt(index) = aSource.ContentAt(index);
|
|
}
|
|
}
|
|
|
|
if (NS_SUCCEEDED(AllocateCounterIncrements(aSource.CounterIncrementCount()))) {
|
|
for (index = 0; index < mIncrementCount; index++) {
|
|
const nsStyleCounterData *data = aSource.GetCounterIncrementAt(index);
|
|
mIncrements[index].mCounter = data->mCounter;
|
|
mIncrements[index].mValue = data->mValue;
|
|
}
|
|
}
|
|
|
|
if (NS_SUCCEEDED(AllocateCounterResets(aSource.CounterResetCount()))) {
|
|
for (index = 0; index < mResetCount; index++) {
|
|
const nsStyleCounterData *data = aSource.GetCounterResetAt(index);
|
|
mResets[index].mCounter = data->mCounter;
|
|
mResets[index].mValue = data->mValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
nsChangeHint nsStyleContent::CalcDifference(const nsStyleContent& aOther) const
|
|
{
|
|
// In ReResolveStyleContext we assume that if there's no existing
|
|
// ::before or ::after and we don't have to restyle children of the
|
|
// node then we can't end up with a ::before or ::after due to the
|
|
// restyle of the node itself. That's not quite true, but the only
|
|
// exception to the above is when the 'content' property of the node
|
|
// changes and the pseudo-element inherits the changed value. Since
|
|
// the code here triggers a frame change on the node in that case,
|
|
// the optimization in ReResolveStyleContext is ok. But if we ever
|
|
// change this code to not reconstruct frames on changes to the
|
|
// 'content' property, then we will need to revisit the optimization
|
|
// in ReResolveStyleContext.
|
|
|
|
if (mContentCount != aOther.mContentCount ||
|
|
mIncrementCount != aOther.mIncrementCount ||
|
|
mResetCount != aOther.mResetCount) {
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
}
|
|
|
|
uint32_t ix = mContentCount;
|
|
while (0 < ix--) {
|
|
if (mContents[ix] != aOther.mContents[ix]) {
|
|
// Unfortunately we need to reframe here; a simple reflow
|
|
// will not pick up different text or different image URLs,
|
|
// since we set all that up in the CSSFrameConstructor
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
}
|
|
}
|
|
ix = mIncrementCount;
|
|
while (0 < ix--) {
|
|
if ((mIncrements[ix].mValue != aOther.mIncrements[ix].mValue) ||
|
|
(mIncrements[ix].mCounter != aOther.mIncrements[ix].mCounter)) {
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
}
|
|
}
|
|
ix = mResetCount;
|
|
while (0 < ix--) {
|
|
if ((mResets[ix].mValue != aOther.mResets[ix].mValue) ||
|
|
(mResets[ix].mCounter != aOther.mResets[ix].mCounter)) {
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
}
|
|
}
|
|
if (mMarkerOffset != aOther.mMarkerOffset) {
|
|
return NS_STYLE_HINT_REFLOW;
|
|
}
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
|
|
nsresult nsStyleContent::AllocateContents(uint32_t aCount)
|
|
{
|
|
// We need to run the destructors of the elements of mContents, so we
|
|
// delete and reallocate even if aCount == mContentCount. (If
|
|
// nsStyleContentData had its members private and managed their
|
|
// ownership on setting, we wouldn't need this, but that seems
|
|
// unnecessary at this point.)
|
|
DELETE_ARRAY_IF(mContents);
|
|
if (aCount) {
|
|
mContents = new nsStyleContentData[aCount];
|
|
if (! mContents) {
|
|
mContentCount = 0;
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
mContentCount = aCount;
|
|
return NS_OK;
|
|
}
|
|
|
|
// ---------------------
|
|
// nsStyleQuotes
|
|
//
|
|
|
|
nsStyleQuotes::nsStyleQuotes(void)
|
|
: mQuotesCount(0),
|
|
mQuotes(nullptr)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleQuotes);
|
|
SetInitial();
|
|
}
|
|
|
|
nsStyleQuotes::~nsStyleQuotes(void)
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleQuotes);
|
|
DELETE_ARRAY_IF(mQuotes);
|
|
}
|
|
|
|
nsStyleQuotes::nsStyleQuotes(const nsStyleQuotes& aSource)
|
|
: mQuotesCount(0),
|
|
mQuotes(nullptr)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleQuotes);
|
|
CopyFrom(aSource);
|
|
}
|
|
|
|
void
|
|
nsStyleQuotes::SetInitial()
|
|
{
|
|
// The initial value for quotes is the en-US typographic convention:
|
|
// outermost are LEFT and RIGHT DOUBLE QUOTATION MARK, alternating
|
|
// with LEFT and RIGHT SINGLE QUOTATION MARK.
|
|
static const char16_t initialQuotes[8] = {
|
|
0x201C, 0, 0x201D, 0, 0x2018, 0, 0x2019, 0
|
|
};
|
|
|
|
if (NS_SUCCEEDED(AllocateQuotes(2))) {
|
|
SetQuotesAt(0,
|
|
nsDependentString(&initialQuotes[0], 1),
|
|
nsDependentString(&initialQuotes[2], 1));
|
|
SetQuotesAt(1,
|
|
nsDependentString(&initialQuotes[4], 1),
|
|
nsDependentString(&initialQuotes[6], 1));
|
|
}
|
|
}
|
|
|
|
void
|
|
nsStyleQuotes::CopyFrom(const nsStyleQuotes& aSource)
|
|
{
|
|
if (NS_SUCCEEDED(AllocateQuotes(aSource.QuotesCount()))) {
|
|
uint32_t count = (mQuotesCount * 2);
|
|
for (uint32_t index = 0; index < count; index += 2) {
|
|
aSource.GetQuotesAt(index, mQuotes[index], mQuotes[index + 1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
nsChangeHint nsStyleQuotes::CalcDifference(const nsStyleQuotes& aOther) const
|
|
{
|
|
// If the quotes implementation is ever going to change we might not need
|
|
// a framechange here and a reflow should be sufficient. See bug 35768.
|
|
if (mQuotesCount == aOther.mQuotesCount) {
|
|
uint32_t ix = (mQuotesCount * 2);
|
|
while (0 < ix--) {
|
|
if (mQuotes[ix] != aOther.mQuotes[ix]) {
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
}
|
|
}
|
|
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleTextReset
|
|
//
|
|
|
|
nsStyleTextReset::nsStyleTextReset(void)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleTextReset);
|
|
mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE, eStyleUnit_Enumerated);
|
|
mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
|
|
mTextDecorationColor = NS_RGB(0,0,0);
|
|
mTextDecorationStyle =
|
|
NS_STYLE_TEXT_DECORATION_STYLE_SOLID | BORDER_COLOR_FOREGROUND;
|
|
mUnicodeBidi = NS_STYLE_UNICODE_BIDI_NORMAL;
|
|
}
|
|
|
|
nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleTextReset);
|
|
*this = aSource;
|
|
}
|
|
|
|
nsStyleTextReset::~nsStyleTextReset(void)
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleTextReset);
|
|
}
|
|
|
|
nsChangeHint nsStyleTextReset::CalcDifference(const nsStyleTextReset& aOther) const
|
|
{
|
|
if (mVerticalAlign == aOther.mVerticalAlign
|
|
&& mUnicodeBidi == aOther.mUnicodeBidi) {
|
|
uint8_t lineStyle = GetDecorationStyle();
|
|
uint8_t otherLineStyle = aOther.GetDecorationStyle();
|
|
if (mTextDecorationLine != aOther.mTextDecorationLine ||
|
|
lineStyle != otherLineStyle) {
|
|
// Reflow for decoration line style changes only to or from double or
|
|
// wave because that may cause overflow area changes
|
|
if (lineStyle == NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE ||
|
|
lineStyle == NS_STYLE_TEXT_DECORATION_STYLE_WAVY ||
|
|
otherLineStyle == NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE ||
|
|
otherLineStyle == NS_STYLE_TEXT_DECORATION_STYLE_WAVY) {
|
|
return NS_STYLE_HINT_REFLOW;
|
|
}
|
|
// Repaint for other style decoration lines because they must be in
|
|
// default overflow rect
|
|
return NS_STYLE_HINT_VISUAL;
|
|
}
|
|
|
|
// Repaint for decoration color changes
|
|
nscolor decColor, otherDecColor;
|
|
bool isFG, otherIsFG;
|
|
GetDecorationColor(decColor, isFG);
|
|
aOther.GetDecorationColor(otherDecColor, otherIsFG);
|
|
if (isFG != otherIsFG || (!isFG && decColor != otherDecColor)) {
|
|
return NS_STYLE_HINT_VISUAL;
|
|
}
|
|
|
|
if (mTextOverflow != aOther.mTextOverflow) {
|
|
return NS_STYLE_HINT_VISUAL;
|
|
}
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
return NS_STYLE_HINT_REFLOW;
|
|
}
|
|
|
|
// Allowed to return one of NS_STYLE_HINT_NONE, NS_STYLE_HINT_REFLOW
|
|
// or NS_STYLE_HINT_VISUAL. Currently we just return NONE or REFLOW, though.
|
|
// XXXbz can this not return a more specific hint? If that's ever
|
|
// changed, nsStyleBorder::CalcDifference will need changing too.
|
|
static nsChangeHint
|
|
CalcShadowDifference(nsCSSShadowArray* lhs,
|
|
nsCSSShadowArray* rhs)
|
|
{
|
|
if (lhs == rhs)
|
|
return NS_STYLE_HINT_NONE;
|
|
|
|
if (!lhs || !rhs || lhs->Length() != rhs->Length())
|
|
return NS_STYLE_HINT_REFLOW;
|
|
|
|
for (uint32_t i = 0; i < lhs->Length(); ++i) {
|
|
if (*lhs->ShadowAt(i) != *rhs->ShadowAt(i))
|
|
return NS_STYLE_HINT_REFLOW;
|
|
}
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
|
|
// --------------------
|
|
// nsStyleText
|
|
//
|
|
|
|
nsStyleText::nsStyleText(void)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleText);
|
|
mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
|
|
mTextAlignLast = NS_STYLE_TEXT_ALIGN_AUTO;
|
|
mTextAlignTrue = false;
|
|
mTextAlignLastTrue = false;
|
|
mTextTransform = NS_STYLE_TEXT_TRANSFORM_NONE;
|
|
mWhiteSpace = NS_STYLE_WHITESPACE_NORMAL;
|
|
mWordBreak = NS_STYLE_WORDBREAK_NORMAL;
|
|
mWordWrap = NS_STYLE_WORDWRAP_NORMAL;
|
|
mHyphens = NS_STYLE_HYPHENS_MANUAL;
|
|
mTextSizeAdjust = NS_STYLE_TEXT_SIZE_ADJUST_AUTO;
|
|
mTextOrientation = NS_STYLE_TEXT_ORIENTATION_AUTO;
|
|
mTextCombineHorizontal = NS_STYLE_TEXT_COMBINE_HORIZ_NONE;
|
|
mControlCharacterVisibility = NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN;
|
|
|
|
mLetterSpacing.SetNormalValue();
|
|
mLineHeight.SetNormalValue();
|
|
mTextIndent.SetCoordValue(0);
|
|
mWordSpacing = 0;
|
|
|
|
mTextShadow = nullptr;
|
|
mTabSize = NS_STYLE_TABSIZE_INITIAL;
|
|
}
|
|
|
|
nsStyleText::nsStyleText(const nsStyleText& aSource)
|
|
: mTextAlign(aSource.mTextAlign),
|
|
mTextAlignLast(aSource.mTextAlignLast),
|
|
mTextAlignTrue(false),
|
|
mTextAlignLastTrue(false),
|
|
mTextTransform(aSource.mTextTransform),
|
|
mWhiteSpace(aSource.mWhiteSpace),
|
|
mWordBreak(aSource.mWordBreak),
|
|
mWordWrap(aSource.mWordWrap),
|
|
mHyphens(aSource.mHyphens),
|
|
mTextSizeAdjust(aSource.mTextSizeAdjust),
|
|
mTextOrientation(aSource.mTextOrientation),
|
|
mTextCombineHorizontal(aSource.mTextCombineHorizontal),
|
|
mControlCharacterVisibility(aSource.mControlCharacterVisibility),
|
|
mTabSize(aSource.mTabSize),
|
|
mWordSpacing(aSource.mWordSpacing),
|
|
mLetterSpacing(aSource.mLetterSpacing),
|
|
mLineHeight(aSource.mLineHeight),
|
|
mTextIndent(aSource.mTextIndent),
|
|
mTextShadow(aSource.mTextShadow)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleText);
|
|
}
|
|
|
|
nsStyleText::~nsStyleText(void)
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleText);
|
|
}
|
|
|
|
nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aOther) const
|
|
{
|
|
if (WhiteSpaceOrNewlineIsSignificant() !=
|
|
aOther.WhiteSpaceOrNewlineIsSignificant()) {
|
|
// This may require construction of suppressed text frames
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
}
|
|
|
|
if (mTextCombineHorizontal != aOther.mTextCombineHorizontal ||
|
|
mControlCharacterVisibility != aOther.mControlCharacterVisibility) {
|
|
return nsChangeHint_ReconstructFrame;
|
|
}
|
|
|
|
if ((mTextAlign != aOther.mTextAlign) ||
|
|
(mTextAlignLast != aOther.mTextAlignLast) ||
|
|
(mTextAlignTrue != aOther.mTextAlignTrue) ||
|
|
(mTextAlignLastTrue != aOther.mTextAlignLastTrue) ||
|
|
(mTextTransform != aOther.mTextTransform) ||
|
|
(mWhiteSpace != aOther.mWhiteSpace) ||
|
|
(mWordBreak != aOther.mWordBreak) ||
|
|
(mWordWrap != aOther.mWordWrap) ||
|
|
(mHyphens != aOther.mHyphens) ||
|
|
(mTextSizeAdjust != aOther.mTextSizeAdjust) ||
|
|
(mTextOrientation != aOther.mTextOrientation) ||
|
|
(mLetterSpacing != aOther.mLetterSpacing) ||
|
|
(mLineHeight != aOther.mLineHeight) ||
|
|
(mTextIndent != aOther.mTextIndent) ||
|
|
(mWordSpacing != aOther.mWordSpacing) ||
|
|
(mTabSize != aOther.mTabSize))
|
|
return NS_STYLE_HINT_REFLOW;
|
|
|
|
return CalcShadowDifference(mTextShadow, aOther.mTextShadow);
|
|
}
|
|
|
|
//-----------------------
|
|
// nsStyleUserInterface
|
|
//
|
|
|
|
nsCursorImage::nsCursorImage()
|
|
: mHaveHotspot(false)
|
|
, mHotspotX(0.0f)
|
|
, mHotspotY(0.0f)
|
|
{
|
|
}
|
|
|
|
nsCursorImage::nsCursorImage(const nsCursorImage& aOther)
|
|
: mHaveHotspot(aOther.mHaveHotspot)
|
|
, mHotspotX(aOther.mHotspotX)
|
|
, mHotspotY(aOther.mHotspotY)
|
|
{
|
|
SetImage(aOther.GetImage());
|
|
}
|
|
|
|
nsCursorImage::~nsCursorImage()
|
|
{
|
|
SetImage(nullptr);
|
|
}
|
|
|
|
nsCursorImage&
|
|
nsCursorImage::operator=(const nsCursorImage& aOther)
|
|
{
|
|
if (this != &aOther) {
|
|
mHaveHotspot = aOther.mHaveHotspot;
|
|
mHotspotX = aOther.mHotspotX;
|
|
mHotspotY = aOther.mHotspotY;
|
|
SetImage(aOther.GetImage());
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
nsStyleUserInterface::nsStyleUserInterface(void)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleUserInterface);
|
|
mUserInput = NS_STYLE_USER_INPUT_AUTO;
|
|
mUserModify = NS_STYLE_USER_MODIFY_READ_ONLY;
|
|
mUserFocus = NS_STYLE_USER_FOCUS_NONE;
|
|
|
|
mCursor = NS_STYLE_CURSOR_AUTO; // fix for bugzilla bug 51113
|
|
|
|
mCursorArrayLength = 0;
|
|
mCursorArray = nullptr;
|
|
}
|
|
|
|
nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource) :
|
|
mUserInput(aSource.mUserInput),
|
|
mUserModify(aSource.mUserModify),
|
|
mUserFocus(aSource.mUserFocus),
|
|
mCursor(aSource.mCursor)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleUserInterface);
|
|
CopyCursorArrayFrom(aSource);
|
|
}
|
|
|
|
nsStyleUserInterface::~nsStyleUserInterface(void)
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleUserInterface);
|
|
delete [] mCursorArray;
|
|
}
|
|
|
|
nsChangeHint nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aOther) const
|
|
{
|
|
nsChangeHint hint = nsChangeHint(0);
|
|
if (mCursor != aOther.mCursor)
|
|
NS_UpdateHint(hint, nsChangeHint_UpdateCursor);
|
|
|
|
// We could do better. But it wouldn't be worth it, URL-specified cursors are
|
|
// rare.
|
|
if (mCursorArrayLength > 0 || aOther.mCursorArrayLength > 0)
|
|
NS_UpdateHint(hint, nsChangeHint_UpdateCursor);
|
|
|
|
if (mUserModify != aOther.mUserModify)
|
|
NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL);
|
|
|
|
if ((mUserInput != aOther.mUserInput) &&
|
|
((NS_STYLE_USER_INPUT_NONE == mUserInput) ||
|
|
(NS_STYLE_USER_INPUT_NONE == aOther.mUserInput))) {
|
|
NS_UpdateHint(hint, NS_STYLE_HINT_FRAMECHANGE);
|
|
}
|
|
|
|
// ignore mUserFocus
|
|
|
|
return hint;
|
|
}
|
|
|
|
void
|
|
nsStyleUserInterface::CopyCursorArrayFrom(const nsStyleUserInterface& aSource)
|
|
{
|
|
mCursorArray = nullptr;
|
|
mCursorArrayLength = 0;
|
|
if (aSource.mCursorArrayLength) {
|
|
mCursorArray = new nsCursorImage[aSource.mCursorArrayLength];
|
|
if (mCursorArray) {
|
|
mCursorArrayLength = aSource.mCursorArrayLength;
|
|
for (uint32_t i = 0; i < mCursorArrayLength; ++i)
|
|
mCursorArray[i] = aSource.mCursorArray[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------
|
|
// nsStyleUIReset
|
|
//
|
|
|
|
nsStyleUIReset::nsStyleUIReset(void)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleUIReset);
|
|
mUserSelect = NS_STYLE_USER_SELECT_AUTO;
|
|
mForceBrokenImageIcon = 0;
|
|
mIMEMode = NS_STYLE_IME_MODE_AUTO;
|
|
mWindowShadow = NS_STYLE_WINDOW_SHADOW_DEFAULT;
|
|
}
|
|
|
|
nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleUIReset);
|
|
mUserSelect = aSource.mUserSelect;
|
|
mForceBrokenImageIcon = aSource.mForceBrokenImageIcon;
|
|
mIMEMode = aSource.mIMEMode;
|
|
mWindowShadow = aSource.mWindowShadow;
|
|
}
|
|
|
|
nsStyleUIReset::~nsStyleUIReset(void)
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleUIReset);
|
|
}
|
|
|
|
nsChangeHint nsStyleUIReset::CalcDifference(const nsStyleUIReset& aOther) const
|
|
{
|
|
// ignore mIMEMode
|
|
if (mForceBrokenImageIcon != aOther.mForceBrokenImageIcon)
|
|
return NS_STYLE_HINT_FRAMECHANGE;
|
|
if (mWindowShadow != aOther.mWindowShadow) {
|
|
// We really need just an nsChangeHint_SyncFrameView, except
|
|
// on an ancestor of the frame, so we get that by doing a
|
|
// reflow.
|
|
return NS_STYLE_HINT_REFLOW;
|
|
}
|
|
if (mUserSelect != aOther.mUserSelect)
|
|
return NS_STYLE_HINT_VISUAL;
|
|
return NS_STYLE_HINT_NONE;
|
|
}
|
|
|
|
//-----------------------
|
|
// nsStyleVariables
|
|
//
|
|
|
|
nsStyleVariables::nsStyleVariables()
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleVariables);
|
|
}
|
|
|
|
nsStyleVariables::nsStyleVariables(const nsStyleVariables& aSource)
|
|
{
|
|
MOZ_COUNT_CTOR(nsStyleVariables);
|
|
}
|
|
|
|
nsStyleVariables::~nsStyleVariables(void)
|
|
{
|
|
MOZ_COUNT_DTOR(nsStyleVariables);
|
|
}
|
|
|
|
nsChangeHint
|
|
nsStyleVariables::CalcDifference(const nsStyleVariables& aOther) const
|
|
{
|
|
return nsChangeHint(0);
|
|
}
|