Bug 948265 - [CSS Filters] Change nsSVGFilterProperty to track an nsStyleFilter chain instead of a single nsIURI and nsSVGFilterFrame. r=roc

This commit is contained in:
Max Vujovic 2014-02-09 20:31:03 -08:00
parent 754074e2f0
commit 2b722685f9
8 changed files with 153 additions and 38 deletions

View File

@ -160,7 +160,7 @@ SVGFilterElement::Invalidate()
nsTObserverArray<nsIMutationObserver*>::ForwardIterator iter(*observers);
while (iter.HasMore()) {
nsCOMPtr<nsIMutationObserver> obs(iter.GetNext());
nsCOMPtr<nsISVGFilterProperty> filter = do_QueryInterface(obs);
nsCOMPtr<nsISVGFilterReference> filter = do_QueryInterface(obs);
if (filter)
filter->Invalidate();
}

View File

@ -4971,7 +4971,7 @@ ComputeOutlineAndEffectsRect(nsIFrame* aFrame,
// For SVG frames, we only need to account for filters.
// TODO: We could also take account of clipPath and mask to reduce the
// visual overflow, but that's not essential.
if (aFrame->StyleSVGReset()->SingleFilter()) {
if (aFrame->StyleSVGReset()->HasFilters()) {
if (aStoreRectProperties) {
aFrame->Properties().
Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));

View File

@ -2626,13 +2626,8 @@ struct nsStyleSVGReset {
nsChangeHint_ClearAncestorIntrinsics);
}
// The backend only supports one SVG reference right now.
// Eventually, it will support multiple chained SVG reference filters and CSS
// filter functions.
nsIURI* SingleFilter() const {
return (mFilters.Length() == 1 &&
mFilters[0].GetType() == NS_STYLE_FILTER_URL) ?
mFilters[0].GetURL() : nullptr;
bool HasFilters() const {
return mFilters.Length() > 0;
}
nsCOMPtr<nsIURI> mClipPath; // [reset]

View File

@ -214,12 +214,72 @@ nsSVGRenderingObserver::ContentRemoved(nsIDocument *aDocument,
DoUpdate();
}
NS_IMPL_ISUPPORTS_INHERITED1(nsSVGFilterProperty,
nsSVGIDRenderingObserver,
nsISVGFilterProperty)
NS_IMPL_ISUPPORTS1(nsSVGFilterProperty, nsISupports)
nsSVGFilterProperty::nsSVGFilterProperty(const nsTArray<nsStyleFilter> &aFilters,
nsIFrame *aFilteredFrame) :
mFilters(aFilters)
{
for (uint32_t i = 0; i < mFilters.Length(); i++) {
if (mFilters[i].GetType() != NS_STYLE_FILTER_URL)
continue;
nsSVGFilterReference *reference =
new nsSVGFilterReference(mFilters[i].GetURL(), aFilteredFrame);
NS_ADDREF(reference);
mReferences.AppendElement(reference);
}
}
nsSVGFilterProperty::~nsSVGFilterProperty()
{
for (uint32_t i = 0; i < mReferences.Length(); i++) {
NS_RELEASE(mReferences[i]);
}
}
bool
nsSVGFilterProperty::ReferencesValidResources()
{
for (uint32_t i = 0; i < mReferences.Length(); i++) {
if (!mReferences[i]->ReferencesValidResource())
return false;
}
return true;
}
bool
nsSVGFilterProperty::IsInObserverLists() const
{
for (uint32_t i = 0; i < mReferences.Length(); i++) {
if (!mReferences[i]->IsInObserverList())
return false;
}
return true;
}
void
nsSVGFilterProperty::Invalidate()
{
for (uint32_t i = 0; i < mReferences.Length(); i++) {
mReferences[i]->Invalidate();
}
}
nsSVGFilterFrame *
nsSVGFilterProperty::GetFilterFrame()
{
// Eventually, callers will ask nsSVGFilterProperty for an nsStyleFilter
// chain, not a single nsSVGFilterFrame, and this function will go away.
return mReferences.Length() > 0 ? mReferences[0]->GetFilterFrame() : nullptr;
}
NS_IMPL_ISUPPORTS_INHERITED1(nsSVGFilterReference,
nsSVGIDRenderingObserver,
nsISVGFilterReference);
nsSVGFilterFrame *
nsSVGFilterReference::GetFilterFrame()
{
return static_cast<nsSVGFilterFrame *>
(GetReferencedFrame(nsGkAtoms::svgFilterFrame, nullptr));
@ -235,7 +295,7 @@ InvalidateAllContinuations(nsIFrame* aFrame)
}
void
nsSVGFilterProperty::DoUpdate()
nsSVGFilterReference::DoUpdate()
{
nsSVGIDRenderingObserver::DoUpdate();
if (!mFrame)
@ -334,10 +394,6 @@ nsSVGPaintingProperty::DoUpdate()
}
}
static nsSVGRenderingObserver *
CreateFilterProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
{ return new nsSVGFilterProperty(aURI, aFrame, aReferenceImage); }
static nsSVGRenderingObserver *
CreateMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
{ return new nsSVGMarkerProperty(aURI, aFrame, aReferenceImage); }
@ -371,6 +427,26 @@ GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame,
return prop;
}
static nsSVGFilterProperty*
GetOrCreateFilterProperty(nsIFrame *aFrame)
{
const nsStyleSVGReset* style = aFrame->StyleSVGReset();
if (!style->HasFilters())
return nullptr;
FrameProperties props = aFrame->Properties();
nsSVGFilterProperty *prop =
static_cast<nsSVGFilterProperty*>(props.Get(nsSVGEffects::FilterProperty()));
if (prop)
return prop;
prop = new nsSVGFilterProperty(style->mFilters, aFrame);
if (!prop)
return nullptr;
NS_ADDREF(prop);
props.Set(nsSVGEffects::FilterProperty(), static_cast<nsISupports*>(prop));
return prop;
}
nsSVGMarkerProperty *
nsSVGEffects::GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame,
const FramePropertyDescriptor *aProp)
@ -438,9 +514,7 @@ nsSVGEffects::GetEffectProperties(nsIFrame *aFrame)
EffectProperties result;
const nsStyleSVGReset *style = aFrame->StyleSVGReset();
result.mFilter = static_cast<nsSVGFilterProperty*>
(GetEffectProperty(style->SingleFilter(), aFrame, FilterProperty(),
CreateFilterProperty));
result.mFilter = GetOrCreateFilterProperty(aFrame);
result.mClipPath =
GetPaintingProperty(style->mClipPath, aFrame, ClipPathProperty());
result.mMask =
@ -515,8 +589,7 @@ nsSVGEffects::UpdateEffects(nsIFrame *aFrame)
// Ensure that the filter is repainted correctly
// We can't do that in DoUpdate as the referenced frame may not be valid
GetEffectProperty(aFrame->StyleSVGReset()->SingleFilter(),
aFrame, FilterProperty(), CreateFilterProperty);
GetOrCreateFilterProperty(aFrame);
if (aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame &&
static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
@ -536,7 +609,7 @@ nsSVGEffects::GetFilterProperty(nsIFrame *aFrame)
{
NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
if (!aFrame->StyleSVGReset()->SingleFilter())
if (!aFrame->StyleSVGReset()->HasFilters())
return nullptr;
return static_cast<nsSVGFilterProperty *>

View File

@ -150,12 +150,25 @@ protected:
nsIPresShell *mFramePresShell;
};
class nsSVGFilterProperty :
public nsSVGIDRenderingObserver, public nsISVGFilterProperty {
/**
* In a filter chain, there can be multiple SVG reference filters.
* e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
*
* This class keeps track of one SVG reference filter in a filter chain.
* e.g. url(#svg-filter-1)
*
* It fires invalidations when the SVG filter element's id changes or when
* the SVG filter element's content changes.
*
* The nsSVGFilterProperty class manages a list of nsSVGFilterReferences.
*/
class nsSVGFilterReference :
public nsSVGIDRenderingObserver, public nsISVGFilterReference {
public:
nsSVGFilterProperty(nsIURI *aURI, nsIFrame *aFilteredFrame,
bool aReferenceImage)
: nsSVGIDRenderingObserver(aURI, aFilteredFrame, aReferenceImage) {}
nsSVGFilterReference(nsIURI *aURI, nsIFrame *aFilteredFrame)
: nsSVGIDRenderingObserver(aURI, aFilteredFrame, false) {}
bool ReferencesValidResource() { return GetFilterFrame(); }
/**
* @return the filter frame, or null if there is no filter frame
@ -165,14 +178,48 @@ public:
// nsISupports
NS_DECL_ISUPPORTS
// nsISVGFilterProperty
virtual void Invalidate() MOZ_OVERRIDE { DoUpdate(); }
// nsISVGFilterReference
virtual void Invalidate() MOZ_OVERRIDE { DoUpdate(); };
private:
// nsSVGRenderingObserver
// nsSVGIDRenderingObserver
virtual void DoUpdate() MOZ_OVERRIDE;
};
/**
* This class manages a list of nsSVGFilterReferences, which represent SVG
* reference filters in a filter chain.
* e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
*
* In the above example, the nsSVGFilterProperty will manage two
* nsSVGFilterReferences, one for each SVG reference filter. CSS filters like
* "blur(10px)" don't reference filter elements, so they don't need an
* nsSVGFilterReference. The style system invalidates changes to CSS filters.
*/
class nsSVGFilterProperty : public nsISupports {
public:
nsSVGFilterProperty(const nsTArray<nsStyleFilter> &aFilters,
nsIFrame *aFilteredFrame);
virtual ~nsSVGFilterProperty();
const nsTArray<nsStyleFilter>& GetFilters() { return mFilters; }
bool ReferencesValidResources();
bool IsInObserverLists() const;
void Invalidate();
/**
* @return the filter frame, or null if there is no filter frame
*/
nsSVGFilterFrame *GetFilterFrame();
// nsISupports
NS_DECL_ISUPPORTS
private:
nsTArray<nsSVGFilterReference*> mReferences;
nsTArray<nsStyleFilter> mFilters;
};
class nsSVGMarkerProperty : public nsSVGIDRenderingObserver {
public:
nsSVGMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)

View File

@ -152,7 +152,7 @@ nsSVGIntegrationUtils::UsingEffectsForFrame(const nsIFrame* aFrame)
// checking the SDL prefs here, since we don't know if we're being called for
// painting or hit-testing anyway.
const nsStyleSVGReset *style = aFrame->StyleSVGReset();
return (style->SingleFilter() || style->mClipPath || style->mMask);
return (style->HasFilters() || style->mClipPath || style->mMask);
}
/* static */ nsPoint
@ -302,7 +302,7 @@ nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame,
return aInvalidRect;
nsSVGFilterProperty *prop = nsSVGEffects::GetFilterProperty(firstFrame);
if (!prop || !prop->IsInObserverList()) {
if (!prop || !prop->IsInObserverLists()) {
return aInvalidRect;
}

View File

@ -930,7 +930,7 @@ nsSVGUtils::CanOptimizeOpacity(nsIFrame *aFrame)
type != nsGkAtoms::svgPathGeometryFrame) {
return false;
}
if (aFrame->StyleSVGReset()->SingleFilter()) {
if (aFrame->StyleSVGReset()->HasFilters()) {
return false;
}
// XXX The SVG WG is intending to allow fill, stroke and markers on <image>

View File

@ -161,18 +161,18 @@ private:
};
#define NS_ISVGFILTERPROPERTY_IID \
#define NS_ISVGFILTERREFERENCE_IID \
{ 0x9744ee20, 0x1bcf, 0x4c62, \
{ 0x86, 0x7d, 0xd3, 0x7a, 0x91, 0x60, 0x3e, 0xef } }
class nsISVGFilterProperty : public nsISupports
class nsISVGFilterReference : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISVGFILTERPROPERTY_IID)
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISVGFILTERREFERENCE_IID)
virtual void Invalidate() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsISVGFilterProperty, NS_ISVGFILTERPROPERTY_IID)
NS_DEFINE_STATIC_IID_ACCESSOR(nsISVGFilterReference, NS_ISVGFILTERREFERENCE_IID)
/**
* General functions used by all of SVG layout and possibly content code.