Bug 463939. When an SVG element's geometry changes and it has an ancestor with a filter effect, invalidate the nearest SVG viewport ancestor because we don't have a good way to compute precise invalidation bounds. r=roc

--HG--
extra : rebase_source : 4f0b385d07b989137f83b80d6cd0907ee1dcd599
This commit is contained in:
Jonathan Watt 2009-04-25 01:17:43 +02:00
Родитель 517b0962e1
Коммит 5ad302fb3b
8 изменённых файлов: 201 добавлений и 63 удалений

Просмотреть файл

@ -0,0 +1,25 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="reftest-wait">
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=463939 -->
<title>Test that the area that's covered by a filtered elemnt is invalidated when it moves</title>
<filter id="filter">
<feGaussianBlur stdDeviation="0.1"/>
</filter>
<script type="text/javascript">//<![CDATA[
function hide_red_rect()
{
document.getElementById("r").setAttribute("y", "-200%");
document.documentElement.removeAttribute('class');
}
document.addEventListener("MozReftestInvalidate", hide_red_rect, false);
setTimeout(hide_red_rect, 5000)
//]]></script>
<rect width="100%" height="100%" fill="lime"/>
<rect width="100%" height="100%" fill="red" id="r" filter="url(#filter)"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 883 B

Просмотреть файл

@ -59,6 +59,7 @@ include moz-only/reftest.list
== filter-basic-02.svg pass.svg
== filter-basic-03.svg pass.svg
== filter-foreignObject-01.svg pass.svg
== filter-invalidation-01.svg pass.svg
== filter-translated-01.svg filter-translated-01-ref.svg
== foreignObject-01.svg pass.svg
== foreignObject-02.svg foreignObject-02-ref.svg

Просмотреть файл

@ -39,6 +39,7 @@
#include "nsSVGOuterSVGFrame.h"
NS_QUERYFRAME_HEAD(nsSVGDisplayContainerFrame)
NS_QUERYFRAME_ENTRY(nsSVGDisplayContainerFrame)
NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsSVGContainerFrame)

Просмотреть файл

@ -83,6 +83,8 @@ protected:
nsSVGContainerFrame(aContext) {}
public:
NS_DECLARE_FRAME_ACCESSOR(nsSVGDisplayContainerFrame);
NS_DECL_QUERYFRAME
// nsIFrame:

Просмотреть файл

@ -36,6 +36,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsSVGInnerSVGFrame.h"
#include "nsIFrame.h"
#include "nsISVGChildFrame.h"
#include "nsSVGOuterSVGFrame.h"
@ -45,68 +46,6 @@
#include "nsSVGContainerFrame.h"
#include "gfxContext.h"
typedef nsSVGDisplayContainerFrame nsSVGInnerSVGFrameBase;
class nsSVGInnerSVGFrame : public nsSVGInnerSVGFrameBase,
public nsISVGSVGFrame
{
friend nsIFrame*
NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
protected:
nsSVGInnerSVGFrame(nsStyleContext* aContext) :
nsSVGInnerSVGFrameBase(aContext) {}
public:
NS_DECL_QUERYFRAME
// We don't define an AttributeChanged method since changes to the
// 'x', 'y', 'width' and 'height' attributes of our content object
// are handled in nsSVGSVGElement::DidModifySVGObservable
#ifdef DEBUG
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow);
#endif
/**
* Get the "type" of the frame
*
* @see nsGkAtoms::svgInnerSVGFrame
*/
virtual nsIAtom* GetType() const;
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("SVGInnerSVG"), aResult);
}
#endif
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsSVGRenderState *aContext, const nsIntRect *aDirtyRect);
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
// nsSVGContainerFrame methods:
virtual already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
// nsISupportsWeakReference
// implementation inherited from nsSupportsWeakReference
// nsISVGSVGFrame interface:
NS_IMETHOD SuspendRedraw();
NS_IMETHOD UnsuspendRedraw();
NS_IMETHOD NotifyViewportChange();
protected:
nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
};
//----------------------------------------------------------------------
// Implementation
nsIFrame*
NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
@ -117,6 +56,7 @@ NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
// nsIFrame methods
NS_QUERYFRAME_HEAD(nsSVGInnerSVGFrame)
NS_QUERYFRAME_ENTRY(nsSVGInnerSVGFrame)
NS_QUERYFRAME_ENTRY(nsISVGSVGFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsSVGInnerSVGFrameBase)

Просмотреть файл

@ -0,0 +1,101 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla SVG project.
*
* The Initial Developer of the Original Code is
* Crocodile Clips Ltd..
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsSVGContainerFrame.h"
#include "nsISVGSVGFrame.h"
typedef nsSVGDisplayContainerFrame nsSVGInnerSVGFrameBase;
class nsSVGInnerSVGFrame : public nsSVGInnerSVGFrameBase,
public nsISVGSVGFrame
{
friend nsIFrame*
NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
protected:
nsSVGInnerSVGFrame(nsStyleContext* aContext) :
nsSVGInnerSVGFrameBase(aContext) {}
public:
NS_DECLARE_FRAME_ACCESSOR(nsSVGInnerSVGFrame);
NS_DECL_QUERYFRAME
// We don't define an AttributeChanged method since changes to the
// 'x', 'y', 'width' and 'height' attributes of our content object
// are handled in nsSVGSVGElement::DidModifySVGObservable
#ifdef DEBUG
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow);
#endif
/**
* Get the "type" of the frame
*
* @see nsGkAtoms::svgInnerSVGFrame
*/
virtual nsIAtom* GetType() const;
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("SVGInnerSVG"), aResult);
}
#endif
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsSVGRenderState *aContext, const nsIntRect *aDirtyRect);
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD_(nsIFrame*) GetFrameForPoint(const nsPoint &aPoint);
// nsSVGContainerFrame methods:
virtual already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
// nsISupportsWeakReference
// implementation inherited from nsSupportsWeakReference
// nsISVGSVGFrame interface:
NS_IMETHOD SuspendRedraw();
NS_IMETHOD UnsuspendRedraw();
NS_IMETHOD NotifyViewportChange();
protected:
nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
};

