Merge latest Skia into master (4 commits)

https://skia.googlesource.com/skia.git/+log/874a872..412a86d

Test: Presubmit checks will test this change.
Change-Id: I8a82eb327a948588261baae8f404fbb97b06df7b
diff --git a/src/core/SkAnalyticEdge.h b/src/core/SkAnalyticEdge.h
index e2a9867..c5f0a02 100644
--- a/src/core/SkAnalyticEdge.h
+++ b/src/core/SkAnalyticEdge.h
@@ -147,11 +147,6 @@
     SkFixed x1 = SkFDot6ToFixed(SkScalarToFDot6(p1.fX * multiplier)) >> accuracy;
     SkFixed y1 = SnapY(SkFDot6ToFixed(SkScalarToFDot6(p1.fY * multiplier)) >> accuracy);
 
-    // are we a zero-height line?
-    if (y0 == y1) {
-        return false;
-    }
-
     int winding = 1;
 
     if (y0 > y1) {
@@ -160,12 +155,19 @@
         winding = -1;
     }
 
+    // are we a zero-height line?
 #ifdef SK_SUPPORT_LEGACY_AAA
+    if (y0 == y1) {
+        return false;
+    }
     SkFixed slope = SkFixedDiv(x1 - x0, y1 - y0);
 #else
     SkFDot6 dy = SkFixedToFDot6(y1 - y0);
+    if (dy == 0) {
+        return false;
+    }
     SkFDot6 dx = SkFixedToFDot6(x1 - x0);
-    SkFixed slope = dy ? QuickSkFDot6Div(dx, dy) : SK_MaxS32;
+    SkFixed slope = QuickSkFDot6Div(dx, dy);
     SkFixed absSlope = SkAbs32(slope);
 #endif
 
diff --git a/src/core/SkArenaAlloc.cpp b/src/core/SkArenaAlloc.cpp
index d6c249b..03ab9fa 100644
--- a/src/core/SkArenaAlloc.cpp
+++ b/src/core/SkArenaAlloc.cpp
@@ -12,15 +12,21 @@
     char* operator()(char* objEnd, ptrdiff_t size) { return objEnd + size; }
 };
 
-struct NextBlock {
-    char* operator()(char* objEnd, ptrdiff_t size) { delete [] objEnd; return objEnd + size; }
+struct SkArenaAlloc::NextBlock {
+    char* operator()(char* objEnd, ptrdiff_t size) {
+        ResetBlock(objEnd + size);
+        delete [] objEnd;
+        return nullptr;
+    }
 };
 
 SkArenaAlloc::SkArenaAlloc(char* block, size_t size, size_t extraSize)
-    : fDtorCursor{block}
-    , fCursor    {block}
-    , fEnd       {block + size}
-    , fExtraSize {extraSize}
+    : fDtorCursor {block}
+    , fCursor     {block}
+    , fEnd        {block + size}
+    , fFirstBlock {block}
+    , fFirstSize  {size}
+    , fExtraSize  {extraSize}
 {
     if (size < sizeof(Footer)) {
         fEnd = fCursor = fDtorCursor = nullptr;
@@ -32,16 +38,12 @@
 }
 
 SkArenaAlloc::~SkArenaAlloc() {
-    this->reset();
+    ResetBlock(fDtorCursor);
 }
 
 void SkArenaAlloc::reset() {
-    Footer f;
-    memmove(&f, fDtorCursor - sizeof(Footer), sizeof(Footer));
-    char* releaser = fDtorCursor;
-    while (releaser != nullptr) {
-        releaser = this->callFooterAction(releaser);
-    }
+    this->~SkArenaAlloc();
+    new (this) SkArenaAlloc{fFirstBlock, fFirstSize, fExtraSize};
 }
 
 void SkArenaAlloc::installFooter(FooterAction* releaser, ptrdiff_t padding) {
@@ -54,8 +56,6 @@
 
     Footer footer = (Footer)(footerData);
     memmove(fCursor, &footer, sizeof(Footer));
-    Footer check;
-    memmove(&check, fCursor, sizeof(Footer));
     fCursor += sizeof(Footer);
     fDtorCursor = fCursor;
 }
@@ -104,7 +104,7 @@
 char* SkArenaAlloc::allocObjectWithFooter(size_t sizeIncludingFooter, size_t alignment) {
     size_t mask = alignment - 1;
 
-    restart:
+restart:
     size_t skipOverhead = 0;
     bool needsSkipFooter = fCursor != fDtorCursor;
     if (needsSkipFooter) {
@@ -132,14 +132,20 @@
     return objStart;
 }
 
-char* SkArenaAlloc::callFooterAction(char* end) {
-    Footer footer;
-    memcpy(&footer, end - sizeof(Footer), sizeof(Footer));
+void SkArenaAlloc::ResetBlock(char* footerEnd) {
+    while (footerEnd != nullptr) {
+        footerEnd = CallFooterAction(footerEnd);
+    }
+}
 
-    FooterAction* releaser = (FooterAction*)((char*)EndChain + (footer >> 5));
+char* SkArenaAlloc::CallFooterAction(char* footerEnd) {
+    Footer footer;
+    memcpy(&footer, footerEnd - sizeof(Footer), sizeof(Footer));
+
+    FooterAction* action = (FooterAction*)((char*)EndChain + (footer >> 5));
     ptrdiff_t padding = footer & 31;
 
-    char* r = releaser(end) - padding;
+    char* r = action(footerEnd) - padding;
 
     return r;
 }
diff --git a/src/core/SkArenaAlloc.h b/src/core/SkArenaAlloc.h
index 8152c94..56006c3 100644
--- a/src/core/SkArenaAlloc.h
+++ b/src/core/SkArenaAlloc.h
@@ -56,7 +56,7 @@
     SkArenaAlloc(char* block, size_t size, size_t extraSize = 0);
 
     template <size_t kSize>
-    SkArenaAlloc(char (&block)[kSize], size_t extraSize = 0)
+    SkArenaAlloc(char (&block)[kSize], size_t extraSize = kSize)
         : SkArenaAlloc(block, kSize, extraSize)
     {}
 
@@ -116,6 +116,8 @@
     using Footer = int32_t;
     using FooterAction = char* (char*);
 
+    struct NextBlock;
+
     void installFooter(FooterAction* releaser, ptrdiff_t padding);
 
     // N.B. Action is different than FooterAction. FooterAction expects the end of the Footer,
@@ -179,7 +181,9 @@
         return objStart;
     }
 
-    char* callFooterAction(char* end);
+    static char* CallFooterAction(char* end);
+
+    static void ResetBlock(char* footerEnd);
 
     static char* EndChain(char*);
 
@@ -195,10 +199,12 @@
         }
     };
 
-    char*  fDtorCursor;
-    char*  fCursor;
-    char*  fEnd;
-    size_t fExtraSize;
+    char*        fDtorCursor;
+    char*        fCursor;
+    char*        fEnd;
+    char* const  fFirstBlock;
+    const size_t fFirstSize;
+    const size_t fExtraSize;
 };
 
 #endif//SkFixedAlloc_DEFINED
