Bug 411555 - Text inside filter causing invalidation loop. r=jwat,sr=tor,a1.9=blocking1.9+

This commit is contained in:
longsonr@gmail.com 2008-01-25 01:27:03 -08:00
parent 8168a9e086
commit 0cf4994554
29 changed files with 236 additions and 163 deletions

View File

@ -99,10 +99,12 @@ NS_IMETHODIMP nsSVGGraphicElement::GetBBox(nsIDOMSVGRect **_retval)
NS_ASSERTION(svgframe, "wrong frame type");
if (svgframe) {
svgframe->SetMatrixPropagation(PR_FALSE);
svgframe->NotifyCanvasTMChanged(PR_TRUE);
svgframe->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
nsresult rv = svgframe->GetBBox(_retval);
svgframe->SetMatrixPropagation(PR_TRUE);
svgframe->NotifyCanvasTMChanged(PR_TRUE);
svgframe->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
return rv;
}
return NS_ERROR_FAILURE;

View File

@ -71,6 +71,8 @@ public:
PRUint8 GetCtxType() const { return mCtxType; }
PRUint8 GetSpecifiedUnitType() const { return mSpecifiedUnitType; }
PRBool IsPercentage() const
{ return mSpecifiedUnitType == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE; }
float GetAnimValInSpecifiedUnits() const { return mAnimVal; }
float GetBaseValInSpecifiedUnits() const { return mBaseVal; }

View File

@ -681,10 +681,12 @@ nsSVGSVGElement::GetBBox(nsIDOMSVGRect **_retval)
CallQueryInterface(frame, &svgframe);
if (svgframe) {
svgframe->SetMatrixPropagation(PR_FALSE);
svgframe->NotifyCanvasTMChanged(PR_TRUE);
svgframe->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
nsresult rv = svgframe->GetBBox(_retval);
svgframe->SetMatrixPropagation(PR_TRUE);
svgframe->NotifyCanvasTMChanged(PR_TRUE);
svgframe->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
return rv;
} else {
// XXX: outer svg

View File

@ -51,8 +51,8 @@ class nsSVGRenderState;
struct nsRect;
#define NS_ISVGCHILDFRAME_IID \
{ 0x93560e72, 0x6818, 0x4218, \
{ 0xa1, 0xe9, 0xf3, 0xb9, 0x63, 0x6a, 0xff, 0xc2 } }
{ 0x667e8781, 0x72bd, 0x4344, \
{ 0x95, 0x8c, 0x69, 0xa5, 0x70, 0xc4, 0xcc, 0xb3 } }
class nsISVGChildFrame : public nsISupports {
public:
@ -84,7 +84,19 @@ public:
// into the frame tree (if they're inserted after the initial reflow).
NS_IMETHOD InitialUpdate()=0;
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation)=0;
// Flags to pass to NotifySVGChange:
//
// SUPPRESS_INVALIDATION - do not invalidate rendered areas (only to be
// used in conjunction with TRANSFORM_CHANGED)
// TRANSFORM_CHANGED - the current transform matrix for this frame has changed
// COORD_CONTEXT_CHANGED - the dimensions of this frame's coordinate context has
// changed (percentage lengths must be reevaluated)
enum SVGChangedFlags {
SUPPRESS_INVALIDATION = 0x01,
TRANSFORM_CHANGED = 0x02,
COORD_CONTEXT_CHANGED = 0x04
};
virtual void NotifySVGChanged(PRUint32 aFlags)=0;
NS_IMETHOD NotifyRedrawSuspended()=0;
NS_IMETHOD NotifyRedrawUnsuspended()=0;

View File

@ -81,7 +81,7 @@ public:
}
#endif
// nsISVGChildFrame interface:
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation);
virtual void NotifySVGChanged(PRUint32 aFlags);
// nsSVGContainerFrame methods:
virtual already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
@ -123,14 +123,7 @@ nsSVGAFrame::AttributeChanged(PRInt32 aNameSpaceID,
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
nsIFrame* kid = mFrames.FirstChild();
while (kid) {
nsISVGChildFrame* SVGFrame = nsnull;
CallQueryInterface(kid, &SVGFrame);
if (SVGFrame)
SVGFrame->NotifyCanvasTMChanged(PR_FALSE);
kid = kid->GetNextSibling();
}
nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
}
return NS_OK;
@ -153,13 +146,15 @@ nsSVGAFrame::GetType() const
//----------------------------------------------------------------------
// nsISVGChildFrame methods
NS_IMETHODIMP
nsSVGAFrame::NotifyCanvasTMChanged(PRBool suppressInvalidation)
void
nsSVGAFrame::NotifySVGChanged(PRUint32 aFlags)
{
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
if (aFlags & TRANSFORM_CHANGED) {
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
}
return nsSVGAFrameBase::NotifyCanvasTMChanged(suppressInvalidation);
nsSVGAFrameBase::NotifySVGChanged(aFlags);
}
//----------------------------------------------------------------------

