Bug 309220 - SVG markers should be live to id changes in document. r+sr=roc

This commit is contained in:
Robert Longson 2008-10-10 14:14:05 +01:00
Родитель 88bca445c7
Коммит 90cf71cd07
7 изменённых файлов: 154 добавлений и 230 удалений

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

@ -182,7 +182,8 @@ nsSVGFilterProperty::nsSVGFilterProperty(nsIURI *aURI,
}
nsSVGFilterFrame *
nsSVGFilterProperty::GetFilterFrame() {
nsSVGFilterProperty::GetFilterFrame()
{
return static_cast<nsSVGFilterFrame *>
(GetReferencedFrame(nsGkAtoms::svgFilterFrame, nsnull));
}
@ -229,6 +230,24 @@ nsSVGFilterProperty::DoUpdate()
}
}
void
nsSVGMarkerProperty::DoUpdate()
{
nsSVGRenderingObserver::DoUpdate();
if (!mFrame)
return;
if (mFrame->IsFrameOfType(nsIFrame::eSVG)) {
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
if (outerSVGFrame) {
// marker changes can change the covered region
outerSVGFrame->UpdateAndInvalidateCoveredRegion(mFrame);
}
} else {
InvalidateAllContinuations(mFrame);
}
}
void
nsSVGPaintingProperty::DoUpdate()
{
@ -250,6 +269,10 @@ static nsSVGRenderingObserver *
CreateFilterProperty(nsIURI *aURI, nsIFrame *aFrame)
{ return new nsSVGFilterProperty(aURI, aFrame); }
static nsSVGRenderingObserver *
CreateMarkerProperty(nsIURI *aURI, nsIFrame *aFrame)
{ return new nsSVGMarkerProperty(aURI, aFrame); }
static nsSVGRenderingObserver *
CreatePaintingProperty(nsIURI *aURI, nsIFrame *aFrame)
{ return new nsSVGPaintingProperty(aURI, aFrame); }
@ -274,6 +297,13 @@ GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp,
return prop;
}
nsSVGMarkerProperty *
nsSVGEffects::GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp)
{
return static_cast<nsSVGMarkerProperty*>(
GetEffectProperty(aURI, aFrame, aProp, CreateMarkerProperty));
}
nsSVGPaintingProperty *
nsSVGEffects::GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp)
{
@ -296,7 +326,8 @@ nsSVGEffects::GetEffectProperties(nsIFrame *aFrame)
}
nsSVGClipPathFrame *
nsSVGEffects::EffectProperties::GetClipPathFrame(PRBool *aOK) {
nsSVGEffects::EffectProperties::GetClipPathFrame(PRBool *aOK)
{
if (!mClipPath)
return nsnull;
return static_cast<nsSVGClipPathFrame *>
@ -304,7 +335,8 @@ nsSVGEffects::EffectProperties::GetClipPathFrame(PRBool *aOK) {
}
nsSVGMaskFrame *
nsSVGEffects::EffectProperties::GetMaskFrame(PRBool *aOK) {
nsSVGEffects::EffectProperties::GetMaskFrame(PRBool *aOK)
{
if (!mMask)
return nsnull;
return static_cast<nsSVGMaskFrame *>
@ -318,6 +350,10 @@ nsSVGEffects::UpdateEffects(nsIFrame *aFrame)
aFrame->DeleteProperty(nsGkAtoms::mask);
aFrame->DeleteProperty(nsGkAtoms::clipPath);
aFrame->DeleteProperty(nsGkAtoms::marker_start);
aFrame->DeleteProperty(nsGkAtoms::marker_mid);
aFrame->DeleteProperty(nsGkAtoms::marker_end);
aFrame->DeleteProperty(nsGkAtoms::stroke);
aFrame->DeleteProperty(nsGkAtoms::fill);
}

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

@ -150,10 +150,19 @@ private:
nsRect mFilterRect;
};
class nsSVGMarkerProperty : public nsSVGRenderingObserver {
public:
nsSVGMarkerProperty(nsIURI *aURI, nsIFrame *aFrame)
: nsSVGRenderingObserver(aURI, aFrame) {}
protected:
virtual void DoUpdate();
};
class nsSVGPaintingProperty : public nsSVGRenderingObserver {
public:
nsSVGPaintingProperty(nsIURI *aURI, nsIFrame *aClippedFrame)
: nsSVGRenderingObserver(aURI, aClippedFrame) {}
nsSVGPaintingProperty(nsIURI *aURI, nsIFrame *aFrame)
: nsSVGRenderingObserver(aURI, aFrame) {}
protected:
virtual void DoUpdate();
@ -264,6 +273,11 @@ public:
*/
static void InvalidateDirectRenderingObservers(nsIFrame *aFrame);
/**
* Get an nsSVGMarkerProperty for the frame, creating a fresh one if necessary
*/
static nsSVGMarkerProperty *
GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp);
/**
* Get an nsSVGPaintingProperty for the frame, creating a fresh one if necessary
*/

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

@ -40,6 +40,7 @@
#include "nsSVGMarkerFrame.h"
#include "nsSVGPathGeometryFrame.h"
#include "nsSVGMatrix.h"
#include "nsSVGEffects.h"
#include "nsSVGMarkerElement.h"
#include "nsSVGPathGeometryElement.h"
#include "gfxContext.h"
@ -69,6 +70,36 @@ NS_GetSVGMarkerElement(nsIURI *aURI, nsIContent *aContent)
return nsnull;
}
//----------------------------------------------------------------------
// nsIFrame methods:
NS_IMETHODIMP
nsSVGMarkerFrame::AttributeChanged(PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType)
{
if (aNameSpaceID == kNameSpaceID_None &&
(aAttribute == nsGkAtoms::markerUnits ||
aAttribute == nsGkAtoms::refX ||
aAttribute == nsGkAtoms::refY ||
aAttribute == nsGkAtoms::markerWidth ||
aAttribute == nsGkAtoms::markerHeight ||
aAttribute == nsGkAtoms::orient ||
aAttribute == nsGkAtoms::preserveAspectRatio ||
aAttribute == nsGkAtoms::viewBox)) {
nsSVGEffects::InvalidateRenderingObservers(this);
}
return nsSVGMarkerFrameBase::AttributeChanged(aNameSpaceID,
aAttribute, aModType);
}
nsIAtom *
nsSVGMarkerFrame::GetType() const
{
return nsGkAtoms::svgMarkerFrame;
}
//----------------------------------------------------------------------
// nsSVGContainerFrame methods:
@ -228,13 +259,6 @@ nsSVGMarkerFrame::RegionMark(nsSVGPathGeometryFrame *aMarkedFrame,
return nsSVGUtils::GetCoveredRegion(mFrames);
}
nsIAtom *
nsSVGMarkerFrame::GetType() const
{
return nsGkAtoms::svgMarkerFrame;
}
void
nsSVGMarkerFrame::SetParentCoordCtxProvider(nsSVGSVGElement *aContext)
{

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

@ -59,6 +59,10 @@ protected:
mInUse2(PR_FALSE) {}
public:
// nsIFrame interface:
NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType);
/**
* Get the "type" of the frame
*

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

@ -37,180 +37,17 @@
* ***** END LICENSE BLOCK ***** */
#include "nsSVGPathGeometryFrame.h"
#include "nsSVGContainerFrame.h"
#include "nsReadableUtils.h"
#include "nsUnicharUtils.h"
#include "nsGkAtoms.h"
#include "nsSVGMarkerFrame.h"
#include "nsSVGMatrix.h"
#include "nsSVGUtils.h"
#include "nsSVGEffects.h"
#include "nsSVGGraphicElement.h"
#include "nsSVGOuterSVGFrame.h"
#include "nsSVGRect.h"
#include "nsSVGPathGeometryElement.h"
#include "gfxContext.h"
class nsSVGMarkerProperty : public nsStubMutationObserver {
public:
nsSVGMarkerProperty(nsIURI *aMarkerStart,
nsIURI *aMarkerMid,
nsIURI *aMarkerEnd,
nsSVGPathGeometryFrame *aMarkedFrame);
virtual ~nsSVGMarkerProperty();
nsSVGMarkerFrame *GetMarkerStartFrame() {
return GetMarkerFrame(mObservedMarkerStart);
}
nsSVGMarkerFrame *GetMarkerMidFrame() {
return GetMarkerFrame(mObservedMarkerMid);
}
nsSVGMarkerFrame *GetMarkerEndFrame() {
return GetMarkerFrame(mObservedMarkerEnd);
}
// nsISupports
NS_DECL_ISUPPORTS
// nsIMutationObserver
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
private:
nsSVGMarkerFrame *GetMarkerFrame(nsWeakPtr aObservedMarker);
already_AddRefed<nsIWeakReference>
AddMutationObserver(nsIURI *aURI, nsIContent *aContent);
void RemoveMutationObserver(nsWeakPtr aObservedMarker);
void DoUpdate();
nsWeakPtr mObservedMarkerStart, mObservedMarkerMid, mObservedMarkerEnd;
nsSVGPathGeometryFrame *mFrame; // frame being marked
};
NS_IMPL_ISUPPORTS1(nsSVGMarkerProperty, nsIMutationObserver)
nsSVGMarkerProperty::nsSVGMarkerProperty(nsIURI *aMarkerStart,
nsIURI *aMarkerMid,
nsIURI *aMarkerEnd,
nsSVGPathGeometryFrame *aMarkedFrame)
: mFrame(aMarkedFrame)
{
nsIContent *content = mFrame->GetContent();
mObservedMarkerStart = AddMutationObserver(aMarkerStart, content);
mObservedMarkerMid = AddMutationObserver(aMarkerMid, content);
mObservedMarkerEnd = AddMutationObserver(aMarkerEnd, content);
NS_ADDREF(this); // addref to allow QI - SupportsDtorFunc releases
mFrame->SetProperty(nsGkAtoms::marker,
static_cast<nsISupports*>(this),
nsPropertyTable::SupportsDtorFunc);
mFrame->AddStateBits(NS_STATE_SVG_HAS_MARKERS);
}
nsSVGMarkerProperty::~nsSVGMarkerProperty()
{
RemoveMutationObserver(mObservedMarkerStart);
RemoveMutationObserver(mObservedMarkerMid);
RemoveMutationObserver(mObservedMarkerEnd);
mFrame->RemoveStateBits(NS_STATE_SVG_HAS_MARKERS);
}
nsSVGMarkerFrame *
nsSVGMarkerProperty::GetMarkerFrame(nsWeakPtr aObservedMarker)
{
nsCOMPtr<nsIContent> marker = do_QueryReferent(aObservedMarker);
if (marker) {
nsIFrame *frame =
static_cast<nsGenericElement*>(marker.get())->GetPrimaryFrame();
if (frame && frame->GetType() == nsGkAtoms::svgMarkerFrame)
return static_cast<nsSVGMarkerFrame*>(frame);
}
return nsnull;
}
already_AddRefed<nsIWeakReference>
nsSVGMarkerProperty::AddMutationObserver(nsIURI *aURI,
nsIContent *aContent)
{
if (!aURI)
return nsnull;
nsIContent *marker = NS_GetSVGMarkerElement(aURI, aContent);
if (marker) {
marker->AddMutationObserver(this);
return do_GetWeakReference(marker);
}
return nsnull;
}
void
nsSVGMarkerProperty::RemoveMutationObserver(nsWeakPtr aObservedMarker)
{
if (!aObservedMarker)
return;
nsCOMPtr<nsIContent> marker = do_QueryReferent(aObservedMarker);
if (marker)
marker->RemoveMutationObserver(this);
}
void
nsSVGMarkerProperty::DoUpdate()
{
nsSVGUtils::UpdateGraphic(mFrame);
}
void
nsSVGMarkerProperty::AttributeChanged(nsIDocument *aDocument,
nsIContent *aContent,
PRInt32 aNameSpaceID,
nsIAtom *aAttribute,
PRInt32 aModType,
PRUint32 aStateMask)
{
DoUpdate();
}
void
nsSVGMarkerProperty::ContentAppended(nsIDocument *aDocument,
nsIContent *aContainer,
PRInt32 aNewIndexInContainer)
{
DoUpdate();
}
void
nsSVGMarkerProperty::ContentInserted(nsIDocument *aDocument,
nsIContent *aContainer,
nsIContent *aChild,
PRInt32 aIndexInContainer)
{
DoUpdate();
}
void
nsSVGMarkerProperty::ContentRemoved(nsIDocument *aDocument,
nsIContent *aContainer,
nsIContent *aChild,
PRInt32 aIndexInContainer)
{
DoUpdate();
}
void
nsSVGMarkerProperty::ParentChainChanged(nsIContent *aContent)
{
if (aContent->IsInDoc())
return;
mFrame->DeleteProperty(nsGkAtoms::marker);
}
//----------------------------------------------------------------------
// Implementation
@ -232,13 +69,6 @@ NS_INTERFACE_MAP_END_INHERITING(nsSVGPathGeometryFrameBase)
//----------------------------------------------------------------------
// nsIFrame methods
void
nsSVGPathGeometryFrame::Destroy()
{
RemovePathProperties();
nsSVGPathGeometryFrameBase::Destroy();
}
NS_IMETHODIMP
nsSVGPathGeometryFrame::AttributeChanged(PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
@ -264,8 +94,6 @@ nsSVGPathGeometryFrame::DidSetStyleContext()
outerSVGFrame->InvalidateCoveredRegion(this);
}
RemovePathProperties();
// 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
@ -297,9 +125,9 @@ nsSVGPathGeometryFrame::PaintSVG(nsSVGRenderState *aContext,
Render(aContext);
if (static_cast<nsSVGPathGeometryElement*>(mContent)->IsMarkable()) {
nsSVGMarkerProperty *property = GetMarkerProperty();
MarkerProperties properties = GetMarkerProperties(this);
if (property) {
if (properties.MarkersExist()) {
float strokeWidth = GetStrokeWidth();
nsTArray<nsSVGMark> marks;
@ -309,17 +137,17 @@ nsSVGPathGeometryFrame::PaintSVG(nsSVGRenderState *aContext,
PRUint32 num = marks.Length();
if (num) {
nsSVGMarkerFrame *frame = property->GetMarkerStartFrame();
nsSVGMarkerFrame *frame = properties.GetMarkerStartFrame();
if (frame)
frame->PaintMark(aContext, this, &marks[0], strokeWidth);
frame = property->GetMarkerMidFrame();
frame = properties.GetMarkerMidFrame();
if (frame) {
for (PRUint32 i = 1; i < num - 1; i++)
frame->PaintMark(aContext, this, &marks[i], strokeWidth);
}
frame = property->GetMarkerEndFrame();
frame = properties.GetMarkerEndFrame();
if (frame)
frame->PaintMark(aContext, this, &marks[num-1], strokeWidth);
}
@ -378,9 +206,9 @@ NS_IMETHODIMP_(nsRect)
nsSVGPathGeometryFrame::GetCoveredRegion()
{
if (static_cast<nsSVGPathGeometryElement*>(mContent)->IsMarkable()) {
nsSVGMarkerProperty *property = GetMarkerProperty();
MarkerProperties properties = GetMarkerProperties(this);
if (!property)
if (!properties.MarkersExist())
return mRect;
nsRect rect(mRect);
@ -393,13 +221,13 @@ nsSVGPathGeometryFrame::GetCoveredRegion()
PRUint32 num = marks.Length();
if (num) {
nsSVGMarkerFrame *frame = property->GetMarkerStartFrame();
nsSVGMarkerFrame *frame = properties.GetMarkerStartFrame();
if (frame) {
nsRect mark = frame->RegionMark(this, &marks[0], strokeWidth);
rect.UnionRect(rect, mark);
}
frame = property->GetMarkerMidFrame();
frame = properties.GetMarkerMidFrame();
if (frame) {
for (PRUint32 i = 1; i < num - 1; i++) {
nsRect mark = frame->RegionMark(this, &marks[i], strokeWidth);
@ -407,7 +235,7 @@ nsSVGPathGeometryFrame::GetCoveredRegion()
}
}
frame = property->GetMarkerEndFrame();
frame = properties.GetMarkerEndFrame();
if (frame) {
nsRect mark = frame->RegionMark(this, &marks[num-1], strokeWidth);
rect.UnionRect(rect, mark);
@ -446,7 +274,6 @@ nsSVGPathGeometryFrame::UpdateCoveredRegion()
}
// Add in markers
UpdateMarkerProperty();
mRect = GetCoveredRegion();
nsSVGUtils::UpdateFilterRegion(this);
@ -577,39 +404,47 @@ nsSVGPathGeometryFrame::GetCanvasTM(nsIDOMSVGMatrix * *aCTM)
//----------------------------------------------------------------------
// nsSVGPathGeometryFrame methods:
nsSVGMarkerProperty *
nsSVGPathGeometryFrame::GetMarkerProperty()
nsSVGPathGeometryFrame::MarkerProperties
nsSVGPathGeometryFrame::GetMarkerProperties(nsSVGPathGeometryFrame *aFrame)
{
if (GetStateBits() & NS_STATE_SVG_HAS_MARKERS)
return static_cast<nsSVGMarkerProperty *>
(GetProperty(nsGkAtoms::marker));
NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
return nsnull;
MarkerProperties result;
const nsStyleSVG *style = aFrame->GetStyleSVG();
result.mMarkerStart = nsSVGEffects::GetMarkerProperty(
style->mMarkerStart, aFrame, nsGkAtoms::marker_start);
result.mMarkerMid = nsSVGEffects::GetMarkerProperty(
style->mMarkerMid, aFrame, nsGkAtoms::marker_mid);
result.mMarkerEnd = nsSVGEffects::GetMarkerProperty(
style->mMarkerEnd, aFrame, nsGkAtoms::marker_end);
return result;
}
void
nsSVGPathGeometryFrame::UpdateMarkerProperty()
nsSVGMarkerFrame *
nsSVGPathGeometryFrame::MarkerProperties::GetMarkerStartFrame()
{
if (GetStateBits() & NS_STATE_SVG_HAS_MARKERS)
return;
const nsStyleSVG *style = GetStyleSVG();
if ((style->mMarkerStart || style->mMarkerMid || style->mMarkerEnd) &&
!new nsSVGMarkerProperty(style->mMarkerStart,
style->mMarkerMid,
style->mMarkerEnd,
this)) {
NS_ERROR("Could not create marker property");
return;
}
if (!mMarkerStart)
return nsnull;
return static_cast<nsSVGMarkerFrame *>
(mMarkerStart->GetReferencedFrame(nsGkAtoms::svgMarkerFrame, nsnull));
}
void
nsSVGPathGeometryFrame::RemovePathProperties()
nsSVGMarkerFrame *
nsSVGPathGeometryFrame::MarkerProperties::GetMarkerMidFrame()
{
if (GetStateBits() & NS_STATE_SVG_HAS_MARKERS)
DeleteProperty(nsGkAtoms::marker);
if (!mMarkerMid)
return nsnull;
return static_cast<nsSVGMarkerFrame *>
(mMarkerMid->GetReferencedFrame(nsGkAtoms::svgMarkerFrame, nsnull));
}
nsSVGMarkerFrame *
nsSVGPathGeometryFrame::MarkerProperties::GetMarkerEndFrame()
{
if (!mMarkerEnd)
return nsnull;
return static_cast<nsSVGMarkerFrame *>
(mMarkerEnd->GetReferencedFrame(nsGkAtoms::svgMarkerFrame, nsnull));
}
void

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

@ -76,7 +76,6 @@ private:
public:
// nsIFrame interface:
virtual void Destroy();
NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType);
@ -137,10 +136,24 @@ private:
rect.Width() == 0 && rect.Height() == 0);
}
nsSVGMarkerProperty *GetMarkerProperty();
void UpdateMarkerProperty();
struct MarkerProperties {
nsSVGMarkerProperty* mMarkerStart;
nsSVGMarkerProperty* mMarkerMid;
nsSVGMarkerProperty* mMarkerEnd;
void RemovePathProperties();
PRBool MarkersExist() const {
return mMarkerStart || mMarkerMid || mMarkerEnd;
}
nsSVGMarkerFrame *GetMarkerStartFrame();
nsSVGMarkerFrame *GetMarkerMidFrame();
nsSVGMarkerFrame *GetMarkerEndFrame();
};
/**
* @param aFrame should be the first continuation
*/
static MarkerProperties GetMarkerProperties(nsSVGPathGeometryFrame *aFrame);
nsCOMPtr<nsIDOMSVGMatrix> mOverrideCTM;
};

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

@ -86,14 +86,12 @@ class nsISVGChildFrame;
// SVG Frame state bits
#define NS_STATE_IS_OUTER_SVG 0x00100000
#define NS_STATE_SVG_HAS_MARKERS 0x00200000
#define NS_STATE_SVG_DIRTY 0x00400000
#define NS_STATE_SVG_DIRTY 0x00200000
/* are we the child of a non-display container? */
#define NS_STATE_SVG_NONDISPLAY_CHILD 0x00800000
#define NS_STATE_SVG_NONDISPLAY_CHILD 0x00400000
#define NS_STATE_SVG_PROPAGATE_TRANSFORM 0x01000000
#define NS_STATE_SVG_PROPAGATE_TRANSFORM 0x00800000
/**
* Byte offsets of channels in a native packed gfxColor or cairo image surface.