Bug 329758 - changing markers via DOM does not cause a refresh. r=tor,sr=roc

This commit is contained in:
longsonr%gmail.com 2006-04-06 13:02:53 +00:00
parent d0dee808f7
commit fc0e9059bf
11 changed files with 196 additions and 40 deletions

View File

@ -137,11 +137,15 @@ NS_GetSVGClipPathFrame(nsISVGClipPathFrame **aResult,
NS_WARNING("No document for this content!");
return NS_ERROR_FAILURE;
}
nsIPresShell *aPresShell = myDoc->GetShellAt(0);
nsIPresShell *presShell = myDoc->GetShellAt(0);
if (!presShell) {
NS_WARNING("no presshell");
return NS_ERROR_FAILURE;
}
// Find the referenced frame
nsIFrame *cpframe;
if (!NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&cpframe, aURI, aContent, aPresShell)))
if (!NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&cpframe, aURI, aContent, presShell)))
return NS_ERROR_FAILURE;
nsIAtom* frameType = cpframe->GetType();

View File

@ -150,11 +150,15 @@ NS_GetSVGFilterFrame(nsISVGFilterFrame **aResult,
NS_WARNING("No document for this content!");
return NS_ERROR_FAILURE;
}
nsIPresShell *aPresShell = myDoc->GetShellAt(0);
nsIPresShell *presShell = myDoc->GetShellAt(0);
if (!presShell) {
NS_WARNING("no presshell");
return NS_ERROR_FAILURE;
}
// Find the referenced frame
nsIFrame *filter;
if (!NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&filter, aURI, aContent, aPresShell)))
if (!NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&filter, aURI, aContent, presShell)))
return NS_ERROR_FAILURE;
nsIAtom* frameType = filter->GetType();

View File

@ -55,18 +55,21 @@
#include "nsSVGMarkerFrame.h"
#include "nsSVGPathGeometryFrame.h"
#include "nsISVGRendererCanvas.h"
#include "nsSVGValue.h"
#include "nsSVGUtils.h"
#include "nsSVGMatrix.h"
#include "nsINameSpaceManager.h"
#include "nsGkAtoms.h"
class nsSVGMarkerFrame : public nsSVGDefsFrame,
public nsSVGValue,
public nsISVGMarkerFrame
{
protected:
friend nsIFrame*
NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext);
virtual ~nsSVGMarkerFrame();
NS_IMETHOD InitSVG();
public:
@ -77,6 +80,10 @@ public:
NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
// nsISVGValue interface:
NS_IMETHOD SetValueString(const nsAString &aValue) { return NS_OK; }
NS_IMETHOD GetValueString(nsAString& aValue) { return NS_ERROR_NOT_IMPLEMENTED; }
// nsIFrame interface:
NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
@ -131,6 +138,7 @@ private:
};
NS_INTERFACE_MAP_BEGIN(nsSVGMarkerFrame)
NS_INTERFACE_MAP_ENTRY(nsISVGValue)
NS_INTERFACE_MAP_ENTRY(nsISVGMarkerFrame)
NS_INTERFACE_MAP_END_INHERITING(nsSVGDefsFrame)
@ -152,11 +160,15 @@ NS_GetSVGMarkerFrame(nsISVGMarkerFrame **aResult,
NS_WARNING("No document for this content!");
return NS_ERROR_FAILURE;
}
nsIPresShell *aPresShell = myDoc->GetShellAt(0);
nsIPresShell *presShell = myDoc->GetShellAt(0);
if (!presShell) {
NS_WARNING("no presshell");
return NS_ERROR_FAILURE;
}
// Find the referenced frame
nsIFrame *marker;
if (!NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&marker, aURI, aContent, aPresShell)))
if (!NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&marker, aURI, aContent, presShell)))
return NS_ERROR_FAILURE;
nsIAtom* frameType = marker->GetType();
@ -167,6 +179,13 @@ NS_GetSVGMarkerFrame(nsISVGMarkerFrame **aResult,
return NS_OK;
}
nsSVGMarkerFrame::~nsSVGMarkerFrame()
{
WillModify();
// Notify the world that we're dying
DidModify(mod_die);
}
NS_IMETHODIMP
nsSVGMarkerFrame::InitSVG()
{
@ -249,7 +268,8 @@ nsSVGMarkerFrame::AttributeChanged(PRInt32 aNameSpaceID,
aAttribute == nsGkAtoms::markerHeight ||
aAttribute == nsGkAtoms::orient ||
aAttribute == nsGkAtoms::viewBox)) {
// XXX: marker frame should be a nsSVGValue and call DidModify() here
WillModify();
DidModify();
return NS_OK;
}

