mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 767647 - Stop invalidating once for every SVG descendant of a changed SVG container, and stop invalidating the descendants' rendering observers. r=longsonr.
This commit is contained in:
parent
c26da70420
commit
95ea2cc074
@ -369,6 +369,17 @@ nsSVGUseElement::DestroyAnonymousContent()
|
|||||||
nsContentUtils::DestroyAnonymousContent(&mClone);
|
nsContentUtils::DestroyAnonymousContent(&mClone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsSVGUseElement::OurWidthAndHeightAreUsed() const
|
||||||
|
{
|
||||||
|
if (mClone) {
|
||||||
|
nsCOMPtr<nsIDOMSVGSVGElement> svg = do_QueryInterface(mClone);
|
||||||
|
nsCOMPtr<nsIDOMSVGSymbolElement> symbol = do_QueryInterface(mClone);
|
||||||
|
return svg || symbol;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// implementation helpers
|
// implementation helpers
|
||||||
|
|
||||||
@ -377,6 +388,7 @@ nsSVGUseElement::SyncWidthOrHeight(nsIAtom* aName)
|
|||||||
{
|
{
|
||||||
NS_ASSERTION(aName == nsGkAtoms::width || aName == nsGkAtoms::height,
|
NS_ASSERTION(aName == nsGkAtoms::width || aName == nsGkAtoms::height,
|
||||||
"The clue is in the function name");
|
"The clue is in the function name");
|
||||||
|
NS_ASSERTION(OurWidthAndHeightAreUsed(), "Don't call this");
|
||||||
|
|
||||||
if (!mClone) {
|
if (!mClone) {
|
||||||
return;
|
return;
|
||||||
|
@ -102,6 +102,12 @@ protected:
|
|||||||
virtual LengthAttributesInfo GetLengthInfo();
|
virtual LengthAttributesInfo GetLengthInfo();
|
||||||
virtual StringAttributesInfo GetStringInfo();
|
virtual StringAttributesInfo GetStringInfo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if our width and height should be used, or false if they
|
||||||
|
* should be ignored. As per the spec, this depends on the type of the
|
||||||
|
* element that we're referencing.
|
||||||
|
*/
|
||||||
|
bool OurWidthAndHeightAreUsed() const;
|
||||||
void SyncWidthOrHeight(nsIAtom *aName);
|
void SyncWidthOrHeight(nsIAtom *aName);
|
||||||
void LookupHref();
|
void LookupHref();
|
||||||
void TriggerReclone();
|
void TriggerReclone();
|
||||||
|
@ -80,6 +80,15 @@ public:
|
|||||||
COORD_CONTEXT_CHANGED = 0x04,
|
COORD_CONTEXT_CHANGED = 0x04,
|
||||||
FULL_ZOOM_CHANGED = 0x08
|
FULL_ZOOM_CHANGED = 0x08
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* This is called on a frame when there has been a change to one of its
|
||||||
|
* ancestors that might affect the frame too. SVGChangedFlags are passed
|
||||||
|
* to indicate what changed.
|
||||||
|
*
|
||||||
|
* Implementations do not need to invalidate, since the caller will
|
||||||
|
* invalidate the entire area of the ancestor that changed. However, they
|
||||||
|
* may need to update their bounds.
|
||||||
|
*/
|
||||||
virtual void NotifySVGChanged(PRUint32 aFlags)=0;
|
virtual void NotifySVGChanged(PRUint32 aFlags)=0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,7 +106,7 @@ nsSVGAFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||||||
{
|
{
|
||||||
if (aNameSpaceID == kNameSpaceID_None &&
|
if (aNameSpaceID == kNameSpaceID_None &&
|
||||||
aAttribute == nsGkAtoms::transform) {
|
aAttribute == nsGkAtoms::transform) {
|
||||||
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
NotifySVGChanged(TRANSFORM_CHANGED);
|
NotifySVGChanged(TRANSFORM_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,8 +278,13 @@ nsSVGDisplayContainerFrame::UpdateBounds()
|
|||||||
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
||||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||||
|
|
||||||
// XXXSDL Make Invalidate() call nsSVGUtils::InvalidateBounds(this)
|
if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||||
// so that we invalidate under FinishAndStoreOverflow().
|
// We only invalidate if our outer-<svg> has already had its
|
||||||
|
// initial reflow (since if it hasn't, its entire area will be
|
||||||
|
// invalidated when it gets that initial reflow):
|
||||||
|
// XXXSDL Let FinishAndStoreOverflow do this.
|
||||||
|
nsSVGUtils::InvalidateBounds(this, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -425,7 +425,9 @@ nsSVGForeignObjectFrame::NotifySVGChanged(PRUint32 aFlags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (aFlags & TRANSFORM_CHANGED) {
|
if (aFlags & TRANSFORM_CHANGED) {
|
||||||
needNewBounds = true; // needed if it was _our_ transform that changed
|
if (mCanvasTM && mCanvasTM->IsSingular()) {
|
||||||
|
needNewBounds = true; // old bounds are bogus
|
||||||
|
}
|
||||||
needNewCanvasTM = true;
|
needNewCanvasTM = true;
|
||||||
// In an ideal world we would reflow when our CTM changes. This is because
|
// In an ideal world we would reflow when our CTM changes. This is because
|
||||||
// glyph metrics do not necessarily scale uniformly with change in scale
|
// glyph metrics do not necessarily scale uniformly with change in scale
|
||||||
@ -436,9 +438,13 @@ nsSVGForeignObjectFrame::NotifySVGChanged(PRUint32 aFlags)
|
|||||||
// reflow.
|
// reflow.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needNewBounds &&
|
if (needNewBounds) {
|
||||||
!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS)) {
|
// Ancestor changes can't affect how we render from the perspective of
|
||||||
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
// any rendering observers that we may have, so we don't need to
|
||||||
|
// invalidate them. We also don't need to invalidate ourself, since our
|
||||||
|
// changed ancestor will have invalidated its entire area, which includes
|
||||||
|
// our area.
|
||||||
|
nsSVGUtils::ScheduleBoundsUpdate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're called while the PresShell is handling reflow events then we
|
// If we're called while the PresShell is handling reflow events then we
|
||||||
|
@ -88,7 +88,7 @@ nsSVGGFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||||||
{
|
{
|
||||||
if (aNameSpaceID == kNameSpaceID_None &&
|
if (aNameSpaceID == kNameSpaceID_None &&
|
||||||
aAttribute == nsGkAtoms::transform) {
|
aAttribute == nsGkAtoms::transform) {
|
||||||
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
NotifySVGChanged(TRANSFORM_CHANGED);
|
NotifySVGChanged(TRANSFORM_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,11 +506,14 @@ nsSVGGlyphFrame::NotifySVGChanged(PRUint32 aFlags)
|
|||||||
NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
|
NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
|
||||||
"Invalidation logic may need adjusting");
|
"Invalidation logic may need adjusting");
|
||||||
|
|
||||||
// XXXjwatt: seems to me that this could change the glyph metrics,
|
// Ancestor changes can't affect how we render from the perspective of
|
||||||
// in which case we should call NotifyGlyphMetricsChange instead.
|
// any rendering observers that we may have, so we don't need to
|
||||||
if (!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS)) {
|
// invalidate them. We also don't need to invalidate ourself, since our
|
||||||
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
// changed ancestor will have invalidated its entire area, which includes
|
||||||
}
|
// our area.
|
||||||
|
// XXXjwatt: seems to me that our ancestor's change could change our glyph
|
||||||
|
// metrics, in which case we should call NotifyGlyphMetricsChange instead.
|
||||||
|
nsSVGUtils::ScheduleBoundsUpdate(this);
|
||||||
|
|
||||||
if (aFlags & TRANSFORM_CHANGED) {
|
if (aFlags & TRANSFORM_CHANGED) {
|
||||||
ClearTextRun();
|
ClearTextRun();
|
||||||
|
@ -104,27 +104,40 @@ nsSVGInnerSVGFrame::NotifySVGChanged(PRUint32 aFlags)
|
|||||||
NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
|
NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
|
||||||
"Invalidation logic may need adjusting");
|
"Invalidation logic may need adjusting");
|
||||||
|
|
||||||
|
bool updateBounds = false;
|
||||||
|
|
||||||
if (aFlags & COORD_CONTEXT_CHANGED) {
|
if (aFlags & COORD_CONTEXT_CHANGED) {
|
||||||
|
|
||||||
nsSVGSVGElement *svg = static_cast<nsSVGSVGElement*>(mContent);
|
nsSVGSVGElement *svg = static_cast<nsSVGSVGElement*>(mContent);
|
||||||
|
|
||||||
|
bool xOrYIsPercentage =
|
||||||
|
svg->mLengthAttributes[nsSVGSVGElement::X].IsPercentage() ||
|
||||||
|
svg->mLengthAttributes[nsSVGSVGElement::Y].IsPercentage();
|
||||||
|
bool widthOrHeightIsPercentage =
|
||||||
|
svg->mLengthAttributes[nsSVGSVGElement::WIDTH].IsPercentage() ||
|
||||||
|
svg->mLengthAttributes[nsSVGSVGElement::HEIGHT].IsPercentage();
|
||||||
|
|
||||||
|
if (xOrYIsPercentage || widthOrHeightIsPercentage) {
|
||||||
|
// Ancestor changes can't affect how we render from the perspective of
|
||||||
|
// any rendering observers that we may have, so we don't need to
|
||||||
|
// invalidate them. We also don't need to invalidate ourself, since our
|
||||||
|
// changed ancestor will have invalidated its entire area, which includes
|
||||||
|
// our area.
|
||||||
|
// For perf reasons we call this before calling NotifySVGChanged() below.
|
||||||
|
nsSVGUtils::ScheduleBoundsUpdate(this);
|
||||||
|
}
|
||||||
|
|
||||||
// Coordinate context changes affect mCanvasTM if we have a
|
// Coordinate context changes affect mCanvasTM if we have a
|
||||||
// percentage 'x' or 'y', or if we have a percentage 'width' or 'height' AND
|
// percentage 'x' or 'y', or if we have a percentage 'width' or 'height' AND
|
||||||
// a 'viewBox'.
|
// a 'viewBox'.
|
||||||
|
|
||||||
if (!(aFlags & TRANSFORM_CHANGED) &&
|
if (!(aFlags & TRANSFORM_CHANGED) &&
|
||||||
(svg->mLengthAttributes[nsSVGSVGElement::X].IsPercentage() ||
|
(xOrYIsPercentage ||
|
||||||
svg->mLengthAttributes[nsSVGSVGElement::Y].IsPercentage() ||
|
(widthOrHeightIsPercentage && svg->HasViewBox()))) {
|
||||||
(svg->HasViewBox() &&
|
|
||||||
(svg->mLengthAttributes[nsSVGSVGElement::WIDTH].IsPercentage() ||
|
|
||||||
svg->mLengthAttributes[nsSVGSVGElement::HEIGHT].IsPercentage())))) {
|
|
||||||
|
|
||||||
aFlags |= TRANSFORM_CHANGED;
|
aFlags |= TRANSFORM_CHANGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svg->HasViewBox() ||
|
if (svg->HasViewBox() || !widthOrHeightIsPercentage) {
|
||||||
(!svg->mLengthAttributes[nsSVGSVGElement::WIDTH].IsPercentage() &&
|
|
||||||
!svg->mLengthAttributes[nsSVGSVGElement::HEIGHT].IsPercentage())) {
|
|
||||||
// Remove COORD_CONTEXT_CHANGED, since we establish the coordinate
|
// Remove COORD_CONTEXT_CHANGED, since we establish the coordinate
|
||||||
// context for our descendants and this notification won't change its
|
// context for our descendants and this notification won't change its
|
||||||
// dimensions:
|
// dimensions:
|
||||||
@ -155,6 +168,7 @@ nsSVGInnerSVGFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||||||
|
|
||||||
if (aAttribute == nsGkAtoms::width ||
|
if (aAttribute == nsGkAtoms::width ||
|
||||||
aAttribute == nsGkAtoms::height) {
|
aAttribute == nsGkAtoms::height) {
|
||||||
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
|
|
||||||
if (content->HasViewBoxOrSyntheticViewBox()) {
|
if (content->HasViewBoxOrSyntheticViewBox()) {
|
||||||
// make sure our cached transform matrix gets (lazily) updated
|
// make sure our cached transform matrix gets (lazily) updated
|
||||||
@ -178,6 +192,8 @@ nsSVGInnerSVGFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||||||
// make sure our cached transform matrix gets (lazily) updated
|
// make sure our cached transform matrix gets (lazily) updated
|
||||||
mCanvasTM = nsnull;
|
mCanvasTM = nsnull;
|
||||||
|
|
||||||
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
|
|
||||||
nsSVGUtils::NotifyChildrenOfSVGChange(
|
nsSVGUtils::NotifyChildrenOfSVGChange(
|
||||||
this, aAttribute == nsGkAtoms::viewBox ?
|
this, aAttribute == nsGkAtoms::viewBox ?
|
||||||
TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED);
|
TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED);
|
||||||
|
@ -265,9 +265,12 @@ nsSVGPathGeometryFrame::NotifySVGChanged(PRUint32 aFlags)
|
|||||||
NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
|
NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
|
||||||
"Invalidation logic may need adjusting");
|
"Invalidation logic may need adjusting");
|
||||||
|
|
||||||
if (!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS)) {
|
// Ancestor changes can't affect how we render from the perspective of
|
||||||
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
// any rendering observers that we may have, so we don't need to
|
||||||
}
|
// invalidate them. We also don't need to invalidate ourself, since our
|
||||||
|
// changed ancestor will have invalidated its entire area, which includes
|
||||||
|
// our area.
|
||||||
|
nsSVGUtils::ScheduleBoundsUpdate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SVGBBox
|
SVGBBox
|
||||||
|
@ -191,8 +191,13 @@ nsSVGSwitchFrame::UpdateBounds()
|
|||||||
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
|
||||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||||
|
|
||||||
// XXXSDL Make Invalidate() call nsSVGUtils::InvalidateBounds(this)
|
if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||||
// so that we invalidate under FinishAndStoreOverflow().
|
// We only invalidate if our outer-<svg> has already had its
|
||||||
|
// initial reflow (since if it hasn't, its entire area will be
|
||||||
|
// invalidated when it gets that initial reflow):
|
||||||
|
// XXXSDL Let FinishAndStoreOverflow do this.
|
||||||
|
nsSVGUtils::InvalidateBounds(this, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SVGBBox
|
SVGBBox
|
||||||
|
@ -79,6 +79,7 @@ nsSVGTSpanFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||||||
aAttribute == nsGkAtoms::dx ||
|
aAttribute == nsGkAtoms::dx ||
|
||||||
aAttribute == nsGkAtoms::dy ||
|
aAttribute == nsGkAtoms::dy ||
|
||||||
aAttribute == nsGkAtoms::rotate)) {
|
aAttribute == nsGkAtoms::rotate)) {
|
||||||
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
NotifyGlyphMetricsChange();
|
NotifyGlyphMetricsChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,14 +55,14 @@ nsSVGTextFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
if (aAttribute == nsGkAtoms::transform) {
|
if (aAttribute == nsGkAtoms::transform) {
|
||||||
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
NotifySVGChanged(TRANSFORM_CHANGED);
|
NotifySVGChanged(TRANSFORM_CHANGED);
|
||||||
|
|
||||||
} else if (aAttribute == nsGkAtoms::x ||
|
} else if (aAttribute == nsGkAtoms::x ||
|
||||||
aAttribute == nsGkAtoms::y ||
|
aAttribute == nsGkAtoms::y ||
|
||||||
aAttribute == nsGkAtoms::dx ||
|
aAttribute == nsGkAtoms::dx ||
|
||||||
aAttribute == nsGkAtoms::dy ||
|
aAttribute == nsGkAtoms::dy ||
|
||||||
aAttribute == nsGkAtoms::rotate) {
|
aAttribute == nsGkAtoms::rotate) {
|
||||||
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
NotifyGlyphMetricsChange();
|
NotifyGlyphMetricsChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,6 +169,16 @@ nsSVGTextFrame::NotifySVGChanged(PRUint32 aFlags)
|
|||||||
mCanvasTM = nsnull;
|
mCanvasTM = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updateGlyphMetrics) {
|
||||||
|
// Ancestor changes can't affect how we render from the perspective of
|
||||||
|
// any rendering observers that we may have, so we don't need to
|
||||||
|
// invalidate them. We also don't need to invalidate ourself, since our
|
||||||
|
// changed ancestor will have invalidated its entire area, which includes
|
||||||
|
// our area.
|
||||||
|
// For perf reasons we call this before calling NotifySVGChanged() below.
|
||||||
|
nsSVGUtils::ScheduleBoundsUpdate(this);
|
||||||
|
}
|
||||||
|
|
||||||
nsSVGTextFrameBase::NotifySVGChanged(aFlags);
|
nsSVGTextFrameBase::NotifySVGChanged(aFlags);
|
||||||
|
|
||||||
if (updateGlyphMetrics) {
|
if (updateGlyphMetrics) {
|
||||||
@ -224,8 +234,13 @@ nsSVGTextFrame::UpdateBounds()
|
|||||||
// areas correctly:
|
// areas correctly:
|
||||||
nsSVGTextFrameBase::UpdateBounds();
|
nsSVGTextFrameBase::UpdateBounds();
|
||||||
|
|
||||||
// XXXSDL once we store bounds on containers, call
|
if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||||
// nsSVGUtils::InvalidateBounds(this) if not first reflow.
|
// We only invalidate if our outer-<svg> has already had its
|
||||||
|
// initial reflow (since if it hasn't, its entire area will be
|
||||||
|
// invalidated when it gets that initial reflow):
|
||||||
|
// XXXSDL Let FinishAndStoreOverflow do this.
|
||||||
|
nsSVGUtils::InvalidateBounds(this, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SVGBBox
|
SVGBBox
|
||||||
@ -260,9 +275,32 @@ nsSVGTextFrame::GetCanvasTM()
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
|
|
||||||
|
static void
|
||||||
|
MarkDirtyBitsOnDescendants(nsIFrame *aFrame)
|
||||||
|
{
|
||||||
|
if (aFrame->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_FIRST_REFLOW)) {
|
||||||
|
// Nothing to do if we're already dirty, or if the outer-<svg>
|
||||||
|
// hasn't yet had its initial reflow.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nsIFrame* kid = aFrame->GetFirstPrincipalChild();
|
||||||
|
while (kid) {
|
||||||
|
nsISVGChildFrame* svgkid = do_QueryFrame(kid);
|
||||||
|
if (svgkid && !(kid->GetStateBits() & NS_FRAME_IS_DIRTY)) {
|
||||||
|
MarkDirtyBitsOnDescendants(kid);
|
||||||
|
kid->AddStateBits(NS_FRAME_IS_DIRTY);
|
||||||
|
}
|
||||||
|
kid = kid->GetNextSibling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsSVGTextFrame::NotifyGlyphMetricsChange()
|
nsSVGTextFrame::NotifyGlyphMetricsChange()
|
||||||
{
|
{
|
||||||
|
// NotifySVGChanged isn't appropriate here, so we just mark our descendants
|
||||||
|
// as fully dirty to get UpdateBounds() called on them:
|
||||||
|
MarkDirtyBitsOnDescendants(this);
|
||||||
|
|
||||||
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
|
|
||||||
mPositioningDirty = true;
|
mPositioningDirty = true;
|
||||||
|
@ -158,9 +158,11 @@ nsSVGTextPathFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||||||
{
|
{
|
||||||
if (aNameSpaceID == kNameSpaceID_None &&
|
if (aNameSpaceID == kNameSpaceID_None &&
|
||||||
aAttribute == nsGkAtoms::startOffset) {
|
aAttribute == nsGkAtoms::startOffset) {
|
||||||
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
NotifyGlyphMetricsChange();
|
NotifyGlyphMetricsChange();
|
||||||
} else if (aNameSpaceID == kNameSpaceID_XLink &&
|
} else if (aNameSpaceID == kNameSpaceID_XLink &&
|
||||||
aAttribute == nsGkAtoms::href) {
|
aAttribute == nsGkAtoms::href) {
|
||||||
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
// Blow away our reference, if any
|
// Blow away our reference, if any
|
||||||
Properties().Delete(nsSVGEffects::HrefProperty());
|
Properties().Delete(nsSVGEffects::HrefProperty());
|
||||||
NotifyGlyphMetricsChange();
|
NotifyGlyphMetricsChange();
|
||||||
|
@ -116,31 +116,37 @@ nsSVGUseFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||||||
nsIAtom* aAttribute,
|
nsIAtom* aAttribute,
|
||||||
PRInt32 aModType)
|
PRInt32 aModType)
|
||||||
{
|
{
|
||||||
|
nsSVGUseElement *useElement = static_cast<nsSVGUseElement*>(mContent);
|
||||||
|
|
||||||
if (aNameSpaceID == kNameSpaceID_None) {
|
if (aNameSpaceID == kNameSpaceID_None) {
|
||||||
if (aAttribute == nsGkAtoms::x ||
|
if (aAttribute == nsGkAtoms::x ||
|
||||||
aAttribute == nsGkAtoms::y) {
|
aAttribute == nsGkAtoms::y) {
|
||||||
// make sure our cached transform matrix gets (lazily) updated
|
// make sure our cached transform matrix gets (lazily) updated
|
||||||
mCanvasTM = nsnull;
|
mCanvasTM = nsnull;
|
||||||
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
|
nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
|
||||||
} else if (aAttribute == nsGkAtoms::width ||
|
} else if (aAttribute == nsGkAtoms::width ||
|
||||||
aAttribute == nsGkAtoms::height) {
|
aAttribute == nsGkAtoms::height) {
|
||||||
static_cast<nsSVGUseElement*>(mContent)->SyncWidthOrHeight(aAttribute);
|
bool invalidate = false;
|
||||||
|
if (mHasValidDimensions != useElement->HasValidDimensions()) {
|
||||||
if (mHasValidDimensions !=
|
|
||||||
static_cast<nsSVGUseElement*>(mContent)->HasValidDimensions()) {
|
|
||||||
|
|
||||||
mHasValidDimensions = !mHasValidDimensions;
|
mHasValidDimensions = !mHasValidDimensions;
|
||||||
|
invalidate = true;
|
||||||
|
}
|
||||||
|
if (useElement->OurWidthAndHeightAreUsed()) {
|
||||||
|
invalidate = true;
|
||||||
|
useElement->SyncWidthOrHeight(aAttribute);
|
||||||
|
}
|
||||||
|
if (invalidate) {
|
||||||
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (aNameSpaceID == kNameSpaceID_XLink &&
|
} else if (aNameSpaceID == kNameSpaceID_XLink &&
|
||||||
aAttribute == nsGkAtoms::href) {
|
aAttribute == nsGkAtoms::href) {
|
||||||
// we're changing our nature, clear out the clone information
|
// we're changing our nature, clear out the clone information
|
||||||
nsSVGUseElement *use = static_cast<nsSVGUseElement*>(mContent);
|
nsSVGUtils::InvalidateAndScheduleBoundsUpdate(this);
|
||||||
use->mOriginal = nsnull;
|
useElement->mOriginal = nsnull;
|
||||||
use->UnlinkSource();
|
useElement->UnlinkSource();
|
||||||
use->TriggerReclone();
|
useElement->TriggerReclone();
|
||||||
}
|
}
|
||||||
|
|
||||||
return nsSVGUseFrameBase::AttributeChanged(aNameSpaceID,
|
return nsSVGUseFrameBase::AttributeChanged(aNameSpaceID,
|
||||||
@ -191,6 +197,13 @@ nsSVGUseFrame::NotifySVGChanged(PRUint32 aFlags)
|
|||||||
if (use->mLengthAttributes[nsSVGUseElement::X].IsPercentage() ||
|
if (use->mLengthAttributes[nsSVGUseElement::X].IsPercentage() ||
|
||||||
use->mLengthAttributes[nsSVGUseElement::Y].IsPercentage()) {
|
use->mLengthAttributes[nsSVGUseElement::Y].IsPercentage()) {
|
||||||
aFlags |= TRANSFORM_CHANGED;
|
aFlags |= TRANSFORM_CHANGED;
|
||||||
|
// Ancestor changes can't affect how we render from the perspective of
|
||||||
|
// any rendering observers that we may have, so we don't need to
|
||||||
|
// invalidate them. We also don't need to invalidate ourself, since our
|
||||||
|
// changed ancestor will have invalidated its entire area, which includes
|
||||||
|
// our area.
|
||||||
|
// For perf reasons we call this before calling NotifySVGChanged() below.
|
||||||
|
nsSVGUtils::ScheduleBoundsUpdate(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,25 +726,6 @@ nsSVGUtils::InvalidateBounds(nsIFrame *aFrame, bool aDuringUpdate)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
MarkDirtyBitsOnDescendants(nsIFrame *aFrame)
|
|
||||||
{
|
|
||||||
NS_ABORT_IF_FALSE(aFrame->IsFrameOfType(nsIFrame::eSVG),
|
|
||||||
"Passed bad frame!");
|
|
||||||
|
|
||||||
nsIFrame* kid = aFrame->GetFirstPrincipalChild();
|
|
||||||
while (kid) {
|
|
||||||
nsISVGChildFrame* svgkid = do_QueryFrame(kid);
|
|
||||||
if (svgkid &&
|
|
||||||
!(kid->GetStateBits() &
|
|
||||||
(NS_STATE_SVG_NONDISPLAY_CHILD | NS_FRAME_IS_DIRTY))) {
|
|
||||||
MarkDirtyBitsOnDescendants(kid);
|
|
||||||
kid->AddStateBits(NS_FRAME_IS_DIRTY);
|
|
||||||
}
|
|
||||||
kid = kid->GetNextSibling();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsSVGUtils::ScheduleBoundsUpdate(nsIFrame *aFrame)
|
nsSVGUtils::ScheduleBoundsUpdate(nsIFrame *aFrame)
|
||||||
{
|
{
|
||||||
@ -773,10 +754,6 @@ nsSVGUtils::ScheduleBoundsUpdate(nsIFrame *aFrame)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXXSDL once we store bounds on containers, we will not need to
|
|
||||||
// mark our descendants dirty.
|
|
||||||
MarkDirtyBitsOnDescendants(aFrame);
|
|
||||||
|
|
||||||
nsSVGOuterSVGFrame *outerSVGFrame = nsnull;
|
nsSVGOuterSVGFrame *outerSVGFrame = nsnull;
|
||||||
|
|
||||||
// We must not add dirty bits to the nsSVGOuterSVGFrame or else
|
// We must not add dirty bits to the nsSVGOuterSVGFrame or else
|
||||||
|
@ -477,8 +477,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
static gfxMatrix GetCanvasTM(nsIFrame* aFrame);
|
static gfxMatrix GetCanvasTM(nsIFrame* aFrame);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Tells child frames that something that might affect them has changed
|
* Notify the descendants of aFrame of a change to one of their ancestors
|
||||||
|
* that might affect them.
|
||||||
|
*
|
||||||
|
* If the changed ancestor renders and needs to be invalidated, it should
|
||||||
|
* call nsSVGUtils::InvalidateAndScheduleBoundsUpdate or
|
||||||
|
* nsSVGUtils::InvalidateBounds _before_ calling this method. That makes it
|
||||||
|
* cheaper when descendants schedule their own bounds update because the code
|
||||||
|
* that walks up the parent chain marking dirty bits can stop earlier.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
NotifyChildrenOfSVGChange(nsIFrame *aFrame, PRUint32 aFlags);
|
NotifyChildrenOfSVGChange(nsIFrame *aFrame, PRUint32 aFlags);
|
||||||
|
Loading…
Reference in New Issue
Block a user