From 19f010c62022e269f99066a8d90e3522fe31adaf Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 4 Sep 2018 17:55:18 +0200 Subject: Part 1. Move IsLocalRefURL to nsContentUtils to reuse this function. (port-rewrite) `IsLocalRefURL` is originally designed to be used by URLValue only. Since we need this function in SVGUseElement::LookupHref too, move it to nsContentUtils as a util function. --- dom/base/nsContentUtils.cpp | 16 ++++++++++++++++ dom/base/nsContentUtils.h | 7 +++++++ layout/style/nsCSSValue.cpp | 20 ++------------------ 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 34c7d23b8..8612e76df 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -9787,3 +9787,19 @@ nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel) return reloadSucceeded; } + +/* static */ bool +nsContentUtils::IsLocalRefURL(const nsString& aString) +{ + // Find the first non-"C0 controls + space" character. + const char16_t* current = aString.get(); + for (; *current != '\0'; current++) { + if (*current > 0x20) { + // if the first non-"C0 controls + space" character is '#', this is a + // local-ref URL. + return *current == '#'; + } + } + + return false; +} \ No newline at end of file diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 9ae6d2155..c255f813a 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2730,6 +2730,13 @@ public: static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel); + /** + * Detect whether a string is a (CSS) local-url. + * https://drafts.csswg.org/css-values/#local-urls + */ + static bool + IsLocalRefURL(const nsString& aString); + private: static bool InitializeEventTable(); diff --git a/layout/style/nsCSSValue.cpp b/layout/style/nsCSSValue.cpp index baf5b7897..e9c391737 100644 --- a/layout/style/nsCSSValue.cpp +++ b/layout/style/nsCSSValue.cpp @@ -29,22 +29,6 @@ using namespace mozilla; -static bool -IsLocalRefURL(nsStringBuffer* aString) -{ - // Find the first non-"C0 controls + space" character. - char16_t* current = static_cast(aString->Data()); - for (; *current != '\0'; current++) { - if (*current > 0x20) { - // if the first non-"C0 controls + space" character is '#', this is a - // local-ref URL. - return *current == '#'; - } - } - - return false; -} - nsCSSValue::nsCSSValue(int32_t aValue, nsCSSUnit aUnit) : mUnit(aUnit) { @@ -2723,7 +2707,7 @@ css::URLValueData::URLValueData(already_AddRefed> aURI, , mReferrer(Move(aReferrer)) , mOriginPrincipal(Move(aOriginPrincipal)) , mURIResolved(true) - , mIsLocalRef(IsLocalRefURL(aString)) + , mIsLocalRef(nsContentUtils::IsLocalRefURL(aString)) { MOZ_ASSERT(mString); MOZ_ASSERT(mBaseURI); @@ -2740,7 +2724,7 @@ css::URLValueData::URLValueData(nsStringBuffer* aString, , mReferrer(Move(aReferrer)) , mOriginPrincipal(Move(aOriginPrincipal)) , mURIResolved(false) - , mIsLocalRef(IsLocalRefURL(aString)) + , mIsLocalRef(nsContentUtils::IsLocalRefURL(aString)) { MOZ_ASSERT(aString); MOZ_ASSERT(mBaseURI); -- cgit v1.2.3 From b43a1afcd369cb7a04d681c0a1bd21002a9ab724 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 4 Sep 2018 17:59:40 +0200 Subject: Revert "Part 1. Move IsLocalRefURL to nsContentUtils to reuse this function. (port-rewrite)" This reverts commit 19f010c62022e269f99066a8d90e3522fe31adaf. --- dom/base/nsContentUtils.cpp | 16 ---------------- dom/base/nsContentUtils.h | 7 ------- layout/style/nsCSSValue.cpp | 20 ++++++++++++++++++-- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 8612e76df..34c7d23b8 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -9787,19 +9787,3 @@ nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel) return reloadSucceeded; } - -/* static */ bool -nsContentUtils::IsLocalRefURL(const nsString& aString) -{ - // Find the first non-"C0 controls + space" character. - const char16_t* current = aString.get(); - for (; *current != '\0'; current++) { - if (*current > 0x20) { - // if the first non-"C0 controls + space" character is '#', this is a - // local-ref URL. - return *current == '#'; - } - } - - return false; -} \ No newline at end of file diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index c255f813a..9ae6d2155 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2730,13 +2730,6 @@ public: static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel); - /** - * Detect whether a string is a (CSS) local-url. - * https://drafts.csswg.org/css-values/#local-urls - */ - static bool - IsLocalRefURL(const nsString& aString); - private: static bool InitializeEventTable(); diff --git a/layout/style/nsCSSValue.cpp b/layout/style/nsCSSValue.cpp index e9c391737..baf5b7897 100644 --- a/layout/style/nsCSSValue.cpp +++ b/layout/style/nsCSSValue.cpp @@ -29,6 +29,22 @@ using namespace mozilla; +static bool +IsLocalRefURL(nsStringBuffer* aString) +{ + // Find the first non-"C0 controls + space" character. + char16_t* current = static_cast(aString->Data()); + for (; *current != '\0'; current++) { + if (*current > 0x20) { + // if the first non-"C0 controls + space" character is '#', this is a + // local-ref URL. + return *current == '#'; + } + } + + return false; +} + nsCSSValue::nsCSSValue(int32_t aValue, nsCSSUnit aUnit) : mUnit(aUnit) { @@ -2707,7 +2723,7 @@ css::URLValueData::URLValueData(already_AddRefed> aURI, , mReferrer(Move(aReferrer)) , mOriginPrincipal(Move(aOriginPrincipal)) , mURIResolved(true) - , mIsLocalRef(nsContentUtils::IsLocalRefURL(aString)) + , mIsLocalRef(IsLocalRefURL(aString)) { MOZ_ASSERT(mString); MOZ_ASSERT(mBaseURI); @@ -2724,7 +2740,7 @@ css::URLValueData::URLValueData(nsStringBuffer* aString, , mReferrer(Move(aReferrer)) , mOriginPrincipal(Move(aOriginPrincipal)) , mURIResolved(false) - , mIsLocalRef(nsContentUtils::IsLocalRefURL(aString)) + , mIsLocalRef(IsLocalRefURL(aString)) { MOZ_ASSERT(aString); MOZ_ASSERT(mBaseURI); -- cgit v1.2.3 From 32464a0b974760b9231ae1f7e49f48eeddbc39b9 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 4 Sep 2018 19:36:08 +0200 Subject: Part 1. Duplicate IsLocalRefURL to nsContentUtils to reuse this function. `IsLocalRefURL` is originally designed to be used by URLValue only. Since we need this function in SVGUseElement::LookupHref too, duplicate it to nsContentUtils as a util function. This is a duplication because CSSValue uses stringbuffers and not nsStrings. While Bug 1356060 - "Just use nsString in URLValueData" converts this use from stringbuffer to nsString, it builds on a bunch of vartype refactoring (nsString vs. nsAString, etc.) which is too much of a headache to deal with just to deduplicate this simple function. --- dom/base/nsContentUtils.cpp | 16 ++++++++++++++++ dom/base/nsContentUtils.h | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 34c7d23b8..8612e76df 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -9787,3 +9787,19 @@ nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel) return reloadSucceeded; } + +/* static */ bool +nsContentUtils::IsLocalRefURL(const nsString& aString) +{ + // Find the first non-"C0 controls + space" character. + const char16_t* current = aString.get(); + for (; *current != '\0'; current++) { + if (*current > 0x20) { + // if the first non-"C0 controls + space" character is '#', this is a + // local-ref URL. + return *current == '#'; + } + } + + return false; +} \ No newline at end of file diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 9ae6d2155..c255f813a 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2730,6 +2730,13 @@ public: static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel); + /** + * Detect whether a string is a (CSS) local-url. + * https://drafts.csswg.org/css-values/#local-urls + */ + static bool + IsLocalRefURL(const nsString& aString); + private: static bool InitializeEventTable(); -- cgit v1.2.3 From d314fcbcc836ab355ce4268083d3dd8df6f33877 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 5 Sep 2018 01:44:01 +0200 Subject: Part 2. Implement nsSVGEffects::GetBaseURLForLocalRef to export local-ref-url-resolving logic. ResolveURLUsingLocalRef is designed to be internally used by nsSVGEffects::Get-{SVGEffect}-URI functions. Since we also need it in SVGUseElement::LookupHref, make it public in nsSVGEffects. --- layout/svg/nsSVGEffects.cpp | 46 +++++++++++++++++++++++++++++---------------- layout/svg/nsSVGEffects.h | 14 +++++++++++++- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/layout/svg/nsSVGEffects.cpp b/layout/svg/nsSVGEffects.cpp index eac094a91..e75c973c8 100644 --- a/layout/svg/nsSVGEffects.cpp +++ b/layout/svg/nsSVGEffects.cpp @@ -888,24 +888,13 @@ nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame* aFrame, uint32_t aFla } } -static already_AddRefed -ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL) +already_AddRefed +nsSVGEffects::GetBaseURLForLocalRef(nsIContent* content, nsIURI* aDocURI) { - MOZ_ASSERT(aFrame); - - if (!aURL) { - return nullptr; - } - - // Non-local-reference URL. - if (!aURL->IsLocalRef()) { - nsCOMPtr result = aURL->GetURI(); - return result.forget(); - } + MOZ_ASSERT(content); // For a local-reference URL, resolve that fragment against the current // document that relative URLs are resolved against. - nsIContent* content = aFrame->GetContent(); nsCOMPtr baseURI = content->OwnerDoc()->GetDocumentURI(); if (content->IsInAnonymousSubtree()) { @@ -933,12 +922,37 @@ ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL) } } - if (originalURI && aURL->EqualsExceptRef(originalURI)) { - baseURI = originalURI; + if (originalURI) { + bool isEqualsExceptRef = false; + aDocURI->EqualsExceptRef(originalURI, &isEqualsExceptRef); + if (isEqualsExceptRef) { + baseURI = originalURI; + } } } } + return baseURI.forget(); +} + +static already_AddRefed +ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL) +{ + MOZ_ASSERT(aFrame); + + if (!aURL) { + return nullptr; + } + + // Non-local-reference URL. + if (!aURL->IsLocalRef()) { + nsCOMPtr result = aURL->GetURI(); + return result.forget(); + } + + nsCOMPtr baseURI = + nsSVGEffects::GetBaseURLForLocalRef(aFrame->GetContent(), aURL->GetURI()); + return aURL->ResolveLocalRef(baseURI); } diff --git a/layout/svg/nsSVGEffects.h b/layout/svg/nsSVGEffects.h index 9dd92fd31..0cf9b1500 100644 --- a/layout/svg/nsSVGEffects.h +++ b/layout/svg/nsSVGEffects.h @@ -626,11 +626,23 @@ public: static already_AddRefed GetPaintURI(nsIFrame* aFrame, nsStyleSVGPaint nsStyleSVG::* aPaint); - /** + /** * A helper function to resolve SVG mask URL. */ static already_AddRefed GetMaskURI(nsIFrame* aFrame, uint32_t aIndex); + + /** + * Return a baseURL for resolving a local-ref URL. + * + * @param aContent an element which uses a local-ref property. Here are some + * examples: + * + * + * + */ + static already_AddRefed + GetBaseURLForLocalRef(nsIContent* aContent, nsIURI* aDocURI); }; #endif /*NSSVGEFFECTS_H_*/ -- cgit v1.2.3 From 246edb5332e3d1415a4949a76e09ff951d5e497d Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 5 Sep 2018 01:47:58 +0200 Subject: Part 3. Resolve local-ref in SVGUseElement::LookupHref by nsSVGEffects::GetBaseURLForLocalRef. --- dom/svg/SVGUseElement.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dom/svg/SVGUseElement.cpp b/dom/svg/SVGUseElement.cpp index 4911e2cac..9212ab1aa 100644 --- a/dom/svg/SVGUseElement.cpp +++ b/dom/svg/SVGUseElement.cpp @@ -15,6 +15,7 @@ #include "mozilla/dom/Element.h" #include "nsContentUtils.h" #include "nsIURI.h" +#include "nsSVGEffects.h" NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Use) @@ -418,11 +419,15 @@ SVGUseElement::LookupHref() return; } + nsCOMPtr originURI = + mOriginal ? mOriginal->GetBaseURI() : GetBaseURI(); + nsCOMPtr baseURI = nsContentUtils::IsLocalRefURL(href) + ? nsSVGEffects::GetBaseURLForLocalRef(this, originURI) + : originURI; + nsCOMPtr targetURI; - nsCOMPtr baseURI = mOriginal ? mOriginal->GetBaseURI() : GetBaseURI(); nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href, GetComposedDoc(), baseURI); - mSource.Reset(this, targetURI); } -- cgit v1.2.3 From 6a7071fdead529d92cb27954523b3bfc4b16d1c8 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Wed, 5 Sep 2018 02:00:48 +0200 Subject: Part 4. Reftest for using local-ref as xlink:href value. --- layout/reftests/svg/reftest.list | 1 + layout/reftests/svg/use-localRef-link.html | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 layout/reftests/svg/use-localRef-link.html diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index 520adc9e6..096628681 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -396,6 +396,7 @@ fuzzy-if(skiaContent,1,300) == tspan-xy-05.svg tspan-xy-ref.svg # bug 773482 fuzzy-if(skiaContent,1,300) == tspan-xy-06.svg tspan-xy-ref.svg # bug 773482 fuzzy-if(skiaContent,1,100) == tspan-xy-anchor-middle-01.svg tspan-xy-anchor-middle-ref.svg # bug 773482 fuzzy-if(skiaContent,1,100) == tspan-xy-anchor-end-01.svg tspan-xy-anchor-end-ref.svg # bug 773482 +== use-localRef-link.html pass.svg == userSpaceOnUse-and-pattern-01.svg userSpaceOnUse-and-pattern-01-ref.svg == viewBox-and-pattern-01.svg pass.svg == viewBox-and-pattern-02.svg pass.svg diff --git a/layout/reftests/svg/use-localRef-link.html b/layout/reftests/svg/use-localRef-link.html new file mode 100644 index 000000000..672e9ffaa --- /dev/null +++ b/layout/reftests/svg/use-localRef-link.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + -- cgit v1.2.3