Browse Source

chore: cherry-pick 872b8c13d7 from skia (#28739)

Pedro Pontes 4 years ago
parent
commit
0b6842d429
2 changed files with 200 additions and 0 deletions
  1. 1 0
      patches/skia/.patches
  2. 199 0
      patches/skia/skscalercontext_getimage_less_brittle.patch

+ 1 - 0
patches/skia/.patches

@@ -1,2 +1,3 @@
 cherry-pick-6763a713f957.patch
 cherry-pick-b0d3d3e85fa6.patch
+skscalercontext_getimage_less_brittle.patch

+ 199 - 0
patches/skia/skscalercontext_getimage_less_brittle.patch

@@ -0,0 +1,199 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ben Wagner <[email protected]>
+Date: Thu, 1 Apr 2021 15:02:21 -0400
+Subject: SkScalerContext::getImage less brittle.
+
+Properly handle edge cases like
+ * the temporary glyph being a different size than expected
+ * filters which reduce in size
+ * filters which return false to indicate no filtering has been done
+
+Bug: chromium:1190525
+Change-Id: Ibc53eb1d7014210019e96cd6bae3e256d967be54
+Reviewed-on: https://skia-review.googlesource.com/c/skia/+/392156
+Commit-Queue: Ben Wagner <[email protected]>
+Reviewed-by: Herb Derby <[email protected]>
+(cherry picked from commit 348ee387a96d7d94733d46ad9e82b19cb890dd16)
+Reviewed-on: https://skia-review.googlesource.com/c/skia/+/392437
+
+diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
+index a2df87c3ef62790353b8fac8169d83bc657db3d4..d1cb80a631814e995c756dc23764a21b00e97270 100644
+--- a/src/core/SkScalerContext.cpp
++++ b/src/core/SkScalerContext.cpp
+@@ -534,41 +534,39 @@ static void generateMask(const SkMask& mask, const SkPath& path,
+ }
+ 
+ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
+-    const SkGlyph*  glyph = &origGlyph;
++    const SkGlyph* unfilteredGlyph = &origGlyph;
+     SkGlyph  tmpGlyph{origGlyph.getPackedID()};
+ 
+     // in case we need to call generateImage on a mask-format that is different
+     // (i.e. larger) than what our caller allocated by looking at origGlyph.
+     SkAutoMalloc tmpGlyphImageStorage;
+ 
+-    if (fMaskFilter) {   // restore the prefilter bounds
+-
++    if (fMaskFilter) {
+         // need the original bounds, sans our maskfilter
+         sk_sp<SkMaskFilter> mf = std::move(fMaskFilter);
+         this->getMetrics(&tmpGlyph);
+         fMaskFilter = std::move(mf);
+ 
+-        // we need the prefilter bounds to be <= filter bounds
+-        SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
+-        SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
+-
+-        if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) {
++        // Use the origGlyph storage for the temporary unfiltered mask if it will fit.
++        if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat &&
++            tmpGlyph.imageSize() <= origGlyph.imageSize())
++        {
+             tmpGlyph.fImage = origGlyph.fImage;
+         } else {
+             tmpGlyphImageStorage.reset(tmpGlyph.imageSize());
+             tmpGlyph.fImage = tmpGlyphImageStorage.get();
+         }
+-        glyph = &tmpGlyph;
++        unfilteredGlyph = &tmpGlyph;
+     }
+ 
+     if (!fGenerateImageFromPath) {
+-        generateImage(*glyph);
++        generateImage(*unfilteredGlyph);
+     } else {
+         SkPath devPath;
+-        SkMask mask = glyph->mask();
++        SkMask mask = unfilteredGlyph->mask();
+ 
+-        if (!this->internalGetPath(glyph->getPackedID(), &devPath)) {
+-            generateImage(*glyph);
++        if (!this->internalGetPath(unfilteredGlyph->getPackedID(), &devPath)) {
++            generateImage(*unfilteredGlyph);
+         } else {
+             SkASSERT(SkMask::kARGB32_Format != origGlyph.fMaskFormat);
+             SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
+@@ -579,39 +577,98 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
+     }
+ 
+     if (fMaskFilter) {
+-        // the src glyph image shouldn't be 3D
+-        SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
++        // k3D_Format should not be mask filtered.
++        SkASSERT(SkMask::k3D_Format != unfilteredGlyph->fMaskFormat);
++
++        SkMask filteredMask;
++        SkMask srcMask;
++        SkMatrix m;
++        fRec.getMatrixFrom2x2(&m);
++
++        if (as_MFB(fMaskFilter)->filterMask(&filteredMask, unfilteredGlyph->mask(), m, nullptr)) {
++            // Filter succeeded; filteredMask.fImage was allocated.
++            srcMask = filteredMask;
++        } else if (unfilteredGlyph->fImage == tmpGlyphImageStorage.get()) {
++            // Filter did nothing; unfiltered mask is independent of origGlyph.fImage.
++            srcMask = unfilteredGlyph->mask();
++        } else if (origGlyph.iRect() == unfilteredGlyph->iRect()) {
++            // Filter did nothing; the unfiltered mask is in origGlyph.fImage and matches.
++            return;
++        } else {
++            // Filter did nothing; the unfiltered mask is in origGlyph.fImage and conflicts.
++            srcMask = unfilteredGlyph->mask();
++            size_t imageSize = unfilteredGlyph->imageSize();
++            tmpGlyphImageStorage.reset(imageSize);
++            srcMask.fImage = static_cast<uint8_t*>(tmpGlyphImageStorage.get());
++            memcpy(srcMask.fImage, unfilteredGlyph->fImage, imageSize);
++        }
+ 
+-        SkMask      srcM = glyph->mask(),
+-                    dstM;
+-        SkMatrix    matrix;
++        SkASSERT_RELEASE(srcMask.fFormat == origGlyph.fMaskFormat);
++        SkMask dstMask = origGlyph.mask();
++        SkIRect origBounds = dstMask.fBounds;
+ 
+-        fRec.getMatrixFrom2x2(&matrix);
++        // Find the intersection of src and dst while updating the fImages.
++        if (srcMask.fBounds.fTop < dstMask.fBounds.fTop) {
++            int32_t topDiff = dstMask.fBounds.fTop - srcMask.fBounds.fTop;
++            srcMask.fImage += srcMask.fRowBytes * topDiff;
++            srcMask.fBounds.fTop = dstMask.fBounds.fTop;
++        }
++        if (dstMask.fBounds.fTop < srcMask.fBounds.fTop) {
++            int32_t topDiff = srcMask.fBounds.fTop - dstMask.fBounds.fTop;
++            dstMask.fImage += dstMask.fRowBytes * topDiff;
++            dstMask.fBounds.fTop = srcMask.fBounds.fTop;
++        }
+ 
+-        if (as_MFB(fMaskFilter)->filterMask(&dstM, srcM, matrix, nullptr)) {
+-            int width = std::min<int>(origGlyph.fWidth, dstM.fBounds.width());
+-            int height = std::min<int>(origGlyph.fHeight, dstM.fBounds.height());
+-            int dstRB = origGlyph.rowBytes();
+-            int srcRB = dstM.fRowBytes;
++        if (srcMask.fBounds.fLeft < dstMask.fBounds.fLeft) {
++            int32_t leftDiff = dstMask.fBounds.fLeft - srcMask.fBounds.fLeft;
++            srcMask.fImage += leftDiff;
++            srcMask.fBounds.fLeft = dstMask.fBounds.fLeft;
++        }
++        if (dstMask.fBounds.fLeft < srcMask.fBounds.fLeft) {
++            int32_t leftDiff = srcMask.fBounds.fLeft - dstMask.fBounds.fLeft;
++            dstMask.fImage += leftDiff;
++            dstMask.fBounds.fLeft = srcMask.fBounds.fLeft;
++        }
+ 
+-            const uint8_t* src = (const uint8_t*)dstM.fImage;
+-            uint8_t* dst = (uint8_t*)origGlyph.fImage;
++        if (srcMask.fBounds.fBottom < dstMask.fBounds.fBottom) {
++            dstMask.fBounds.fBottom = srcMask.fBounds.fBottom;
++        }
++        if (dstMask.fBounds.fBottom < srcMask.fBounds.fBottom) {
++            srcMask.fBounds.fBottom = dstMask.fBounds.fBottom;
++        }
+ 
+-            if (SkMask::k3D_Format == dstM.fFormat) {
+-                // we have to copy 3 times as much
+-                height *= 3;
+-            }
++        if (srcMask.fBounds.fRight < dstMask.fBounds.fRight) {
++            dstMask.fBounds.fRight = srcMask.fBounds.fRight;
++        }
++        if (dstMask.fBounds.fRight < srcMask.fBounds.fRight) {
++            srcMask.fBounds.fRight = dstMask.fBounds.fRight;
++        }
+ 
+-            // clean out our glyph, since it may be larger than dstM
+-            //sk_bzero(dst, height * dstRB);
++        SkASSERT(srcMask.fBounds == dstMask.fBounds);
++        int width = srcMask.fBounds.width();
++        int height = srcMask.fBounds.height();
++        int dstRB = dstMask.fRowBytes;
++        int srcRB = srcMask.fRowBytes;
+ 
+-            while (--height >= 0) {
+-                memcpy(dst, src, width);
+-                src += srcRB;
+-                dst += dstRB;
+-            }
+-            SkMask::FreeImage(dstM.fImage);
++        const uint8_t* src = srcMask.fImage;
++        uint8_t* dst = dstMask.fImage;
++
++        if (SkMask::k3D_Format == filteredMask.fFormat) {
++            // we have to copy 3 times as much
++            height *= 3;
++        }
++
++        // If not filling the full original glyph, clear it out first.
++        if (dstMask.fBounds != origBounds) {
++            sk_bzero(origGlyph.fImage, origGlyph.fHeight * origGlyph.rowBytes());
++        }
++
++        while (--height >= 0) {
++            memcpy(dst, src, width);
++            src += srcRB;
++            dst += dstRB;
+         }
++        SkMask::FreeImage(filteredMask.fImage);
+     }
+ }
+