Bug 1457110: Restore behavior of maintaining width/height when one of the two is exactly zero. r=jrmuizel, a=RyanVM
authorBas Schouten <bschouten@mozilla.com>
Fri, 25 May 2018 18:16:52 +0200
changeset 473576 26ad4f0fc4f3332b17250e9a44c3ba0cae10c508
parent 473575 d188896a583d22cda4176c132fdbe96c52310996
child 473577 6fafce03df13c69f759abf2931f92e79c4e87b07
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel, RyanVM
bugs1457110
milestone61.0
Bug 1457110: Restore behavior of maintaining width/height when one of the two is exactly zero. r=jrmuizel, a=RyanVM MozReview-Commit-ID: 5OpjfTnJQxe
gfx/2d/BaseRect.h
gfx/src/nsRect.h
--- a/gfx/2d/BaseRect.h
+++ b/gfx/2d/BaseRect.h
@@ -119,31 +119,42 @@ struct BaseRect {
   // of *this and aRect.
   MOZ_MUST_USE Sub Intersect(const Sub& aRect) const
   {
     Sub result;
     result.x = std::max<T>(x, aRect.x);
     result.y = std::max<T>(y, aRect.y);
     result.width = std::min<T>(x - result.x + width, aRect.x - result.x + aRect.width);
     result.height = std::min<T>(y - result.y + height, aRect.y - result.y + aRect.height);
-    if (result.width <= 0 || result.height <= 0) {
+    // See bug 1457110, this function expects to -only- size to 0,0 if the width/height
+    // is explicitly negative.
+    if (result.width < 0 || result.height < 0) {
       result.SizeTo(0, 0);
     }
     return result;
   }
   // Sets *this to be the rectangle containing the intersection of the points
   // (including edges) of *this and aRect. If there are no points in that
   // intersection, sets *this to be an empty rectangle with x/y set to the std::max
   // of the x/y of *this and aRect.
   //
   // 'this' can be the same object as either aRect1 or aRect2
   bool IntersectRect(const Sub& aRect1, const Sub& aRect2)
   {
-    *static_cast<Sub*>(this) = aRect1.Intersect(aRect2);
-    return !IsEmpty();
+    T newX = std::max<T>(aRect1.x, aRect2.x);
+    T newY = std::max<T>(aRect1.y, aRect2.y);
+    width = std::min<T>(aRect1.x - newX + aRect1.width, aRect2.x - newX + aRect2.width);
+    height = std::min<T>(aRect1.y - newY + aRect1.height, aRect2.y - newY + aRect2.height);
+    x = newX;
+    y = newY;
+    if (width <= 0 || height <= 0) {
+      SizeTo(0, 0);
+      return false;
+    }
+    return true;
   }
 
   // Returns the smallest rectangle that contains both the area of both
   // this and aRect2.
   // Thus, empty input rectangles are ignored.
   // If both rectangles are empty, returns this.
   // WARNING! This is not safe against overflow, prefer using SafeUnion instead
   // when dealing with int-based rects.
--- a/gfx/src/nsRect.h
+++ b/gfx/src/nsRect.h
@@ -145,32 +145,32 @@ struct nsRect :
       // result.width = std::min<int32_t>(x - result.x + width, aRect.x - result.x + aRect.width);
       // result.height = std::min<int32_t>(y - result.y + height, aRect.y - result.y + aRect.height);
       __m128i widthheight = _mm_min_epi32(_mm_add_epi32(_mm_sub_epi32(rect1, resultRect), _mm_srli_si128(rect1, 8)),
                                           _mm_add_epi32(_mm_sub_epi32(rect2, resultRect), _mm_srli_si128(rect2, 8))); // w, h, zz, zz
       widthheight = _mm_slli_si128(widthheight, 8); // 00, 00, wr, hr
 
       resultRect = _mm_blend_epi16(resultRect, widthheight, 0xF0); // xr, yr, wr, hr
 
-      if ((_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpgt_epi32(resultRect, _mm_setzero_si128()))) & 0xC) != 0xC) {
+      if ((_mm_movemask_ps(_mm_castsi128_ps(_mm_cmplt_epi32(resultRect, _mm_setzero_si128()))) & 0xC) != 0) {
         // It's potentially more efficient to store all 0s. But the non SSE4 code leaves x/y intact
         // so let's do the same here.
         resultRect = _mm_and_si128(resultRect, _mm_set_epi32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF));
       }
 
       _mm_storeu_si128((__m128i*)&result, resultRect);
 
       return result;
     }
 
     result.x = std::max<int32_t>(x, aRect.x);
     result.y = std::max<int32_t>(y, aRect.y);
     result.width = std::min<int32_t>(x - result.x + width, aRect.x - result.x + aRect.width);
     result.height = std::min<int32_t>(y - result.y + height, aRect.y - result.y + aRect.height);
-    if (result.width <= 0 || result.height <= 0) {
+    if (result.width < 0 || result.height < 0) {
       result.SizeTo(0, 0);
     }
     return result;
   }
 
   bool IntersectRect(const nsRect& aRect1, const nsRect& aRect2)
   {
     if (mozilla::gfx::Factory::HasSSE4()) {
@@ -193,18 +193,28 @@ struct nsRect :
         _mm_storeu_si128((__m128i*)this, resultRect);
         return false;
       }
 
       _mm_storeu_si128((__m128i*)this, resultRect);
 
       return true;
     }
-    *static_cast<nsRect*>(this) = aRect1.Intersect(aRect2);
-    return !IsEmpty();
+
+    int32_t newX = std::max<int32_t>(aRect1.x, aRect2.x);
+    int32_t newY = std::max<int32_t>(aRect1.y, aRect2.y);
+    width = std::min<int32_t>(aRect1.x - newX + aRect1.width, aRect2.x - newX + aRect2.width);
+    height = std::min<int32_t>(aRect1.y - newY + aRect1.height, aRect2.y - newY + aRect2.height);
+    x = newX;
+    y = newY;
+    if (width <= 0 || height <= 0) {
+      SizeTo(0, 0);
+      return false;
+    }
+    return true;
   }
 #endif
 #endif
 
   void SaturatingUnionRect(const nsRect& aRect1, const nsRect& aRect2)
   {
     *this = aRect1.SaturatingUnion(aRect2);
   }