diff --git a/src/core/SkImageInfoPriv.h b/src/core/SkImageInfoPriv.h
index 2b09a4e..72138ae 100644
--- a/src/core/SkImageInfoPriv.h
+++ b/src/core/SkImageInfoPriv.h
@@ -51,8 +51,6 @@
  *      should we use kPremul or kUnpremul color values with the opaque alphas?  Or should
  *      we just use whatever the |src| alpha is?  In the future, we could choose to clearly
  *      define this, but currently no one is asking for this feature.
- *      We will not convert to a particular color space if |src| is nullptr.  The color space
- *      conversion is not well-defined.
  */
 static inline bool SkImageInfoValidConversion(const SkImageInfo& dst, const SkImageInfo& src) {
     if (!SkImageInfoIsValid(dst) || !SkImageInfoIsValid(src)) {
@@ -75,9 +73,5 @@
         return false;
     }
 
-    if (dst.colorSpace() && !src.colorSpace()) {
-        return false;
-    }
-
     return true;
 }
diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp
index 6d28f4b..9f81eac 100644
--- a/src/core/SkScan_Path.cpp
+++ b/src/core/SkScan_Path.cpp
@@ -608,6 +608,19 @@
     return (int)ceil(xx);
 }
 
+#ifdef SK_RASTERIZE_EVEN_ROUNDING
+/**
+  * Variant of SkDScalarRoundToInt that biases the input up by a half an FDot6 unit to account
+  * for potential FDot6 rounding in downstream FDot6 calculations.
+  */
+static inline int round_biased_to_int(SkScalar x) {
+    const double bias = 0.5 / SK_FDot6One;
+    double xx = x;
+    xx += 0.5 + bias;
+    return (int)floor(xx);
+}
+#endif
+
 /**
   *  Variant of SkRect::round() that explicitly performs the rounding step (i.e. floor(x + 0.5))
   *  using double instead of SkScalar (float). It does this by calling SkDScalarRoundToInt(),
@@ -625,11 +638,28 @@
   *      SkASSERT(0 == iright);  // <--- fails
   *      iright = SkDScalarRoundToInt(right);
   *      SkASSERT(0 == iright);  // <--- succeeds
+  *
+  *
+  *  If using SK_RASTERIZE_EVEN_ROUNDING, we need to ensure that bottom and right account for
+  *  edges bounded by this rect being rounded to FDot6 format before being later rounded to an
+  *  integer. For example, a value like 0.499 can be below 0.5, but round to 0.5 as FDot6, which
+  *  would finally round to the integer 1, instead of just rounding to 0.
+  *
+  *  To handle this, a small bias of half an FDot6 increment is added before actually rounding to
+  *  an integer value. This simulates the rounding of SkScalarRoundToFDot6 without incurring the
+  *  range loss of converting to FDot6 format first, preserving the integer range for the SkIRect.
+  *  Thus, bottom and right are rounded in this manner (biased up), ensuring the rect is large
+  *  enough. Top and left can round as normal since they will round (biased down) to values less
+  *  or equal to the desired rect origin.
   */
 static void round_asymmetric_to_int(const SkRect& src, SkIRect* dst) {
     SkASSERT(dst);
     dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop),