View File

@ -100,7 +100,9 @@ nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
nsISVGChildFrame* SVGFrame = nsnull;
CallQueryInterface(kid, &SVGFrame);
if (SVGFrame) {
SVGFrame->NotifyCanvasTMChanged(PR_TRUE);
// The CTM of each frame referencing us can be different.
SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
SVGFrame->PaintSVG(aContext, nsnull);
}
}
@ -139,7 +141,7 @@ nsSVGClipPathFrame::ClipHitTest(nsISVGChildFrame* aParent,
// Notify the child frame that we may be working with a
// different transform, so it can update its covered region
// (used to shortcut hit testing).
SVGFrame->NotifyCanvasTMChanged(PR_FALSE);
SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);
nsIFrame *temp = nsnull;
nsresult rv = SVGFrame->GetFrameForPointSVG(aX, aY, &temp);

View File

@ -241,15 +241,17 @@ nsSVGDisplayContainerFrame::InitialUpdate()
return NS_OK;
}
NS_IMETHODIMP
nsSVGDisplayContainerFrame::NotifyCanvasTMChanged(PRBool suppressInvalidation)
void
nsSVGDisplayContainerFrame::NotifySVGChanged(PRUint32 aFlags)
{
if (!suppressInvalidation &&
NS_ASSERTION(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
"Invalidation logic may need adjusting");
if (!(aFlags & SUPPRESS_INVALIDATION) &&
!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD))
nsSVGUtils::UpdateFilterRegion(this);
nsSVGUtils::NotifyChildrenCanvasTMChanged(this, suppressInvalidation);
return NS_OK;
nsSVGUtils::NotifyChildrenOfSVGChange(this, aFlags);
}
NS_IMETHODIMP

View File

@ -107,7 +107,7 @@ public:
NS_IMETHOD_(nsRect) GetCoveredRegion();
NS_IMETHOD UpdateCoveredRegion();
NS_IMETHOD InitialUpdate();
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation);
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD NotifyRedrawSuspended();
NS_IMETHOD NotifyRedrawUnsuspended();
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate) { return NS_ERROR_FAILURE; }

View File

@ -79,7 +79,8 @@ nsSVGFilterFrame::FilterFailCleanup(nsSVGRenderState *aContext,
{
aTarget->SetOverrideCTM(nsnull);
aTarget->SetMatrixPropagation(PR_TRUE);
aTarget->NotifyCanvasTMChanged(PR_TRUE);
aTarget->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
aTarget->PaintSVG(aContext, nsnull);
}
@ -121,7 +122,8 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
nsSVGElement *target = static_cast<nsSVGElement*>(frame->GetContent());
aTarget->SetMatrixPropagation(PR_FALSE);
aTarget->NotifyCanvasTMChanged(PR_TRUE);
aTarget->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
nsSVGFilterElement *filter = static_cast<nsSVGFilterElement*>(mContent);
@ -192,7 +194,8 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
0.0f, filterRes.height / height,
-x * filterRes.width / width, -y * filterRes.height / height);
aTarget->SetOverrideCTM(filterTransform);
aTarget->NotifyCanvasTMChanged(PR_TRUE);
aTarget->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
// paint the target geometry
nsRefPtr<gfxImageSurface> tmpSurface =
@ -289,7 +292,8 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
aTarget->SetOverrideCTM(nsnull);
aTarget->SetMatrixPropagation(PR_TRUE);
aTarget->NotifyCanvasTMChanged(PR_TRUE);
aTarget->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
return NS_OK;
}
@ -314,12 +318,14 @@ nsSVGFilterFrame::GetInvalidationRegion(nsIFrame *aTarget)
nsCOMPtr<nsIDOMSVGRect> bbox;
svg->SetMatrixPropagation(PR_FALSE);
svg->NotifyCanvasTMChanged(PR_TRUE);
svg->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
svg->GetBBox(getter_AddRefs(bbox));
svg->SetMatrixPropagation(PR_TRUE);
svg->NotifyCanvasTMChanged(PR_TRUE);
svg->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
nsSVGLength2 *tmpX, *tmpY, *tmpWidth, *tmpHeight;
tmpX = &filter->mLengthAttributes[nsSVGFilterElement::X];