View File

@ -127,11 +127,15 @@ NS_GetSVGMaskFrame(nsISVGMaskFrame **aResult,
NS_WARNING("No document for this content!");
return NS_ERROR_FAILURE;
}
nsIPresShell *aPresShell = myDoc->GetShellAt(0);
nsIPresShell *presShell = myDoc->GetShellAt(0);
if (!presShell) {
NS_WARNING("no presshell");
return NS_ERROR_FAILURE;
}
// Find the referenced frame
nsIFrame *cpframe;
if (!NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&cpframe, aURI, aContent, aPresShell)))
if (!NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&cpframe, aURI, aContent, presShell)))
return NS_ERROR_FAILURE;
nsIAtom* frameType = cpframe->GetType();

View File

@ -44,7 +44,6 @@
#include "nsIDOMSVGMatrix.h"
#include "nsISVGRendererPathBuilder.h"
#include "nsISVGMarkable.h"
#include "nsSVGMarkerFrame.h"
#include "nsISupports.h"
#include "nsLayoutAtoms.h"
#include "nsISVGPathFlatten.h"

View File

@ -66,6 +66,18 @@
#include "nsISVGRendererSurface.h"
#include "nsINameSpaceManager.h"
struct nsSVGMarkerProperty {
nsISVGMarkerFrame *mMarkerStart;
nsISVGMarkerFrame *mMarkerMid;
nsISVGMarkerFrame *mMarkerEnd;
nsSVGMarkerProperty()
: mMarkerStart(nsnull),
mMarkerMid(nsnull),
mMarkerEnd(nsnull)
{}
};
////////////////////////////////////////////////////////////////////////
// nsSVGPathGeometryFrame
@ -99,6 +111,9 @@ nsSVGPathGeometryFrame::~nsSVGPathGeometryFrame()
if (mStrokePattern) {
NS_REMOVE_SVGVALUE_OBSERVER(mStrokePattern);
}
if (GetStateBits() & NS_STATE_SVG_HAS_MARKERS) {
DeleteProperty(nsGkAtoms::marker);
}
}
//----------------------------------------------------------------------
@ -169,6 +184,11 @@ nsSVGPathGeometryFrame::DidSetStyleContext()
}
nsSVGUtils::StyleEffects(this);
if (GetStateBits() & NS_STATE_SVG_HAS_MARKERS) {
DeleteProperty(nsGkAtoms::marker);
RemoveStateBits(NS_STATE_SVG_HAS_MARKERS);
}
// XXX: we'd like to use the style_hint mechanism and the
// ContentStateChanged/AttributeChanged functions for style changes
// to get slightly finer granularity, but unfortunately the
@ -192,32 +212,102 @@ nsSVGPathGeometryFrame::IsFrameOfType(PRUint32 aFlags) const
return !(aFlags & ~nsIFrame::eSVG);
}
//----------------------------------------------------------------------
// nsISVGChildFrame methods
// marker helper
static void
RemoveMarkerObserver(nsSVGMarkerProperty *property,
nsIFrame *aFrame,
nsISVGMarkerFrame *marker)
{
if (!marker) return;
if (property->mMarkerStart == marker)
property->mMarkerStart = nsnull;
if (property->mMarkerMid == marker)
property->mMarkerMid = nsnull;
if (property->mMarkerEnd == marker)
property->mMarkerEnd = nsnull;
nsSVGUtils::RemoveObserver(aFrame, marker);
}
static void
MarkerPropertyDtor(void *aObject, nsIAtom *aPropertyName,
void *aPropertyValue, void *aData)
{
nsSVGMarkerProperty *property = NS_STATIC_CAST(nsSVGMarkerProperty *,
aPropertyValue);
nsIFrame *frame = NS_STATIC_CAST(nsIFrame *, aObject);
RemoveMarkerObserver(property, frame, property->mMarkerStart);
RemoveMarkerObserver(property, frame, property->mMarkerMid);
RemoveMarkerObserver(property, frame, property->mMarkerEnd);
delete property;
}
void
nsSVGPathGeometryFrame::GetMarkerFrames(nsISVGMarkerFrame **markerStart,
nsISVGMarkerFrame **markerMid,
nsISVGMarkerFrame **markerEnd)
{
nsIURI *aURI;
*markerStart = *markerMid = *markerEnd = nsnull;
*markerStart = *markerMid = *markerEnd = NULL;
aURI = GetStyleSVG()->mMarkerEnd;
if (aURI)
NS_GetSVGMarkerFrame(markerEnd, aURI, mContent);
aURI = GetStyleSVG()->mMarkerMid;
if (aURI)
NS_GetSVGMarkerFrame(markerMid, aURI, mContent);
aURI = GetStyleSVG()->mMarkerStart;
if (aURI)
NS_GetSVGMarkerFrame(markerStart, aURI, mContent);
if (GetStateBits() & NS_STATE_SVG_HAS_MARKERS) {
nsSVGMarkerProperty *property;
property = NS_STATIC_CAST(nsSVGMarkerProperty *,
GetProperty(nsGkAtoms::marker));
if (property) {
*markerStart = property->mMarkerStart;
*markerMid = property->mMarkerMid;
*markerEnd = property->mMarkerEnd;
}
}
}
void
nsSVGPathGeometryFrame::GetMarkerFromStyle(nsISVGMarkerFrame **aResult,
nsSVGMarkerProperty *property,
nsIURI *aURI)
{
if (aURI && !*aResult) {
nsISVGMarkerFrame *marker;
NS_GetSVGMarkerFrame(&marker, aURI, GetContent());
if (marker) {
if (property->mMarkerStart != marker &&
property->mMarkerMid != marker &&
property->mMarkerEnd != marker)
nsSVGUtils::AddObserver(NS_STATIC_CAST(nsIFrame *, this), marker);
*aResult = marker;
}
}
}
void
nsSVGPathGeometryFrame::UpdateMarkerProperty()
{
const nsStyleSVG *style = GetStyleSVG();
if (style->mMarkerStart || style->mMarkerMid || style->mMarkerEnd) {
nsSVGMarkerProperty *property;
if (GetStateBits() & NS_STATE_SVG_HAS_MARKERS) {
property = NS_STATIC_CAST(nsSVGMarkerProperty *,
GetProperty(nsGkAtoms::marker));
} else {
property = new nsSVGMarkerProperty;
if (!property) {
NS_ERROR("Could not create marker property");
return;
}
SetProperty(nsGkAtoms::marker, property, MarkerPropertyDtor);
AddStateBits(NS_STATE_SVG_HAS_MARKERS);
}
GetMarkerFromStyle(&property->mMarkerStart, property, style->mMarkerStart);
GetMarkerFromStyle(&property->mMarkerMid, property, style->mMarkerMid);
GetMarkerFromStyle(&property->mMarkerEnd, property, style->mMarkerEnd);
}
}
//----------------------------------------------------------------------
// nsISVGChildFrame methods
NS_IMETHODIMP
nsSVGPathGeometryFrame::PaintSVG(nsISVGRendererCanvas* canvas)
{
@ -231,6 +321,8 @@ nsSVGPathGeometryFrame::PaintSVG(nsISVGRendererCanvas* canvas)
CallQueryInterface(this, &markable);
if (markable) {
// Marker Property is added lazily and may have been removed by a restyle
UpdateMarkerProperty();
nsISVGMarkerFrame *markerEnd, *markerMid, *markerStart;
GetMarkerFrames(&markerStart, &markerMid, &markerEnd);
@ -370,7 +462,7 @@ NS_IMETHODIMP
nsSVGPathGeometryFrame::NotifyRedrawUnsuspended()
{
if (mUpdateFlags != 0)
UpdateGraphic(0);
UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_NOTHING);
return NS_OK;
}
@ -463,6 +555,20 @@ nsSVGPathGeometryFrame::DidModifySVGObservable (nsISVGValue* observable,
}
UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_STROKE_PAINT);
}
return NS_OK;
}
nsISVGMarkerFrame *marker;
CallQueryInterface(observable, &marker);
if (marker) {
if (aModType == nsISVGValue::mod_die)
RemoveMarkerObserver(NS_STATIC_CAST(nsSVGMarkerProperty *,
GetProperty(nsGkAtoms::marker)),
this,
marker);
UpdateGraphic(nsISVGGeometrySource::UPDATEMASK_NOTHING);
return NS_OK;
}
return NS_OK;