+#ifdef SK_RASTERIZE_EVEN_ROUNDING
+             round_biased_to_int(src.fRight), round_biased_to_int(src.fBottom));
+#else
              SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom));
+#endif
 }
 
 void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
diff --git a/tests/ArenaAllocTest.cpp b/tests/ArenaAllocTest.cpp
index 647ea25..0836b0c 100644
--- a/tests/ArenaAllocTest.cpp
+++ b/tests/ArenaAllocTest.cpp
@@ -26,6 +26,26 @@
         uint32_t array[128];
     };
 
+    struct Node {
+        Node(Node* n) : next(n) { created++; }
+        ~Node() {
+            destroyed++;
+            if (next) {
+                next->~Node();
+            }
+        }
+        Node *next;
+    };
+
+    struct Start {
+        ~Start() {
+            if (start) {
+                start->~Node();
+            }
+        }
+        Node* start;
+    };
+
 }
 
 struct WithDtor {
@@ -63,7 +83,7 @@
     {
         created = 0;
         destroyed = 0;
-        char block[1024];
+        char block[64];
         SkArenaAlloc arena{block};
 
         REPORTER_ASSERT(r, *arena.make<int>(3) == 3);
@@ -113,4 +133,30 @@
     }
     REPORTER_ASSERT(r, created == 11);
     REPORTER_ASSERT(r, destroyed == 11);
+
+    {
+        char storage[64];
+        SkArenaAlloc arena{storage};
+        arena.makeArrayDefault<char>(256);
+        arena.reset();
+        arena.reset();
+    }
+
+    {
+        created = 0;
+        destroyed = 0;
+        char storage[64];
+        SkArenaAlloc arena{storage};
+
+        Start start;
+        Node* current = nullptr;
+        for (int i = 0; i < 128; i++) {
+            uint64_t* temp = arena.makeArrayDefault<uint64_t>(sizeof(Node) / sizeof(Node*));
+            current = new (temp)Node(current);
+        }
+        start.start = current;
+    }
+
+    REPORTER_ASSERT(r, created == 128);
+    REPORTER_ASSERT(r, destroyed == 128);
 }
diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp
index 904ca20..4f9d944 100644
--- a/tests/ImageTest.cpp
+++ b/tests/ImageTest.cpp
@@ -34,14 +34,6 @@
 
 using namespace sk_gpu_test;
 
-SkImageInfo read_pixels_info(SkImage* image) {
-    if (as_IB(image)->onImageInfo().colorSpace()) {
-        return SkImageInfo::MakeS32(image->width(), image->height(), image->alphaType());
-    }
-
-    return SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType());
-}
-
 static void assert_equal(skiatest::Reporter* reporter, SkImage* a, const SkIRect* subsetA,
                          SkImage* b) {
     const int widthA = subsetA ? subsetA->width() : a->width();
@@ -53,9 +45,11 @@
     // see https://bug.skia.org/3965
     //REPORTER_ASSERT(reporter, a->isOpaque() == b->isOpaque());
 
+    // The codecs may have given us back F16, we can't read from F16 raster to N32, only S32.
+    SkImageInfo info = SkImageInfo::MakeS32(widthA, heightA, a->alphaType());
     SkAutoPixmapStorage pmapA, pmapB;
-    pmapA.alloc(read_pixels_info(a));
-    pmapB.alloc(read_pixels_info(b));
+    pmapA.alloc(info);
+    pmapB.alloc(info);
 
     const int srcX = subsetA ? subsetA->x() : 0;
     const int srcY = subsetA ? subsetA->y() : 0;
@@ -63,7 +57,7 @@
     REPORTER_ASSERT(reporter, a->readPixels(pmapA, srcX, srcY));
     REPORTER_ASSERT(reporter, b->readPixels(pmapB, 0, 0));
 
-    const size_t widthBytes = widthA * 4;
+    const size_t widthBytes = widthA * info.bytesPerPixel();
     for (int y = 0; y < heightA; ++y) {
         REPORTER_ASSERT(reporter, !memcmp(pmapA.addr32(0, y), pmapB.addr32(0, y), widthBytes));
     }