Bug 1305376 - Use nsTArray for cursor image list storage. r=xidorn
authorCameron McCormack <cam@mcc.id.au>
Thu, 29 Sep 2016 10:55:55 +0800
changeset 315748 e4e13b10667c36eeb0d24ad09f37851504977208
parent 315747 f6c5daab390c0772cd67dc624359e50ba539c6b4
child 315749 9ec418dcac3f0611f612bdad7d2fc0f0b23de043
push id20634
push usercbook@mozilla.com
push dateFri, 30 Sep 2016 10:10:13 +0000
treeherderfx-team@afe79b010d13 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersxidorn
bugs1305376
milestone52.0a1
Bug 1305376 - Use nsTArray for cursor image list storage. r=xidorn MozReview-Commit-ID: 2uRGInQmNYU
layout/generic/nsFrame.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -8675,32 +8675,30 @@ nsIFrame::VerticalAlignEnum() const
 void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
                                              nsIFrame::Cursor& aCursor)
 {
   aCursor.mCursor = ui->mCursor;
   aCursor.mHaveHotspot = false;
   aCursor.mLoading = false;
   aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
 
-  for (nsCursorImage *item = ui->mCursorArray,
-                 *item_end = ui->mCursorArray + ui->mCursorArrayLength;
-       item < item_end; ++item) {
+  for (const nsCursorImage& item : ui->mCursorImages) {
     uint32_t status;
-    nsresult rv = item->GetImage()->GetImageStatus(&status);
+    nsresult rv = item.GetImage()->GetImageStatus(&status);
     if (NS_SUCCEEDED(rv)) {
       if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
         // If we are falling back because any cursor before is loading,
         // let the consumer know.
         aCursor.mLoading = true;
       } else if (!(status & imgIRequest::STATUS_ERROR)) {
         // This is the one we want
-        item->GetImage()->GetImage(getter_AddRefs(aCursor.mContainer));
-        aCursor.mHaveHotspot = item->mHaveHotspot;
-        aCursor.mHotspotX = item->mHotspotX;
-        aCursor.mHotspotY = item->mHotspotY;
+        item.GetImage()->GetImage(getter_AddRefs(aCursor.mContainer));
+        aCursor.mHaveHotspot = item.mHaveHotspot;
+        aCursor.mHotspotX = item.mHotspotX;
+        aCursor.mHotspotY = item.mHotspotY;
         break;
       }
     }
   }
 }
 
 NS_IMETHODIMP
 nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -4154,34 +4154,32 @@ nsComputedDOMStyle::DoGetUnicodeBidi()
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetCursor()
 {
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   const nsStyleUserInterface *ui = StyleUserInterface();
 
-  for (nsCursorImage *item = ui->mCursorArray,
-         *item_end = ui->mCursorArray + ui->mCursorArrayLength;
-       item < item_end; ++item) {
+  for (const nsCursorImage& item : ui->mCursorImages) {
     RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
 
     nsCOMPtr<nsIURI> uri;
-    item->GetImage()->GetURI(getter_AddRefs(uri));
+    item.GetImage()->GetURI(getter_AddRefs(uri));
 
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetURI(uri);
     itemList->AppendCSSValue(val.forget());
 
-    if (item->mHaveHotspot) {
+    if (item.mHaveHotspot) {
       RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
       RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
 
-      valX->SetNumber(item->mHotspotX);
-      valY->SetNumber(item->mHotspotY);
+      valX->SetNumber(item.mHotspotX);
+      valY->SetNumber(item.mHotspotY);
 
       itemList->AppendCSSValue(valX.forget());
       itemList->AppendCSSValue(valY.forget());
     }
     valueList->AppendCSSValue(itemList.forget());
   }
 
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -104,29 +104,36 @@ nsConditionalResetStyleData::GetConditio
 
       return data;
     }
     e = e->mNext;
   } while (e);
   return nullptr;
 }
 
+// Creates and returns an imgRequestProxy based on the specified
+// value in aValue.
+static imgRequestProxy*
+GetImageRequest(nsPresContext* aPresContext, const nsCSSValue& aValue)
+{
+  return aValue.GetImageValue(aPresContext->Document());
+}
+
 // Creates an imgRequestProxy based on the specified value in
 // aValue and calls aCallback with it.  If the nsPresContext
 // is static (e.g. for printing), then a static request (i.e.
 // showing the first frame, without animation) will be created.
 // (The expectation is then that aCallback will set the resulting
 // imgRequestProxy in a style struct somewhere.)
 static void
 SetImageRequest(function<void(imgRequestProxy*)> aCallback,
                 nsPresContext* aPresContext,
                 const nsCSSValue& aValue)
 {
-  nsIDocument* doc = aPresContext->Document();
-  imgRequestProxy* req = aValue.GetImageValue(doc);
+  imgRequestProxy* req = GetImageRequest(aPresContext, aValue);
   if (aPresContext->IsDynamic()) {
     aCallback(req);
   } else {
     RefPtr<imgRequestProxy> staticReq = nsContentUtils::GetStaticRequest(req);
     aCallback(staticReq);
   }
 }
 