View File

@ -56,6 +56,7 @@ class nsIDOMSVGMatrix;
class nsISVGRendererRegion;
class nsISVGMarkerFrame;
class nsISVGFilterFrame;
struct nsSVGMarkerProperty;
typedef nsFrame nsSVGPathGeometryFrameBase;
@ -144,6 +145,10 @@ private:
void GetMarkerFrames(nsISVGMarkerFrame **markerStart,
nsISVGMarkerFrame **markerMid,
nsISVGMarkerFrame **markerEnd);
void GetMarkerFromStyle(nsISVGMarkerFrame **aResult,
nsSVGMarkerProperty *property,
nsIURI *aURI);
void UpdateMarkerProperty();
nsCOMPtr<nsISVGRendererPathGeometry> mGeometry;
PRUint32 mUpdateFlags;

View File

@ -42,7 +42,6 @@
#include "nsIDOMSVGPoint.h"
#include "nsISVGRendererPathBuilder.h"
#include "nsISVGMarkable.h"
#include "nsSVGMarkerFrame.h"
#include "nsLayoutAtoms.h"
#include "nsSVGUtils.h"
#include "nsINameSpaceManager.h"

View File

@ -42,7 +42,6 @@
#include "nsIDOMSVGPoint.h"
#include "nsISVGRendererPathBuilder.h"
#include "nsISVGMarkable.h"
#include "nsSVGMarkerFrame.h"
#include "nsLayoutAtoms.h"
#include "nsSVGUtils.h"
#include "nsINameSpaceManager.h"

