Bug 1354772 - Part 2. Compute URLValueData::mMightHaveRef when need. draft
authorcku <cku@mozilla.com>
Mon, 10 Apr 2017 16:41:51 +0800
changeset 560486 6bb071f15a708d3063438e4426a7f2badc6d4165
parent 560485 f4560cf43290bbb598f48a02efd970a9f8ba31cc
child 560487 25128973bb0b53a0ac468ce8f15c5961afd47a03
push id53430
push userbmo:cku@mozilla.com
push dateTue, 11 Apr 2017 13:47:32 +0000
bugs1354772
milestone55.0a1
Bug 1354772 - Part 2. Compute URLValueData::mMightHaveRef when need. MozReview-Commit-ID: 8t5tKrjB1cz
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
layout/style/nsStyleStruct.cpp
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -40,16 +40,29 @@ IsLocalRefURL(nsStringBuffer* aString)
       // local-ref URL.
       return *current == '#';
     }
   }
 
   return false;
 }
 
+static bool
+MightHaveRef(nsStringBuffer* aString)
+{
+  char16_t* current = static_cast<char16_t*>(aString->Data());
+  for (; *current != '\0'; current++) {
+    if (*current == '#') {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 nsCSSValue::nsCSSValue(int32_t aValue, nsCSSUnit aUnit)
   : mUnit(aUnit)
 {
   MOZ_ASSERT(aUnit == eCSSUnit_Integer || aUnit == eCSSUnit_Enumerated ||
              aUnit == eCSSUnit_EnumColor,
              "not an int value");
   if (aUnit == eCSSUnit_Integer || aUnit == eCSSUnit_Enumerated ||
       aUnit == eCSSUnit_EnumColor) {
@@ -2890,16 +2903,28 @@ css::URLValueData::HasRef() const
   nsresult rv = uri->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
     return true;
   }
 
   return false;
 }
 
+bool
+css::URLValueData::MightHaveRef() const
+{
+  if (mMightHaveRef.isNothing()) {
+    // ::MightHaveRef is O(N), use it only use it only when MightHaveRef is
+    // called.
+    mMightHaveRef.emplace(::MightHaveRef(mString));
+  }
+
+  return mMightHaveRef.value();
+}
+
 already_AddRefed<nsIURI>
 css::URLValueData::ResolveLocalRef(nsIURI* aURI) const
 {
   nsCOMPtr<nsIURI> result = GetURI();
 
   if (result && IsLocalRef()) {
     nsCString ref;
     mURI->GetRef(ref);
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -130,16 +130,24 @@ public:
   bool DefinitelyEqualURIsAndPrincipal(const URLValueData& aOther) const;
 
   nsIURI* GetURI() const;
 
   bool IsLocalRef() const;
 
   bool HasRef() const;
 
+  // This function takes a guess whether the URL has a fragment, by searching
+  // for a hash character. It definitely returns false if we know it can't
+  // have a fragment because it has no hash character.
+  //
+  // MightHaveRef can be used in any thread, whereas HasRef can only be used
+  // in the main thread.
+  bool MightHaveRef() const;
+
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLValueData)
 
   // When matching a url with mIsLocalRef set, resolve it against aURI;
   // Otherwise, ignore aURL and return mURL directly.
   already_AddRefed<nsIURI> ResolveLocalRef(nsIURI* aURI) const;
   already_AddRefed<nsIURI> ResolveLocalRef(nsIContent* aContent) const;
 
   // Serializes mURI as a computed URI value, taking into account mIsLocalRef
@@ -154,16 +162,17 @@ private:
   mutable PtrHandle<nsIURI> mURI;
 public:
   RefPtr<nsStringBuffer> mString;
   RefPtr<URLExtraData> mExtraData;
 private:
   mutable bool mURIResolved;
   // mIsLocalRef is set when url starts with a U+0023 number sign(#) character.
   mutable Maybe<bool> mIsLocalRef;
+  mutable Maybe<bool> mMightHaveRef;
 
 protected:
   virtual ~URLValueData() = default;
 
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
 private:
   URLValueData(const URLValueData& aOther) = delete;
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3023,21 +3023,21 @@ nsStyleImageLayers::Layer::CalcDifferenc
     //   mask:url(#localMaskID); // The fragment of this URI is an ID of a mask
     //                           // element in local document.
     //   mask:url(b.svg#viewBoxID); // The fragment of this URI is an ID of a
     //                              // viewbox defined in b.svg.
     // That is, if mSourceURI has a fragment, it may link to a SVG mask; If
     // not, it "must" not link to a SVG mask.
     bool maybeSVGMask = false;
     if (mImage.GetURLValue()) {
-      maybeSVGMask = mImage.GetURLValue()->HasRef();
+      maybeSVGMask = mImage.GetURLValue()->MightHaveRef();
     }
 
     if (!maybeSVGMask && aNewLayer.mImage.GetURLValue()) {
-      maybeSVGMask = aNewLayer.mImage.GetURLValue()->HasRef();
+      maybeSVGMask = aNewLayer.mImage.GetURLValue()->MightHaveRef();
     }
 
     // Return nsChangeHint_UpdateOverflow if either URI might link to an SVG
     // mask.
     if (maybeSVGMask) {
       // Mask changes require that we update the PreEffectsBBoxProperty,
       // which is done during overflow computation.
       hint |= nsChangeHint_UpdateOverflow;