Просмотреть файл

@ -62,6 +62,7 @@
#include "nsSVGPoint.h"
#include "nsDOMError.h"
#include "nsSVGOuterSVGFrame.h"
#include "nsSVGInnerSVGFrame.h"
#include "nsSVGPreserveAspectRatio.h"
#include "nsSVGMatrix.h"
#include "nsSVGClipPathFrame.h"
@ -462,6 +463,24 @@ nsSVGUtils::GetNearestViewportElement(nsIContent *aContent,
return NS_OK;
}
nsSVGDisplayContainerFrame*
nsSVGUtils::GetNearestSVGViewport(nsIFrame *aFrame)
{
NS_ASSERTION(aFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
if (aFrame->GetType() == nsGkAtoms::svgOuterSVGFrame) {
return nsnull;
}
while ((aFrame = aFrame->GetParent())) {
NS_ASSERTION(aFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
if (aFrame->GetType() == nsGkAtoms::svgInnerSVGFrame ||
aFrame->GetType() == nsGkAtoms::svgOuterSVGFrame) {
return do_QueryFrame(aFrame);
}
}
NS_NOTREACHED("This is not reached. It's only needed to compile.");
return nsnull;
}
nsresult
nsSVGUtils::GetFarthestViewportElement(nsIContent *aContent,
nsIDOMSVGElement * *aFarthestViewportElement)
@ -552,7 +571,48 @@ nsSVGUtils::FindFilterInvalidation(nsIFrame *aFrame, const nsRect& aRect)
nsSVGFilterFrame *filter = nsSVGEffects::GetFilterFrame(aFrame);
if (filter) {
rect = filter->GetInvalidationBBox(aFrame, rect);
// When we are under AttributeChanged, we can no longer get the old bbox
// by calling GetBBox(), and we need that to set up the filter region
// with the correct position. :-(
//rect = filter->GetInvalidationBBox(aFrame, rect);
// XXX [perf] As a horrible workaround, for now we just invalidate the
// entire area of the nearest viewport establishing frame that doesnt
// have overflow:visible. See bug 463939.
nsSVGDisplayContainerFrame* viewportFrame = GetNearestSVGViewport(aFrame);
while (viewportFrame && !viewportFrame->GetStyleDisplay()->IsScrollableOverflow()) {
viewportFrame = GetNearestSVGViewport(viewportFrame);
}
if (!viewportFrame) {
viewportFrame = GetOuterSVGFrame(aFrame);
}
if (viewportFrame->GetType() == nsGkAtoms::svgOuterSVGFrame) {
nsRect r = viewportFrame->GetOverflowRect();
// GetOverflowRect is relative to our border box, but we need it
// relative to our content box.
nsMargin bp = viewportFrame->GetUsedBorderAndPadding();
viewportFrame->ApplySkipSides(bp);
r.MoveBy(-bp.left, -bp.top);
return r;
}
NS_ASSERTION(viewportFrame->GetType() == nsGkAtoms::svgInnerSVGFrame,
"Wrong frame type");
nsSVGInnerSVGFrame* innerSvg = do_QueryFrame(static_cast<nsIFrame*>(viewportFrame));
nsSVGDisplayContainerFrame* innerSvgParent = do_QueryFrame(viewportFrame->GetParent());
float x, y, width, height;
static_cast<nsSVGSVGElement*>(innerSvg->GetContent())->
GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
nsCOMPtr<nsIDOMSVGMatrix> domctm = nsSVGUtils::GetCanvasTM(innerSvgParent);
gfxMatrix ctm = nsSVGUtils::ConvertSVGMatrixToThebes(domctm);
gfxRect bounds = ctm.TransformBounds(gfxRect(x, y, width, height));
bounds.RoundOut();
nsIntRect r;
if (NS_SUCCEEDED(nsSVGUtils::GfxRectToIntRect(bounds, &r))) {
rect = r;
} else {
NS_NOTREACHED("Not going to invalidate the correct area");
}
aFrame = viewportFrame;
}
aFrame = aFrame->GetParent();
}

Просмотреть файл

@ -79,6 +79,7 @@ struct nsStyleFont;
class nsSVGEnum;
class nsISVGChildFrame;
class nsSVGGeometryFrame;
class nsSVGDisplayContainerFrame;
#ifndef M_PI
#define M_PI 3.14159265358979323846
@ -256,6 +257,13 @@ public:
static nsresult GetNearestViewportElement(nsIContent *aContent,
nsIDOMSVGElement * *aNearestViewportElement);
/**
* Gets the nearest nsSVGInnerSVGFrame or nsSVGOuterSVGFrame frame. aFrame
* must be an SVG frame. If aFrame is of type nsGkAtoms::svgOuterSVGFrame,
* returns nsnull.
*/
static nsSVGDisplayContainerFrame* GetNearestSVGViewport(nsIFrame *aFrame);
/*
* Get the farthest viewport element
*/