View File

@ -775,11 +775,8 @@ nsSVGUtils::GetCanvasTM(nsIFrame *aFrame)
return nsnull;
}
// ************************************************************
// Effect helper functions
static void
AddObserver(nsISupports *aObserver, nsISupports *aTarget)
void
nsSVGUtils::AddObserver(nsISupports *aObserver, nsISupports *aTarget)
{
nsISVGValueObserver *observer = nsnull;
nsISVGValue *v = nsnull;
@ -789,8 +786,8 @@ AddObserver(nsISupports *aObserver, nsISupports *aTarget)
v->AddObserver(observer);
}
static void
RemoveObserver(nsISupports *aObserver, nsISupports *aTarget)
void
nsSVGUtils::RemoveObserver(nsISupports *aObserver, nsISupports *aTarget)
{
nsISVGValueObserver *observer = nsnull;
nsISVGValue *v = nsnull;
@ -800,12 +797,17 @@ RemoveObserver(nsISupports *aObserver, nsISupports *aTarget)
v->RemoveObserver(observer);
}
// ************************************************************
// Effect helper functions
static void
FilterPropertyDtor(void *aObject, nsIAtom *aPropertyName,
void *aPropertyValue, void *aData)
{
nsSVGFilterProperty *property = (nsSVGFilterProperty *)aPropertyValue;
RemoveObserver((nsIFrame *)aObject, property->mFilter);
nsSVGFilterProperty *property = NS_STATIC_CAST(nsSVGFilterProperty *,
aPropertyValue);
nsSVGUtils::RemoveObserver(NS_STATIC_CAST(nsIFrame *, aObject),
property->mFilter);
delete property;
}
@ -830,8 +832,12 @@ AddEffectProperties(nsIFrame *aFrame)
nsISVGFilterFrame *filter;
NS_GetSVGFilterFrame(&filter, style->mFilter, aFrame->GetContent());
if (filter) {
AddObserver(aFrame, filter);
nsSVGUtils::AddObserver(aFrame, filter);
nsSVGFilterProperty *property = new nsSVGFilterProperty;
if (!property) {
NS_ERROR("Could not create filter property");
return;
}
property->mFilter = filter;
filter->GetInvalidationRegion(aFrame, getter_AddRefs(property->mFilterRegion));
aFrame->SetProperty(nsGkAtoms::filter, property, FilterPropertyDtor);

View File

@ -82,6 +82,8 @@ class nsIAtom;
#define NS_STATE_SVG_FILTERED 0x00800000
#define NS_STATE_SVG_MASKED 0x01000000
#define NS_STATE_SVG_HAS_MARKERS 0x02000000
class nsSVGUtils
{
public:
@ -257,6 +259,14 @@ public:
static void
HitTestChildren(nsIFrame *aFrame, float x, float y, nsIFrame **aResult);
/* Add observation of an nsISVGValue to an nsISVGValueObserver */
static void
AddObserver(nsISupports *aObserver, nsISupports *aTarget);
/* Remove observation of an nsISVGValue from an nsISVGValueObserver */
static void
RemoveObserver(nsISupports *aObserver, nsISupports *aTarget);
/*
* Returns the CanvasTM of the indicated frame, whether it's a
* child or container SVG frame.