зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
517b0962e1
Коммит
5ad302fb3b
|
@ -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
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче