diff --git a/layout/svg/base/src/nsSVGClipPathFrame.cpp b/layout/svg/base/src/nsSVGClipPathFrame.cpp index b4245430f5c0..1068d5c4ba2f 100644 --- a/layout/svg/base/src/nsSVGClipPathFrame.cpp +++ b/layout/svg/base/src/nsSVGClipPathFrame.cpp @@ -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(); diff --git a/layout/svg/base/src/nsSVGFilterFrame.cpp b/layout/svg/base/src/nsSVGFilterFrame.cpp index f9e44f98337c..1296076ad650 100644 --- a/layout/svg/base/src/nsSVGFilterFrame.cpp +++ b/layout/svg/base/src/nsSVGFilterFrame.cpp @@ -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(); diff --git a/layout/svg/base/src/nsSVGMarkerFrame.cpp b/layout/svg/base/src/nsSVGMarkerFrame.cpp index b19d166ba4c0..e49c7e97817a 100644 --- a/layout/svg/base/src/nsSVGMarkerFrame.cpp +++ b/layout/svg/base/src/nsSVGMarkerFrame.cpp @@ -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; } diff --git a/layout/svg/base/src/nsSVGMaskFrame.cpp b/layout/svg/base/src/nsSVGMaskFrame.cpp index 0158dfacbffe..121432e53c74 100644 --- a/layout/svg/base/src/nsSVGMaskFrame.cpp +++ b/layout/svg/base/src/nsSVGMaskFrame.cpp @@ -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(); diff --git a/layout/svg/base/src/nsSVGPathFrame.cpp b/layout/svg/base/src/nsSVGPathFrame.cpp index 7c4ea80ee8c9..8c030fd0500c 100644 --- a/layout/svg/base/src/nsSVGPathFrame.cpp +++ b/layout/svg/base/src/nsSVGPathFrame.cpp @@ -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" diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp index 1af6821e73be..e89d08d7f295 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp @@ -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; diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.h b/layout/svg/base/src/nsSVGPathGeometryFrame.h index 96103ec6e7e5..794c680b1991 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.h +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.h @@ -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 mGeometry; PRUint32 mUpdateFlags; diff --git a/layout/svg/base/src/nsSVGPolygonFrame.cpp b/layout/svg/base/src/nsSVGPolygonFrame.cpp index ec5fce137afc..399a6a44a362 100644 --- a/layout/svg/base/src/nsSVGPolygonFrame.cpp +++ b/layout/svg/base/src/nsSVGPolygonFrame.cpp @@ -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" diff --git a/layout/svg/base/src/nsSVGPolylineFrame.cpp b/layout/svg/base/src/nsSVGPolylineFrame.cpp index 3ef924b92999..51a446af0096 100644 --- a/layout/svg/base/src/nsSVGPolylineFrame.cpp +++ b/layout/svg/base/src/nsSVGPolylineFrame.cpp @@ -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" diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index ddcf9d5cbc8d..6adf233c9002 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -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); diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h index 235395b6edc8..5c3677060210 100644 --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -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.