View File

@ -380,40 +380,46 @@ nsSVGForeignObjectFrame::InitialUpdate()
return NS_OK;
}
NS_IMETHODIMP
nsSVGForeignObjectFrame::NotifyCanvasTMChanged(PRBool suppressInvalidation)
void
nsSVGForeignObjectFrame::NotifySVGChanged(PRUint32 aFlags)
{
mCanvasTM = nsnull;
PRBool reflow = PR_FALSE;
// XXX we should really have a separate notification for viewport changes and
// not overload NotifyCanvasTMChanged, e.g. we wouldn't need to check
// IsReflowLocked below. Note both notifications would be required for
// viewport changes when there's a viewBox though!
//
// If our width/height have a percentage value then we need to reflow if the
// width/height of our parent coordinate context changes. XXX Perhaps
// unexpectedly we also reflow if our CTM changes. This is because glyph
// metrics do not necessarily scale uniformly with change in scale and, as a
// result, CTM changes may require text to break at different points. roc
// says we shouldn't do this. See bug 381285 comment 20.
if (aFlags & TRANSFORM_CHANGED) {
// Perhaps unexpectedly, we reflow if our CTM changes. This is because
// glyph metrics do not necessarily scale uniformly with change in scale
// and, as a result, CTM changes may require text to break at different
// points.
// XXX roc says we shouldn't do this. See bug 381285 comment 20.
reflow = PR_TRUE;
mCanvasTM = nsnull;
UpdateGraphic(); // update mRect before requesting reflow
// If we're called while the PresShell is handling reflow events then we
// must have been called as a result of the NotifyViewportChange() call in
// our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow
// at this point (i.e. during reflow) because it could confuse the PresShell
// and prevent it from reflowing us properly in future. Besides that,
// nsSVGOuterSVGFrame::DidReflow will take care of reflowing us
// synchronously, so there's no need.
PRBool reflowing;
PresContext()->PresShell()->IsReflowLocked(&reflowing);
if (!reflowing) {
RequestReflow(nsIPresShell::eResize); // XXX use mState & NS_FRAME_IN_REFLOW?
} else if (aFlags & COORD_CONTEXT_CHANGED) {
// Our coordinate context's width/height has changed. If we have a
// percentage width/height our dimensions will change so we must reflow.
nsSVGForeignObjectElement *fO =
static_cast<nsSVGForeignObjectElement*>(mContent);
if (fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].IsPercentage() ||
fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].IsPercentage()) {
reflow = PR_TRUE;
}
}
return NS_OK;
if (reflow) {
// If we're called while the PresShell is handling reflow events then we
// must have been called as a result of the NotifyViewportChange() call in
// our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow
// at this point (i.e. during reflow) because it could confuse the
// PresShell and prevent it from reflowing us properly in future. Besides
// that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us
// synchronously, so there's no need.
PRBool reflowing;
PresContext()->PresShell()->IsReflowLocked(&reflowing);
if (!reflowing) {
UpdateGraphic(); // update mRect before requesting reflow
RequestReflow(nsIPresShell::eResize);
}
}
}
NS_IMETHODIMP

View File

@ -112,7 +112,7 @@ public:
NS_IMETHOD_(nsRect) GetCoveredRegion();
NS_IMETHOD UpdateCoveredRegion();
NS_IMETHOD InitialUpdate();
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation);
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD NotifyRedrawSuspended();
NS_IMETHOD NotifyRedrawUnsuspended();
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);

View File

@ -69,13 +69,15 @@ nsSVGGFrame::GetType() const
//----------------------------------------------------------------------
// nsISVGChildFrame methods
NS_IMETHODIMP
nsSVGGFrame::NotifyCanvasTMChanged(PRBool suppressInvalidation)
void
nsSVGGFrame::NotifySVGChanged(PRUint32 aFlags)
{
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
if (aFlags & TRANSFORM_CHANGED) {
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
}
return nsSVGGFrameBase::NotifyCanvasTMChanged(suppressInvalidation);
nsSVGGFrameBase::NotifySVGChanged(aFlags);
}
NS_IMETHODIMP
@ -155,13 +157,7 @@ nsSVGGFrame::AttributeChanged(PRInt32 aNameSpaceID,
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
for (nsIFrame* kid = mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) {
nsISVGChildFrame* SVGFrame = nsnull;
CallQueryInterface(kid, &SVGFrame);
if (SVGFrame)
SVGFrame->NotifyCanvasTMChanged(PR_FALSE);
}
nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
}
return NS_OK;