@@ -5068,61 +5075,44 @@ nsRuleNode::ComputeUserInterfaceData(voi
                                      const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(UserInterface, ui, parentUI)
 
   // cursor: enum, url, inherit
   const nsCSSValue* cursorValue = aRuleData->ValueForCursor();
   nsCSSUnit cursorUnit = cursorValue->GetUnit();
   if (cursorUnit != eCSSUnit_Null) {
-    delete [] ui->mCursorArray;
-    ui->mCursorArray = nullptr;
-    ui->mCursorArrayLength = 0;
+    ui->mCursorImages.Clear();
 
     if (cursorUnit == eCSSUnit_Inherit ||
         cursorUnit == eCSSUnit_Unset) {
       conditions.SetUncacheable();
       ui->mCursor = parentUI->mCursor;
-      ui->CopyCursorArrayFrom(*parentUI);
+      ui->mCursorImages = parentUI->mCursorImages;
     }
     else if (cursorUnit == eCSSUnit_Initial) {
       ui->mCursor = NS_STYLE_CURSOR_AUTO;
     }
     else {
       // The parser will never create a list that is *all* URL values --
       // that's invalid.
       MOZ_ASSERT(cursorUnit == eCSSUnit_List || cursorUnit == eCSSUnit_ListDep,
                  "unrecognized cursor unit");
       const nsCSSValueList* list = cursorValue->GetListValue();
-      const nsCSSValueList* list2 = list;
-      nsIDocument* doc = aContext->PresContext()->Document();
-      uint32_t arrayLength = 0;
-      for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext)
-        if (list->mValue.GetArrayValue()->Item(0).GetImageValue(doc))
-          ++arrayLength;
-
-      if (arrayLength != 0) {
-        ui->mCursorArray = new nsCursorImage[arrayLength];
-        if (ui->mCursorArray) {
-          ui->mCursorArrayLength = arrayLength;
-
-          for (nsCursorImage *item = ui->mCursorArray;
-               list2->mValue.GetUnit() == eCSSUnit_Array;
-               list2 = list2->mNext) {
-            nsCSSValue::Array *arr = list2->mValue.GetArrayValue();
-            imgIRequest *req = arr->Item(0).GetImageValue(doc);
-            if (req) {
-              item->SetImage(req);
-              if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
-                item->mHaveHotspot = true;
-                item->mHotspotX = arr->Item(1).GetFloatValue(),
-                item->mHotspotY = arr->Item(2).GetFloatValue();
-              }
-              ++item;
-            }
+      for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext) {
+        nsCSSValue::Array* arr = list->mValue.GetArrayValue();
+        imgRequestProxy* req =
+          GetImageRequest(aContext->PresContext(), arr->Item(0));
+        if (req) {
+          nsCursorImage* item = ui->mCursorImages.AppendElement();
+          item->SetImage(req);
+          if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
+            item->mHaveHotspot = true;
+            item->mHotspotX = arr->Item(1).GetFloatValue();
+            item->mHotspotY = arr->Item(2).GetFloatValue();
           }
         }
       }
 
       NS_ASSERTION(list, "Must have non-array value at the end");
       NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated,
                    "Unexpected fallback value at end of cursor list");
       ui->mCursor = list->mValue.GetIntValue();
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3890,56 +3890,68 @@ nsCursorImage::operator=(const nsCursorI
     mHotspotX = aOther.mHotspotX;
     mHotspotY = aOther.mHotspotY;
     SetImage(aOther.GetImage());
   }
 
   return *this;
 }
 
+bool
+nsCursorImage::operator==(const nsCursorImage& aOther) const
+{
+  NS_ASSERTION(mHaveHotspot ||
+               (mHotspotX == 0 && mHotspotY == 0),
+               "expected mHotspot{X,Y} to be 0 when mHaveHotspot is false");
+  NS_ASSERTION(aOther.mHaveHotspot ||
+               (aOther.mHotspotX == 0 && aOther.mHotspotY == 0),
+               "expected mHotspot{X,Y} to be 0 when mHaveHotspot is false");
+  return mHaveHotspot == aOther.mHaveHotspot &&
+         mHotspotX == aOther.mHotspotX &&
+         mHotspotY == aOther.mHotspotY &&
+         EqualImages(mImage, aOther.mImage);
+}
+
 nsStyleUserInterface::nsStyleUserInterface(StyleStructContext aContext)
   : mUserInput(NS_STYLE_USER_INPUT_AUTO)
   , mUserModify(NS_STYLE_USER_MODIFY_READ_ONLY)
   , mUserFocus(StyleUserFocus::None)
   , mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO)
   , mCursor(NS_STYLE_CURSOR_AUTO)
