Bug 652991 - Part 7. Using FragmentOrURL to represent SVG filter url.
MozReview-Commit-ID: F6BpTQfC82i
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -393,26 +393,16 @@ SetCalcValue(const PixelCalcValue& aCalc
arr->Item(0).SetArrayValue(arr2, eCSSUnit_Calc_Plus);
arr2->Item(0).SetFloatValue(aCalc.mLength, eCSSUnit_Pixel);
arr2->Item(1).SetPercentValue(aCalc.mPercent);
}
aValue.SetArrayValue(arr, eCSSUnit_Calc);
}
-static already_AddRefed<nsStringBuffer>
-GetURIAsUtf16StringBuffer(nsIURI* aUri)
-{
- nsAutoCString utf8String;
- nsresult rv = aUri->GetSpec(utf8String);
- NS_ENSURE_SUCCESS(rv, nullptr);
-
- return nsCSSValue::BufferFromString(NS_ConvertUTF8toUTF16(utf8String));
-}
-
double
CalcPositionSquareDistance(const nsCSSValue& aPos1,
const nsCSSValue& aPos2)
{
NS_ASSERTION(aPos1.GetUnit() == eCSSUnit_Array &&
aPos2.GetUnit() == eCSSUnit_Array,
"Expected two arrays");
@@ -3994,20 +3984,22 @@ StyleAnimationValue::ExtractComputedValu
for (uint32_t i = 0; i < filters.Length(); ++i) {
nsCSSValueList *item = new nsCSSValueList;
*resultTail = item;
resultTail = &item->mNext;
const nsStyleFilter& filter = filters[i];
int32_t type = filter.GetType();
if (type == NS_STYLE_FILTER_URL) {
nsIDocument* doc = aStyleContext->PresContext()->Document();
+ nsString pathString;
+ filter.GetURL()->GetSourceString(pathString);
RefPtr<nsStringBuffer> uriAsStringBuffer =
- GetURIAsUtf16StringBuffer(filter.GetURL());
+ nsCSSValue::BufferFromString(pathString);
RefPtr<mozilla::css::URLValue> url =
- new mozilla::css::URLValue(filter.GetURL(),
+ new mozilla::css::URLValue(filter.GetURL()->GetSourceURL(),
uriAsStringBuffer,
doc->GetDocumentURI(),
doc->NodePrincipal());
item->mValue.SetURLValue(url);
} else {
nsCSSKeyword functionName =
nsCSSProps::ValueToKeywordEnum(type,
nsCSSProps::kFilterFunctionKTable);
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -6061,17 +6061,19 @@ nsComputedDOMStyle::SetCssTextToCoord(ns
already_AddRefed<CSSValue>
nsComputedDOMStyle::CreatePrimitiveValueForStyleFilter(
const nsStyleFilter& aStyleFilter)
{
RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
// Handle url().
if (aStyleFilter.GetType() == NS_STYLE_FILTER_URL) {
- value->SetURI(aStyleFilter.GetURL());
+ // Bug 1288812 - we should only serialize fragment for local-ref URL.
+ nsCOMPtr<nsIURI> filterURI = aStyleFilter.GetURL()->GetSourceURL();
+ value->SetURI(filterURI);
return value.forget();
}
// Filter function name and opening parenthesis.
nsAutoString filterFunctionString;
AppendASCIItoUTF16(
nsCSSProps::ValueToKeyword(aStyleFilter.GetType(),
nsCSSProps::kFilterFunctionKTable),
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -9770,21 +9770,17 @@ static bool
SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
const nsCSSValue& aValue,
nsStyleContext* aStyleContext,
nsPresContext* aPresContext,
RuleNodeCacheConditions& aConditions)
{
nsCSSUnit unit = aValue.GetUnit();
if (unit == eCSSUnit_URL) {
- nsIURI* url = aValue.GetURLValue();
- if (!url)
- return false;
- aStyleFilter->SetURL(url);
- return true;
+ return aStyleFilter->SetURL(&aValue);
}
MOZ_ASSERT(unit == eCSSUnit_Function, "expected a filter function");
nsCSSValue::Array* filterFunction = aValue.GetArrayValue();
nsCSSKeyword functionName =
(nsCSSKeyword)filterFunction->Item(0).GetIntValue();
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1245,17 +1245,17 @@ nsStyleFilter::nsStyleFilter()
}
nsStyleFilter::nsStyleFilter(const nsStyleFilter& aSource)
: mType(NS_STYLE_FILTER_NONE)
, mDropShadow(nullptr)
{
MOZ_COUNT_CTOR(nsStyleFilter);
if (aSource.mType == NS_STYLE_FILTER_URL) {
- SetURL(aSource.mURL);
+ CopyURL(aSource);
} else if (aSource.mType == NS_STYLE_FILTER_DROP_SHADOW) {
SetDropShadow(aSource.mDropShadow);
} else if (aSource.mType != NS_STYLE_FILTER_NONE) {
SetFilterParameter(aSource.mFilterParameter, aSource.mType);
}
}
nsStyleFilter::~nsStyleFilter()
@@ -1267,17 +1267,17 @@ nsStyleFilter::~nsStyleFilter()
nsStyleFilter&
nsStyleFilter::operator=(const nsStyleFilter& aOther)
{
if (this == &aOther) {
return *this;
}
if (aOther.mType == NS_STYLE_FILTER_URL) {
- SetURL(aOther.mURL);
+ CopyURL(aOther);
} else if (aOther.mType == NS_STYLE_FILTER_DROP_SHADOW) {
SetDropShadow(aOther.mDropShadow);
} else if (aOther.mType != NS_STYLE_FILTER_NONE) {
SetFilterParameter(aOther.mFilterParameter, aOther.mType);
} else {
ReleaseRef();
mType = NS_STYLE_FILTER_NONE;
}
@@ -1306,38 +1306,52 @@ nsStyleFilter::operator==(const nsStyleF
void
nsStyleFilter::ReleaseRef()
{
if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
NS_ASSERTION(mDropShadow, "expected pointer");
mDropShadow->Release();
} else if (mType == NS_STYLE_FILTER_URL) {
NS_ASSERTION(mURL, "expected pointer");
- mURL->Release();
+ delete mURL;
}
mURL = nullptr;
}
void
+nsStyleFilter::CopyURL(const nsStyleFilter& aOther)
+{
+ ReleaseRef();
+ mURL = new FragmentOrURL(*aOther.mURL);
+ mType = NS_STYLE_FILTER_URL;
+}
+
+void
nsStyleFilter::SetFilterParameter(const nsStyleCoord& aFilterParameter,
int32_t aType)
{
ReleaseRef();
mFilterParameter = aFilterParameter;
mType = aType;
}
-void
-nsStyleFilter::SetURL(nsIURI* aURL)
+bool
+nsStyleFilter::SetURL(const nsCSSValue* aValue)
{
- NS_ASSERTION(aURL, "expected pointer");
+ if (!aValue->GetURLValue()) {
+ return false;
+ }
+
ReleaseRef();
- mURL = aURL;
- mURL->AddRef();
+
+ mURL = new FragmentOrURL();
+ mURL->SetValue(aValue);
+
mType = NS_STYLE_FILTER_URL;
+ return true;
}
void
nsStyleFilter::SetDropShadow(nsCSSShadowArray* aDropShadow)
{
NS_ASSERTION(aDropShadow, "expected pointer");
ReleaseRef();
mDropShadow = aDropShadow;
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -3580,35 +3580,37 @@ struct nsStyleFilter
NS_ASSERTION(mType != NS_STYLE_FILTER_DROP_SHADOW &&
mType != NS_STYLE_FILTER_URL &&
mType != NS_STYLE_FILTER_NONE, "wrong filter type");
return mFilterParameter;
}
void SetFilterParameter(const nsStyleCoord& aFilterParameter,
int32_t aType);
- nsIURI* GetURL() const {
+ FragmentOrURL* GetURL() const {
NS_ASSERTION(mType == NS_STYLE_FILTER_URL, "wrong filter type");
return mURL;
}
- void SetURL(nsIURI* aURL);
+
+ bool SetURL(const nsCSSValue* aValue);
nsCSSShadowArray* GetDropShadow() const {
NS_ASSERTION(mType == NS_STYLE_FILTER_DROP_SHADOW, "wrong filter type");
return mDropShadow;
}
void SetDropShadow(nsCSSShadowArray* aDropShadow);
private:
void ReleaseRef();
+ void CopyURL(const nsStyleFilter& aOther);
int32_t mType; // see NS_STYLE_FILTER_* constants in nsStyleConsts.h
nsStyleCoord mFilterParameter; // coord, percent, factor, angle
union {
- nsIURI* mURL;
+ FragmentOrURL* mURL;
nsCSSShadowArray* mDropShadow;
};
};
template<>
struct nsTArray_CopyChooser<nsStyleFilter>
{
typedef nsTArray_CopyWithConstructors<nsStyleFilter> Type;
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -208,17 +208,17 @@ nsFilterInstance::nsFilterInstance(nsIFr
FrameSpaceToFilterSpace(aPreFilterVisualOverflowRectOverride);
} else if (mTargetFrame) {
nsRect preFilterVOR = mTargetFrame->GetPreEffectsVisualOverflowRect();
targetBounds = FrameSpaceToFilterSpace(&preFilterVOR);
}
mTargetBounds.UnionRect(mTargetBBoxInFilterSpace, targetBounds);
// Build the filter graph.
- rv = BuildPrimitives(aFilterChain);
+ rv = BuildPrimitives(aFilterChain, aTargetFrame);
if (NS_FAILED(rv)) {
return;
}
if (mPrimitiveDescriptions.IsEmpty()) {
// Nothing should be rendered.
return;
}
@@ -268,43 +268,46 @@ nsFilterInstance::FilterSpaceToUserSpace
{
gfxRect userSpaceRect = aFilterSpaceRect;
userSpaceRect.Scale(mFilterSpaceToUserSpaceScale.width,
mFilterSpaceToUserSpaceScale.height);
return userSpaceRect;
}
nsresult
-nsFilterInstance::BuildPrimitives(const nsTArray<nsStyleFilter>& aFilterChain)
+nsFilterInstance::BuildPrimitives(const nsTArray<nsStyleFilter>& aFilterChain,
+ nsIFrame* aTargetFrame)
{
NS_ASSERTION(!mPrimitiveDescriptions.Length(),
"expected to start building primitives from scratch");
for (uint32_t i = 0; i < aFilterChain.Length(); i++) {
- nsresult rv = BuildPrimitivesForFilter(aFilterChain[i]);
+ nsresult rv = BuildPrimitivesForFilter(aFilterChain[i], aTargetFrame);
if (NS_FAILED(rv)) {
return rv;
}
}
mFilterDescription = FilterDescription(mPrimitiveDescriptions);
return NS_OK;
}
nsresult
-nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter)
+nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter,
+ nsIFrame* aTargetFrame)
{
NS_ASSERTION(mUserSpaceToFilterSpaceScale.width > 0.0f &&
mFilterSpaceToUserSpaceScale.height > 0.0f,
"scale factors between spaces should be positive values");
if (aFilter.GetType() == NS_STYLE_FILTER_URL) {
// Build primitives for an SVG filter.
- nsSVGFilterInstance svgFilterInstance(aFilter, mTargetContent,
+ nsSVGFilterInstance svgFilterInstance(aFilter, aTargetFrame,
+ mTargetContent,
mMetrics, mTargetBBox,
mUserSpaceToFilterSpaceScale,
mFilterSpaceToUserSpaceScale);
if (!svgFilterInstance.IsInitialized()) {
return NS_ERROR_FAILURE;
}
return svgFilterInstance.BuildPrimitives(mPrimitiveDescriptions, mInputImages);
--- a/layout/svg/nsFilterInstance.h
+++ b/layout/svg/nsFilterInstance.h
@@ -233,24 +233,26 @@ private:
*/
nsresult BuildSourceImage(DrawTarget* aTargetDT);
/**
* Build the list of FilterPrimitiveDescriptions that describes the filter's
* filter primitives and their connections. This populates
* mPrimitiveDescriptions and mInputImages.
*/
- nsresult BuildPrimitives(const nsTArray<nsStyleFilter>& aFilterChain);
+ nsresult BuildPrimitives(const nsTArray<nsStyleFilter>& aFilterChain,
+ nsIFrame* aTargetFrame);
/**
* Add to the list of FilterPrimitiveDescriptions for a particular SVG
* reference filter or CSS filter. This populates mPrimitiveDescrs and
* mInputImages.
*/
- nsresult BuildPrimitivesForFilter(const nsStyleFilter& aFilter);
+ nsresult BuildPrimitivesForFilter(const nsStyleFilter& aFilter,
+ nsIFrame* aTargetFrame);
/**
* Computes the filter space bounds of the areas that we actually *need* from
* the filter sources, based on the value of mPostFilterDirtyRegion.
* This sets mNeededBounds on the corresponding SourceInfo structs.
*/
void ComputeNeededBoxes();
--- a/layout/svg/nsSVGEffects.cpp
+++ b/layout/svg/nsSVGEffects.cpp
@@ -287,24 +287,31 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReferences);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGFilterChainObserver)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
nsSVGFilterChainObserver::nsSVGFilterChainObserver(const nsTArray<nsStyleFilter>& aFilters,
- nsIContent* aFilteredElement)
+ nsIContent* aFilteredElement,
+ nsIFrame* aFilteredFrame)
{
for (uint32_t i = 0; i < aFilters.Length(); i++) {
if (aFilters[i].GetType() != NS_STYLE_FILTER_URL)
continue;
+ // aFilteredFrame can be null if this filter belongs to a
+ // CanvasRenderingContext2D.
+ nsCOMPtr<nsIURI> filterURL = aFilteredFrame
+ ? nsSVGEffects::GetFilterURI(aFilteredFrame, i)
+ : aFilters[i].GetURL()->Resolve(aFilteredElement);
+
RefPtr<nsSVGFilterReference> reference =
- new nsSVGFilterReference(aFilters[i].GetURL(), aFilteredElement, this);
+ new nsSVGFilterReference(filterURL, aFilteredElement, this);
mReferences.AppendElement(reference);
}
}
nsSVGFilterChainObserver::~nsSVGFilterChainObserver()
{
DetachReferences();
}
@@ -916,8 +923,27 @@ already_AddRefed<nsIURI>
nsSVGEffects::GetClipPathURI(nsIFrame* aFrame)
{
const nsStyleSVGReset* svgResetStyle = aFrame->StyleSVGReset();
MOZ_ASSERT(svgResetStyle->mClipPath.GetType() == StyleClipPathType::URL);
FragmentOrURL* url = svgResetStyle->mClipPath.GetURL();
return ResolveFragmentOrURL(aFrame, url);
}
+
+already_AddRefed<nsIURI>
+nsSVGEffects::GetFilterURI(nsIFrame* aFrame, uint32_t aIndex)
+{
+ const nsStyleEffects* effects = aFrame->StyleEffects();
+ MOZ_ASSERT(effects->mFilters.Length() > aIndex);
+ MOZ_ASSERT(effects->mFilters[aIndex].GetType() == NS_STYLE_FILTER_URL);
+
+ return ResolveFragmentOrURL(aFrame, effects->mFilters[aIndex].GetURL());
+}
+
+already_AddRefed<nsIURI>
+nsSVGEffects::GetFilterURI(nsIFrame* aFrame, const nsStyleFilter& aFilter)
+{
+ MOZ_ASSERT(aFrame->StyleEffects()->mFilters.Length());
+ MOZ_ASSERT(aFilter.GetType() == NS_STYLE_FILTER_URL);
+
+ return ResolveFragmentOrURL(aFrame, aFilter.GetURL());
+}
--- a/layout/svg/nsSVGEffects.h
+++ b/layout/svg/nsSVGEffects.h
@@ -250,17 +250,18 @@ private:
* 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 nsSVGFilterChainObserver : public nsISupports
{
public:
nsSVGFilterChainObserver(const nsTArray<nsStyleFilter>& aFilters,
- nsIContent* aFilteredElement);
+ nsIContent* aFilteredElement,
+ nsIFrame* aFiltedFrame = nullptr);
bool ReferencesValidResources();
bool IsInObserverLists() const;
void Invalidate() { DoUpdate(); }
// nsISupports
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsSVGFilterChainObserver)
@@ -282,17 +283,18 @@ private:
nsTArray<RefPtr<nsSVGFilterReference>> mReferences;
};
class nsSVGFilterProperty : public nsSVGFilterChainObserver
{
public:
nsSVGFilterProperty(const nsTArray<nsStyleFilter> &aFilters,
nsIFrame *aFilteredFrame)
- : nsSVGFilterChainObserver(aFilters, aFilteredFrame->GetContent())
+ : nsSVGFilterChainObserver(aFilters, aFilteredFrame->GetContent(),
+ aFilteredFrame)
, mFrameReference(aFilteredFrame)
{}
void DetachFromFrame() { mFrameReference.Detach(); }
protected:
virtual void DoUpdate() override;
@@ -599,11 +601,23 @@ public:
static already_AddRefed<nsIURI>
GetMarkerURI(nsIFrame* aFrame, FragmentOrURL nsStyleSVG::* aMarker);
/**
* A helper function to resolve clip-path URL.
*/
static already_AddRefed<nsIURI>
GetClipPathURI(nsIFrame* aFrame);
+
+ /**
+ * A helper function to resolve filter URL.
+ */
+ static already_AddRefed<nsIURI>
+ GetFilterURI(nsIFrame* aFrame, uint32_t aIndex);
+
+ /**
+ * A helper function to resolve filter URL.
+ */
+ static already_AddRefed<nsIURI>
+ GetFilterURI(nsIFrame* aFrame, const nsStyleFilter& aFilter);
};
#endif /*NSSVGEFFECTS_H_*/
--- a/layout/svg/nsSVGFilterInstance.cpp
+++ b/layout/svg/nsSVGFilterInstance.cpp
@@ -19,32 +19,33 @@
#include "FilterSupport.h"
#include "gfx2DGlue.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::gfx;
nsSVGFilterInstance::nsSVGFilterInstance(const nsStyleFilter& aFilter,
+ nsIFrame* aTargetFrame,
nsIContent* aTargetContent,
const UserSpaceMetrics& aMetrics,
const gfxRect& aTargetBBox,
const gfxSize& aUserSpaceToFilterSpaceScale,
const gfxSize& aFilterSpaceToUserSpaceScale) :
mFilter(aFilter),
mTargetContent(aTargetContent),
mMetrics(aMetrics),
mTargetBBox(aTargetBBox),
mUserSpaceToFilterSpaceScale(aUserSpaceToFilterSpaceScale),
mFilterSpaceToUserSpaceScale(aFilterSpaceToUserSpaceScale),
mSourceAlphaAvailable(false),
mInitialized(false) {
// Get the filter frame.
- mFilterFrame = GetFilterFrame();
+ mFilterFrame = GetFilterFrame(aTargetFrame);
if (!mFilterFrame) {
return;
}
// Get the filter element.
mFilterElement = mFilterFrame->GetFilterContent();
if (!mFilterElement) {
NS_NOTREACHED("filter frame should have a related element");
@@ -108,32 +109,37 @@ nsSVGFilterInstance::ComputeBounds()
}
mUserSpaceBounds = FilterSpaceToUserSpace(filterSpaceBounds);
return NS_OK;
}
nsSVGFilterFrame*
-nsSVGFilterInstance::GetFilterFrame()
+nsSVGFilterInstance::GetFilterFrame(nsIFrame* aTargetFrame)
{
if (mFilter.GetType() != NS_STYLE_FILTER_URL) {
// The filter is not an SVG reference filter.
return nullptr;
}
- nsIURI* url = mFilter.GetURL();
- if (!url) {
- NS_NOTREACHED("an nsStyleFilter of type URL should have a non-null URL");
+ // Get the target element to use as a point of reference for looking up the
+ // filter element.
+ if (!mTargetContent) {
return nullptr;
}
- // Get the target element to use as a point of reference for looking up the
- // filter element.
- if (!mTargetContent) {
+ // aTargetFrame can be null if this filter belongs to a
+ // CanvasRenderingContext2D.
+ nsCOMPtr<nsIURI> url = aTargetFrame
+ ? nsSVGEffects::GetFilterURI(aTargetFrame, mFilter)
+ : mFilter.GetURL()->Resolve(mTargetContent);
+
+ if (!url) {
+ NS_NOTREACHED("an nsStyleFilter of type URL should have a non-null URL");
return nullptr;
}
// Look up the filter element by URL.
nsReferencedElement filterElement;
bool watch = false;
filterElement.Reset(mTargetContent, url, watch);
Element* element = filterElement.get();
--- a/layout/svg/nsSVGFilterInstance.h
+++ b/layout/svg/nsSVGFilterInstance.h
@@ -76,16 +76,17 @@ public:
* @param aFilter The SVG filter reference from the style system. This class
* stores aFilter by reference, so callers should avoid modifying or
* deleting aFilter during the lifetime of nsSVGFilterInstance.
* @param aTargetContent The filtered element.
* @param aTargetBBox The SVG bbox to use for the target frame, computed by
* the caller. The caller may decide to override the actual SVG bbox.
*/
nsSVGFilterInstance(const nsStyleFilter& aFilter,
+ nsIFrame* aTargetFrame,
nsIContent* aTargetContent,
const UserSpaceMetrics& aMetrics,
const gfxRect& aTargetBBox,
const gfxSize& aUserSpaceToFilterSpaceScale,
const gfxSize& aFilterSpaceToUserSpaceScale);
/**
* Returns true if the filter instance was created successfully.
@@ -135,17 +136,17 @@ public:
* Transform a rect between user space and filter space.
*/
gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpaceRect) const;
private:
/**
* Finds the filter frame associated with this SVG filter.
*/
- nsSVGFilterFrame* GetFilterFrame();
+ nsSVGFilterFrame* GetFilterFrame(nsIFrame* aTargetFrame);
/**
* Computes the filter primitive subregion for the given primitive.
*/
IntRect ComputeFilterPrimitiveSubregion(nsSVGFE* aFilterElement,
const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
const nsTArray<int32_t>& aInputIndices);