View File

@ -73,7 +73,7 @@ public:
PRInt32 aModType);
// nsISVGChildFrame interface:
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation);
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM();

View File

@ -475,12 +475,10 @@ nsSVGGlyphFrame::InitialUpdate()
return NS_OK;
}
NS_IMETHODIMP
nsSVGGlyphFrame::NotifyCanvasTMChanged(PRBool suppressInvalidation)
void
nsSVGGlyphFrame::NotifySVGChanged(PRUint32 aFlags)
{
UpdateGeometry(PR_TRUE, suppressInvalidation);
return NS_OK;
UpdateGeometry(PR_TRUE, (aFlags & SUPPRESS_INVALIDATION) != 0);
}
NS_IMETHODIMP

View File

@ -112,7 +112,7 @@ public:
NS_IMETHOD_(nsRect) GetCoveredRegion();
NS_IMETHOD UpdateCoveredRegion();
NS_IMETHOD InitialUpdate();
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation);
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD NotifyRedrawSuspended();
NS_IMETHOD NotifyRedrawUnsuspended();
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate) { return NS_OK; }

View File

@ -272,11 +272,13 @@ nsSVGGradientFrame::GetGradientTransform(nsSVGGeometryFrame *aSource)
nsCOMPtr<nsIDOMSVGMatrix> matrix = frame->GetOverrideCTM();
frame->SetMatrixPropagation(PR_FALSE);
frame->SetOverrideCTM(nsnull);
frame->NotifyCanvasTMChanged(PR_TRUE);
frame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
frame->GetBBox(getter_AddRefs(rect));
frame->SetMatrixPropagation(PR_TRUE);
frame->SetOverrideCTM(matrix);
frame->NotifyCanvasTMChanged(PR_TRUE);
frame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
}
if (rect) {
float x, y, width, height;

View File

@ -87,7 +87,7 @@ public:
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsSVGRenderState *aContext, nsRect *aDirtyRect);
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation);
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM();
@ -191,13 +191,49 @@ nsSVGInnerSVGFrame::PaintSVG(nsSVGRenderState *aContext, nsRect *aDirtyRect)
return rv;
}
NS_IMETHODIMP
nsSVGInnerSVGFrame::NotifyCanvasTMChanged(PRBool suppressInvalidation)
void
nsSVGInnerSVGFrame::NotifySVGChanged(PRUint32 aFlags)
{
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
if (aFlags & COORD_CONTEXT_CHANGED) {
return nsSVGInnerSVGFrameBase::NotifyCanvasTMChanged(suppressInvalidation);
nsSVGSVGElement *svg = static_cast<nsSVGSVGElement*>(mContent);
// Coordinate context changes affect mCanvasTM if we have a
// percentage 'x' or 'y', or if we have a percentage 'width' or 'height' AND
// a 'viewBox'.
if (!(aFlags & TRANSFORM_CHANGED) &&
svg->mLengthAttributes[nsSVGSVGElement::X].IsPercentage() ||
svg->mLengthAttributes[nsSVGSVGElement::Y].IsPercentage() ||
(mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox) &&
(svg->mLengthAttributes[nsSVGSVGElement::WIDTH].IsPercentage() ||
svg->mLengthAttributes[nsSVGSVGElement::HEIGHT].IsPercentage()))) {
aFlags |= TRANSFORM_CHANGED;
}
// XXX We could clear the COORD_CONTEXT_CHANGED flag in some circumstances
// if we have a non-percentage 'width' AND 'height, or if we have a 'viewBox'
// rect. This is because, when we have a viewBox rect, the viewBox rect
// is the coordinate context for our children, and it isn't changing.
// Percentage lengths on our children will continue to resolve to the
// same number of user units because they're relative to our viewBox rect. The
// same is true if we have a non-percentage width and height and don't have a
// viewBox. We (the <svg>) establish the coordinate context for our children. Our
// children don't care about changes to our parent coordinate context unless that
// change results in a change to the coordinate context that _we_ establish. Hence
// we can (should, really) stop propagating COORD_CONTEXT_CHANGED in these cases.
// We'd actually need to check that we have a viewBox rect and not just
// that viewBox is set, since it could be set to none.
// Take care not to break the testcase for bug 394463 when implementing this
}
if (aFlags & TRANSFORM_CHANGED) {
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
}
nsSVGInnerSVGFrameBase::NotifySVGChanged(aFlags);
}
NS_IMETHODIMP
@ -275,19 +311,30 @@ nsSVGInnerSVGFrame::UnsuspendRedraw()
NS_IMETHODIMP
nsSVGInnerSVGFrame::NotifyViewportChange()
{
PRUint32 flags = COORD_CONTEXT_CHANGED;
#if 1
// XXX nsSVGSVGElement::InvalidateTransformNotifyFrame calls us for changes
// to 'x' and 'y'. Until this is fixed, add TRANSFORM_CHANGED to flags
// unconditionally.
flags |= TRANSFORM_CHANGED;
// make sure canvas transform matrix gets (lazily) recalculated:
mCanvasTM = nsnull;
#else
// viewport changes only affect our transform if we have a viewBox attribute
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
// make sure canvas transform matrix gets (lazily) recalculated:
mCanvasTM = nsnull;
flags |= TRANSFORM_CHANGED;
}
#endif
// inform children
SuspendRedraw();
nsIFrame* kid = mFrames.FirstChild();
while (kid) {
nsISVGChildFrame* SVGFrame = nsnull;
CallQueryInterface(kid, &SVGFrame);
if (SVGFrame)
SVGFrame->NotifyCanvasTMChanged(PR_FALSE);
kid = kid->GetNextSibling();
}
nsSVGUtils::NotifyChildrenOfSVGChange(this, flags);
UnsuspendRedraw();
return NS_OK;
}