-  , mCursorArrayLength(0)
-  , mCursorArray(nullptr)
 {
   MOZ_COUNT_CTOR(nsStyleUserInterface);
 }
 
 nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource)
   : mUserInput(aSource.mUserInput)
   , mUserModify(aSource.mUserModify)
   , mUserFocus(aSource.mUserFocus)
   , mPointerEvents(aSource.mPointerEvents)
   , mCursor(aSource.mCursor)
+  , mCursorImages(aSource.mCursorImages)
 {
   MOZ_COUNT_CTOR(nsStyleUserInterface);
-  CopyCursorArrayFrom(aSource);
 }
 
 nsStyleUserInterface::~nsStyleUserInterface()
 {
   MOZ_COUNT_DTOR(nsStyleUserInterface);
-  delete [] mCursorArray;
 }
 
 nsChangeHint
 nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aNewData) const
 {
   nsChangeHint hint = nsChangeHint(0);
   if (mCursor != aNewData.mCursor) {
     hint |= nsChangeHint_UpdateCursor;
   }
 
   // We could do better. But it wouldn't be worth it, URL-specified cursors are
   // rare.
-  if (mCursorArrayLength > 0 || aNewData.mCursorArrayLength > 0) {
+  if (mCursorImages != aNewData.mCursorImages) {
     hint |= nsChangeHint_UpdateCursor;
   }
 
   if (mPointerEvents != aNewData.mPointerEvents) {
     // nsSVGPathGeometryFrame's mRect depends on stroke _and_ on the value
     // of pointer-events. See nsSVGPathGeometryFrame::ReflowSVG's use of
     // GetHitTestFlags. (Only a reflow, no visual change.)
     hint |= nsChangeHint_NeedReflow |
@@ -3961,32 +3973,16 @@ nsStyleUserInterface::CalcDifference(con
 
   if (mUserFocus != aNewData.mUserFocus) {
     hint |= nsChangeHint_NeutralChange;
   }
 
   return hint;
 }
 
-void
-nsStyleUserInterface::CopyCursorArrayFrom(const nsStyleUserInterface& aSource)
-{
-  mCursorArray = nullptr;
-  mCursorArrayLength = 0;
-  if (aSource.mCursorArrayLength) {
-    mCursorArray = new nsCursorImage[aSource.mCursorArrayLength];
-    if (mCursorArray) {
-      mCursorArrayLength = aSource.mCursorArrayLength;
-      for (uint32_t i = 0; i < mCursorArrayLength; ++i) {
-        mCursorArray[i] = aSource.mCursorArray[i];
-      }
-    }
-  }
-}
-
 //-----------------------
 // nsStyleUIReset
 //
 
 nsStyleUIReset::nsStyleUIReset(StyleStructContext aContext)
   : mUserSelect(StyleUserSelect::Auto)
   , mForceBrokenImageIcon(0)
   , mIMEMode(NS_STYLE_IME_MODE_AUTO)
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -3371,16 +3371,22 @@ struct nsCursorImage
   float mHotspotX, mHotspotY;
 
   nsCursorImage();
   nsCursorImage(const nsCursorImage& aOther);
   ~nsCursorImage();
 
   nsCursorImage& operator=(const nsCursorImage& aOther);
 
+  bool operator==(const nsCursorImage& aOther) const;
+  bool operator!=(const nsCursorImage& aOther) const
+  {
+    return !(*this == aOther);
+  }
+
   void SetImage(imgIRequest *aImage) {
     if (mImage) {
       mImage->UnlockImage();
       mImage->RequestDiscard();
     }
     mImage = aImage;
     if (mImage) {
       mImage->LockImage();
@@ -3426,27 +3432,18 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
     return nsChangeHint_NeedReflow;
   }
 
   uint8_t                   mUserInput;       // [inherited]
   uint8_t                   mUserModify;      // [inherited] (modify-content)
   mozilla::StyleUserFocus   mUserFocus;       // [inherited] (auto-select)
   uint8_t                   mPointerEvents;   // [inherited] see nsStyleConsts.h
 
-  uint8_t   mCursor;          // [inherited] See nsStyleConsts.h
-
-  uint32_t mCursorArrayLength;
-  nsCursorImage *mCursorArray;// [inherited] The specified URL values
-                              //   and coordinates.  Takes precedence over
-                              //   mCursor.  Zero-length array is represented
-                              //   by null pointer.
-
-  // Does not free mCursorArray; the caller is responsible for calling
-  // |delete [] mCursorArray| first if it is needed.
-  void CopyCursorArrayFrom(const nsStyleUserInterface& aSource);
+  uint8_t mCursor;                            // [inherited] See nsStyleConsts.h
+  nsTArray<nsCursorImage> mCursorImages;      // [inherited] images and coords
 
   inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const;
 };
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleXUL
 {
   explicit nsStyleXUL(StyleStructContext aContext);
   nsStyleXUL(const nsStyleXUL& aSource);