View File

@ -171,7 +171,9 @@ nsSVGMarkerFrame::PaintMark(nsSVGRenderState *aContext,
nsISVGChildFrame* SVGFrame = nsnull;
CallQueryInterface(kid, &SVGFrame);
if (SVGFrame) {
SVGFrame->NotifyCanvasTMChanged(PR_TRUE);
// The CTM of each frame referencing us may be different.
SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
nsSVGUtils::PaintChildWithEffects(aContext, nsnull, kid);
}
}

View File

@ -112,13 +112,15 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
if (units == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
aParent->SetMatrixPropagation(PR_FALSE);
aParent->NotifyCanvasTMChanged(PR_TRUE);
aParent->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
nsCOMPtr<nsIDOMSVGRect> bbox;
aParent->GetBBox(getter_AddRefs(bbox));
aParent->SetMatrixPropagation(PR_TRUE);
aParent->NotifyCanvasTMChanged(PR_TRUE);
aParent->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
if (!bbox)
return nsnull;

View File

@ -227,7 +227,7 @@ nsSVGOuterSVGFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
nsSVGSVGElement *svg = static_cast<nsSVGSVGElement*>(mContent);
nsSVGLength2 &width = svg->mLengthAttributes[nsSVGSVGElement::WIDTH];
if (width.GetSpecifiedUnitType() == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE) {
if (width.IsPercentage()) {
result = nscoord(0);
} else {
result = nsPresContext::CSSPixelsToAppUnits(width.GetAnimValue(svg));
@ -251,7 +251,7 @@ nsSVGOuterSVGFrame::GetIntrinsicSize()
nsSVGLength2 &width = content->mLengthAttributes[nsSVGSVGElement::WIDTH];
nsSVGLength2 &height = content->mLengthAttributes[nsSVGSVGElement::HEIGHT];
if (width.GetSpecifiedUnitType() == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE) {
if (width.IsPercentage()) {
float val = width.GetAnimValInSpecifiedUnits() / 100.0f;
if (val < 0.0f) val = 0.0f;
intrinsicSize.width.SetPercentValue(val);
@ -261,7 +261,7 @@ nsSVGOuterSVGFrame::GetIntrinsicSize()
intrinsicSize.width.SetCoordValue(val);
}
if (height.GetSpecifiedUnitType() == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE) {
if (height.IsPercentage()) {
float val = height.GetAnimValInSpecifiedUnits() / 100.0f;
if (val < 0.0f) val = 0.0f;
intrinsicSize.height.SetPercentValue(val);
@ -285,8 +285,7 @@ nsSVGOuterSVGFrame::GetIntrinsicRatio()
nsSVGLength2 &width = content->mLengthAttributes[nsSVGSVGElement::WIDTH];
nsSVGLength2 &height = content->mLengthAttributes[nsSVGSVGElement::HEIGHT];
if (width.GetSpecifiedUnitType() != nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE &&
height.GetSpecifiedUnitType() != nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE) {
if (!width.IsPercentage() && !height.IsPercentage()) {
nsSize ratio(width.GetAnimValue(content), height.GetAnimValue(content));
if (ratio.width < 0) {
ratio.width = 0;
@ -718,22 +717,28 @@ NS_IMETHODIMP
nsSVGOuterSVGFrame::NotifyViewportChange()
{
// no point in doing anything when were not init'ed yet:
if (!mViewportInitialized) return NS_OK;
/* XXX this caused reftest failures
// viewport changes only affect our transform if we have a viewBox attribute
nsSVGSVGElement *svgElem = static_cast<nsSVGSVGElement*>(mContent);
if (!svgElem->HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
if (!mViewportInitialized) {
return NS_OK;
}
*/
// make sure canvas transform matrix gets (lazily) recalculated:
mCanvasTM = nsnull;
PRUint32 flags = COORD_CONTEXT_CHANGED;
// viewport changes only affect our transform if we have a viewBox attribute
#if 1
{
#else
// XXX this caused reftest failures (bug 413960)
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
#endif
// make sure canvas transform matrix gets (lazily) recalculated:
mCanvasTM = nsnull;
flags |= TRANSFORM_CHANGED;
}
// inform children
SuspendRedraw();
nsSVGUtils::NotifyChildrenCanvasTMChanged(this, PR_FALSE);
nsSVGUtils::NotifyChildrenOfSVGChange(this, flags);
UnsuspendRedraw();
return NS_OK;
}

View File

@ -470,12 +470,10 @@ nsSVGPathGeometryFrame::InitialUpdate()
return NS_OK;
}
NS_IMETHODIMP
nsSVGPathGeometryFrame::NotifyCanvasTMChanged(PRBool suppressInvalidation)
void
nsSVGPathGeometryFrame::NotifySVGChanged(PRUint32 aFlags)
{
UpdateGraphic(suppressInvalidation);
return NS_OK;
UpdateGraphic((aFlags & SUPPRESS_INVALIDATION) != 0);
}
NS_IMETHODIMP

View File

@ -109,7 +109,7 @@ protected:
NS_IMETHOD_(nsRect) GetCoveredRegion();
NS_IMETHOD UpdateCoveredRegion();
NS_IMETHOD InitialUpdate();
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation);
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD NotifyRedrawSuspended();
NS_IMETHOD NotifyRedrawUnsuspended();
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);

View File

@ -781,10 +781,12 @@ nsSVGPatternFrame::GetCallerGeometry(nsIDOMSVGMatrix **aCTM,
CallQueryInterface(aSource, &callerSVGFrame);
callerSVGFrame->SetMatrixPropagation(PR_FALSE);
callerSVGFrame->NotifyCanvasTMChanged(PR_TRUE);
callerSVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED );
callerSVGFrame->GetBBox(aBBox);
callerSVGFrame->SetMatrixPropagation(PR_TRUE);
callerSVGFrame->NotifyCanvasTMChanged(PR_TRUE);
callerSVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED);
// Sanity check
PRUint16 type = GetPatternUnits();

View File

@ -95,15 +95,9 @@ nsSVGTextFrame::AttributeChanged(PRInt32 aNameSpaceID,
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
nsIFrame* kid = mFrames.FirstChild();
while (kid) {
nsISVGChildFrame* SVGFrame = nsnull;
CallQueryInterface(kid, &SVGFrame);
if (SVGFrame)
SVGFrame->NotifyCanvasTMChanged(PR_FALSE);
kid = kid->GetNextSibling();
}
nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
} else if (aAttribute == nsGkAtoms::x ||
aAttribute == nsGkAtoms::y ||
aAttribute == nsGkAtoms::dx ||
@ -198,19 +192,25 @@ nsSVGTextFrame::GetCharNumAtPosition(nsIDOMSVGPoint *point, PRInt32 *_retval)
//----------------------------------------------------------------------
// nsISVGChildFrame methods
NS_IMETHODIMP
nsSVGTextFrame::NotifyCanvasTMChanged(PRBool suppressInvalidation)
void
nsSVGTextFrame::NotifySVGChanged(PRUint32 aFlags)
{
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
if (aFlags & TRANSFORM_CHANGED) {
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
}
// If we are positioned using percentage values we need to update our
// position whenever our viewport's dimensions change.
// XXX we should really have a separate notification for viewport changes and
// not overload NotifyCanvasTMChanged.
NotifyGlyphMetricsChange();
if (aFlags & COORD_CONTEXT_CHANGED) {
// If we are positioned using percentage values we need to update our
// position whenever our viewport's dimensions change.
return nsSVGTextFrameBase::NotifyCanvasTMChanged(suppressInvalidation);
// XXX We could check here whether the text frame or any of its children
// have any percentage co-ordinates and only update if they don't. This
// may not be worth it as we might need to check each glyph
NotifyGlyphMetricsChange();
}
nsSVGTextFrameBase::NotifySVGChanged(aFlags);
}
NS_IMETHODIMP

View File

@ -81,7 +81,7 @@ public:
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
virtual already_AddRefed<nsIDOMSVGMatrix> GetOverrideCTM();
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation);
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD NotifyRedrawSuspended();
NS_IMETHOD NotifyRedrawUnsuspended();
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);

View File

@ -202,8 +202,7 @@ nsSVGTextPathFrame::GetStartOffset()
if (val == 0.0f)
return 0.0;
if (length->GetSpecifiedUnitType() ==
nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE) {
if (length->IsPercentage()) {
nsRefPtr<gfxFlattenedPath> data = GetFlattenedPath();
return data ? (val * data->GetLength() / 100.0) : 0.0;
} else {

View File

@ -130,13 +130,7 @@ nsSVGUseFrame::AttributeChanged(PRInt32 aNameSpaceID,
// make sure our cached transform matrix gets (lazily) updated
mCanvasTM = nsnull;
for (nsIFrame* kid = mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) {
nsISVGChildFrame* SVGFrame = nsnull;
CallQueryInterface(kid, &SVGFrame);
if (SVGFrame)
SVGFrame->NotifyCanvasTMChanged(PR_FALSE);
}
nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
return NS_OK;
}

View File

@ -918,8 +918,7 @@ nsSVGUtils::ObjectSpace(nsIDOMSVGRect *aRect, nsSVGLength2 *aLength)
}
}
if (aLength->GetSpecifiedUnitType() ==
nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE) {
if (aLength->IsPercentage()) {
fraction = aLength->GetAnimValInSpecifiedUnits() / 100;
} else
fraction = aLength->GetAnimValue(static_cast<nsSVGSVGElement*>
@ -1115,7 +1114,7 @@ nsSVGUtils::GetCanvasTM(nsIFrame *aFrame)
}
void
nsSVGUtils::NotifyChildrenCanvasTMChanged(nsIFrame *aFrame, PRBool suppressInvalidation)
nsSVGUtils::NotifyChildrenOfSVGChange(nsIFrame *aFrame, PRUint32 aFlags)
{
nsIFrame *aKid = aFrame->GetFirstChild(nsnull);
@ -1123,12 +1122,12 @@ nsSVGUtils::NotifyChildrenCanvasTMChanged(nsIFrame *aFrame, PRBool suppressInval
nsISVGChildFrame* SVGFrame = nsnull;
CallQueryInterface(aKid, &SVGFrame);
if (SVGFrame) {
SVGFrame->NotifyCanvasTMChanged(suppressInvalidation);
SVGFrame->NotifySVGChanged(aFlags);
} else {
NS_ASSERTION(aKid->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
// recurse into the children of container frames e.g. <clipPath>, <mask>
// in case they have child frames with transformation matrices
nsSVGUtils::NotifyChildrenCanvasTMChanged(aKid, suppressInvalidation);
nsSVGUtils::NotifyChildrenOfSVGChange(aKid, aFlags);
}
aKid = aKid->GetNextSibling();
}

View File

@ -354,10 +354,10 @@ public:
static already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM(nsIFrame *aFrame);
/*
* Tells child frames that the canvasTM has changed
* Tells child frames that something that might affect them has changed
*/
static void
NotifyChildrenCanvasTMChanged(nsIFrame *aFrame, PRBool suppressInvalidation);
NotifyChildrenOfSVGChange(nsIFrame *aFrame, PRUint32 aFlags);
/*
* Get frame's covered region by walking the children and doing union.