Revert "Remove "content" rect from GrTextureAdjuster."

This reverts commit 6e4bbbefe153495cf34ea42aa72691756e6ab40e.

Reason for revert: assertion failure

Original change's description:
> Remove "content" rect from GrTextureAdjuster.
> 
> Since we got rid of texture-backed bitmaps this is no longer required.
> 
> Change-Id: Id15c745994a3d6a1489e193b5d29916fa0931264
> Reviewed-on: https://skia-review.googlesource.com/36340
> Commit-Queue: Brian Salomon <bsalomon@google.com>
> Reviewed-by: Robert Phillips <robertphillips@google.com>

TBR=bsalomon@google.com,robertphillips@google.com

Change-Id: I2229ec05079368ff196ff351107f88062080e5ec
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/43720
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrTextureAdjuster.cpp b/src/gpu/GrTextureAdjuster.cpp
index 1508cb5..546ea67 100644
--- a/src/gpu/GrTextureAdjuster.cpp
+++ b/src/gpu/GrTextureAdjuster.cpp
@@ -13,14 +13,22 @@
 #include "SkGr.h"
 
 GrTextureAdjuster::GrTextureAdjuster(GrContext* context, sk_sp<GrTextureProxy> original,
-                                     SkAlphaType alphaType, uint32_t uniqueID, SkColorSpace* cs)
-        : INHERITED(original->width(), original->height(),
-                    GrPixelConfigIsAlphaOnly(original->config()))
-        , fContext(context)
-        , fOriginal(std::move(original))
-        , fAlphaType(alphaType)
-        , fColorSpace(cs)
-        , fUniqueID(uniqueID) {}
+                                     SkAlphaType alphaType,
+                                     const SkIRect& contentArea, uint32_t uniqueID,
+                                     SkColorSpace* cs)
+    : INHERITED(contentArea.width(), contentArea.height(),
+                GrPixelConfigIsAlphaOnly(original->config()))
+    , fContext(context)
+    , fOriginal(std::move(original))
+    , fAlphaType(alphaType)
+    , fColorSpace(cs)
+    , fUniqueID(uniqueID) {
+    SkASSERT(SkIRect::MakeWH(fOriginal->width(), fOriginal->height()).contains(contentArea));
+    if (contentArea.fLeft > 0 || contentArea.fTop > 0 ||
+        contentArea.fRight < fOriginal->width() || contentArea.fBottom < fOriginal->height()) {
+        fContentArea.set(contentArea);
+    }
+}
 
 void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey,
                                     SkColorSpace* dstColorSpace) {
@@ -46,8 +54,9 @@
     }
 
     sk_sp<GrTextureProxy> proxy = this->originalProxyRef();
+    const SkIRect* contentArea = this->contentAreaOrNull();
 
-    sk_sp<GrTextureProxy> copy = CopyOnGpu(fContext, std::move(proxy), copyParams);
+    sk_sp<GrTextureProxy> copy = CopyOnGpu(fContext, std::move(proxy), contentArea, copyParams);
     if (copy) {
         if (key.isValid()) {
             SkASSERT(copy->origin() == this->originalProxy()->origin());
@@ -60,31 +69,60 @@
 
 sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxySafeForParams(
                                                                  const GrSamplerParams& params,
+                                                                 SkIPoint* outOffset,
                                                                  SkScalar scaleAdjust[2]) {
     sk_sp<GrTextureProxy> proxy = this->originalProxyRef();
     CopyParams copyParams;
+    const SkIRect* contentArea = this->contentAreaOrNull();
 
     if (!fContext) {
         // The texture was abandoned.
         return nullptr;
     }
-    if (!fContext->getGpu()->isACopyNeededForTextureParams(proxy.get(), params, &copyParams,
-                                                           scaleAdjust)) {
+
+    if (contentArea && GrSamplerParams::kMipMap_FilterMode == params.filterMode()) {
+        // If we generate a MIP chain for texture it will read pixel values from outside the content
+        // area.
+        copyParams.fWidth = contentArea->width();
+        copyParams.fHeight = contentArea->height();
+        copyParams.fFilter = GrSamplerParams::kBilerp_FilterMode;
+    } else if (!fContext->getGpu()->isACopyNeededForTextureParams(proxy.get(), params, &copyParams,
+                                                                  scaleAdjust)) {
+        if (outOffset) {
+            if (contentArea) {
+                outOffset->set(contentArea->fLeft, contentArea->fRight);
+            } else {
+                outOffset->set(0, 0);
+            }
+        }
         return proxy;
     }
 
     sk_sp<GrTextureProxy> copy = this->refTextureProxyCopy(copyParams);
+    if (copy && outOffset) {
+        outOffset->set(0, 0);
+    }
     return copy;
 }
 
 std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
         const SkMatrix& origTextureMatrix,
-        const SkRect& constraintRect,
+        const SkRect& origConstraintRect,
         FilterConstraint filterConstraint,
         bool coordsLimitedToConstraintRect,
         const GrSamplerParams::FilterMode* filterOrNullForBicubic,
         SkColorSpace* dstColorSpace) {
     SkMatrix textureMatrix = origTextureMatrix;
+    const SkIRect* contentArea = this->contentAreaOrNull();
+    // Convert the constraintRect to be relative to the texture rather than the content area so
+    // that both rects are in the same coordinate system.
+    SkTCopyOnFirstWrite<SkRect> constraintRect(origConstraintRect);
+    if (contentArea) {
+        SkScalar l = SkIntToScalar(contentArea->fLeft);
+        SkScalar t = SkIntToScalar(contentArea->fTop);
+        constraintRect.writable()->offset(l, t);
+        textureMatrix.postTranslate(l, t);
+    }
 
     SkRect domain;
     GrSamplerParams params;
@@ -92,19 +130,22 @@
         params.setFilterMode(*filterOrNullForBicubic);
     }
     SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
-    sk_sp<GrTextureProxy> proxy(this->refTextureProxySafeForParams(params, scaleAdjust));
+    sk_sp<GrTextureProxy> proxy(this->refTextureProxySafeForParams(params, nullptr, scaleAdjust));
     if (!proxy) {
         return nullptr;
     }
     // If we made a copy then we only copied the contentArea, in which case the new texture is all
     // content.
     if (proxy.get() != this->originalProxy()) {
+        contentArea = nullptr;
         textureMatrix.postScale(scaleAdjust[0], scaleAdjust[1]);
     }
 
     DomainMode domainMode =
-            DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
-                                proxy.get(), filterOrNullForBicubic, &domain);
+        DetermineDomainMode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
+                            proxy.get(),
+                            contentArea, filterOrNullForBicubic,
+                            &domain);
     if (kTightCopy_DomainMode == domainMode) {
         // TODO: Copy the texture and adjust the texture matrix (both parts need to consider
         // non-int constraint rect)
@@ -115,8 +156,9 @@
                  GrSamplerParams::kMipMap_FilterMode == *filterOrNullForBicubic);
         static const GrSamplerParams::FilterMode kBilerp = GrSamplerParams::kBilerp_FilterMode;
         domainMode =
-                DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
-                                    proxy.get(), &kBilerp, &domain);
+            DetermineDomainMode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
+                                proxy.get(),
+                                contentArea, &kBilerp, &domain);
         SkASSERT(kTightCopy_DomainMode != domainMode);
     }
     SkASSERT(kNoDomain_DomainMode == domainMode ||
diff --git a/src/gpu/GrTextureAdjuster.h b/src/gpu/GrTextureAdjuster.h
index 3c9d0fd..fad533f 100644
--- a/src/gpu/GrTextureAdjuster.h
+++ b/src/gpu/GrTextureAdjuster.h
@@ -21,9 +21,10 @@
 class GrTextureAdjuster : public GrTextureProducer {
 public:
     /** Makes the subset of the texture safe to use with the given texture parameters.
-        If the copy's size does not match subset's dimensions then the resulting scale
-        factors used to sample the copy are returned in 'scaleAdjust'. */
-    sk_sp<GrTextureProxy> refTextureProxySafeForParams(const GrSamplerParams&,
+        outOffset will be the top-left corner of the subset if a copy is not made. Otherwise,
+        the copy will be tight to the contents and outOffset will be (0, 0). If the copy's size
+        does not match subset's dimensions then the contents are scaled to fit the copy.*/
+    sk_sp<GrTextureProxy> refTextureProxySafeForParams(const GrSamplerParams&, SkIPoint* outOffset,
                                                        SkScalar scaleAdjust[2]);
 
     std::unique_ptr<GrFragmentProcessor> createFragmentProcessor(
@@ -36,8 +37,8 @@
 
     // We do not ref the texture nor the colorspace, so the caller must keep them in scope while
     // this Adjuster is alive.
-    GrTextureAdjuster(GrContext*, sk_sp<GrTextureProxy>, SkAlphaType, uint32_t uniqueID,
-                      SkColorSpace*);
+    GrTextureAdjuster(GrContext*, sk_sp<GrTextureProxy>, SkAlphaType, const SkIRect& area,
+                      uint32_t uniqueID, SkColorSpace*);
 
 protected:
     SkAlphaType alphaType() const override { return fAlphaType; }
@@ -48,7 +49,11 @@
     GrTextureProxy* originalProxy() const { return fOriginal.get(); }
     sk_sp<GrTextureProxy> originalProxyRef() const { return fOriginal; }
 
+    /** Returns the content area or null for the whole original texture */
+    const SkIRect* contentAreaOrNull() { return fContentArea.getMaybeNull(); }
+
 private:
+    SkTLazy<SkIRect>      fContentArea;
     GrContext*            fContext;
     sk_sp<GrTextureProxy> fOriginal;
     SkAlphaType           fAlphaType;
diff --git a/src/gpu/GrTextureMaker.cpp b/src/gpu/GrTextureMaker.cpp
index bb30439..7e257d8 100644
--- a/src/gpu/GrTextureMaker.cpp
+++ b/src/gpu/GrTextureMaker.cpp
@@ -59,7 +59,7 @@
 
     sk_sp<GrTextureProxy> result;
     if (original) {
-        result = CopyOnGpu(fContext, std::move(original), copyParams);
+        result = CopyOnGpu(fContext, std::move(original), nullptr, copyParams);
     } else {
         result = this->generateTextureProxyForParams(copyParams, willBeMipped, dstColorSpace);
     }
@@ -114,8 +114,9 @@
     adjustedMatrix.postScale(scaleAdjust[0], scaleAdjust[1]);
     SkRect domain;
     DomainMode domainMode =
-            DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
-                                proxy.get(), fmForDetermineDomain, &domain);
+        DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
+                            proxy.get(),
+                            nullptr, fmForDetermineDomain, &domain);
     SkASSERT(kTightCopy_DomainMode != domainMode);
     sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(),
                                                                        dstColorSpace);
@@ -134,5 +135,5 @@
         return nullptr;
     }
 
-    return CopyOnGpu(fContext, std::move(original), copyParams);
+    return CopyOnGpu(fContext, std::move(original), nullptr, copyParams);
 }
diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp
index f7d71fa..9273223 100644
--- a/src/gpu/GrTextureProducer.cpp
+++ b/src/gpu/GrTextureProducer.cpp
@@ -16,7 +16,9 @@
 
 sk_sp<GrTextureProxy> GrTextureProducer::CopyOnGpu(GrContext* context,
                                                    sk_sp<GrTextureProxy> inputProxy,
+                                                   const SkIRect* subset,
                                                    const CopyParams& copyParams) {
+    SkASSERT(!subset || !subset->isEmpty());
     SkASSERT(context);
 
     const SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight);
@@ -31,13 +33,23 @@
     GrPaint paint;
     paint.setGammaCorrect(true);
 
-    SkRect localRect = SkRect::MakeWH(inputProxy->width(), inputProxy->height());
+    SkRect localRect;
+    if (subset) {
+        localRect = SkRect::Make(*subset);
+    } else {
+        localRect = SkRect::MakeWH(inputProxy->width(), inputProxy->height());
+    }
 
     bool needsDomain = false;
     if (copyParams.fFilter != GrSamplerParams::kNone_FilterMode) {
         bool resizing = localRect.width()  != dstRect.width() ||
                         localRect.height() != dstRect.height();
-        needsDomain = resizing && !GrResourceProvider::IsFunctionallyExact(inputProxy.get());
+
+        if (GrResourceProvider::IsFunctionallyExact(inputProxy.get())) {
+            needsDomain = subset && resizing;
+        } else {
+            needsDomain = resizing;
+        }
     }
 
     if (needsDomain) {
@@ -76,45 +88,62 @@
                                 FilterConstraint filterConstraint,
                                 bool coordsLimitedToConstraintRect,
                                 GrTextureProxy* proxy,
+                                const SkIRect* contentRect,
                                 const GrSamplerParams::FilterMode* filterModeOrNullForBicubic,
                                 SkRect* domainRect) {
     const SkIRect proxyBounds = SkIRect::MakeWH(proxy->width(), proxy->height());
 
     SkASSERT(proxyBounds.contains(constraintRect));
+    // We only expect a content area rect if there is some non-content area.
+    SkASSERT(!contentRect ||
+             (!contentRect->contains(proxyBounds) &&
+              proxyBounds.contains(*contentRect) &&
+              contentRect->contains(constraintRect)));
 
     const bool proxyIsExact = GrResourceProvider::IsFunctionallyExact(proxy);
-    // We don't expect to have an image that is in an inexact proxy unless the caller was aware
-    // of the potential of sampling outside of the proxy's bounds and specified a constraint rect
-    // with a filter constraint.
-    SkASSERT(kYes_FilterConstraint == filterConstraint || proxyIsExact);
+
     // If the constraint rectangle contains the whole proxy then no need for a domain.
     if (constraintRect.contains(proxyBounds) && proxyIsExact) {
         return kNoDomain_DomainMode;
     }
 
+    if (!contentRect && !proxyIsExact) {
+        contentRect = &proxyBounds;
+    }
+
     bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint);
 
     // If we can filter outside the constraint rect, and there is no non-content area of the
     // proxy, and we aren't going to generate sample coords outside the constraint rect then we
     // don't need a domain.
-    if (!restrictFilterToRect && coordsLimitedToConstraintRect) {
+    if (!restrictFilterToRect && !contentRect && coordsLimitedToConstraintRect) {
         return kNoDomain_DomainMode;
     }
 
     // Get the domain inset based on sampling mode (or bail if mipped)
+    SkScalar filterHalfWidth = 0.f;
     if (filterModeOrNullForBicubic) {
         switch (*filterModeOrNullForBicubic) {
             case GrSamplerParams::kNone_FilterMode:
                 if (coordsLimitedToConstraintRect) {
                     return kNoDomain_DomainMode;
+                } else {
+                    filterHalfWidth = 0.f;
                 }
                 break;
             case GrSamplerParams::kBilerp_FilterMode:
+                filterHalfWidth = .5f;
                 break;
             case GrSamplerParams::kMipMap_FilterMode:
-                // No domain can save us with mip maps.
-                return  restrictFilterToRect ? kTightCopy_DomainMode : kNoDomain_DomainMode;
+                if (restrictFilterToRect || contentRect) {
+                    // No domain can save us here.
+                    return kTightCopy_DomainMode;
+                }
+                return kNoDomain_DomainMode;
         }
+    } else {
+        // bicubic does nearest filtering internally.
+        filterHalfWidth = 1.5f;
     }
 
     // Both bilerp and bicubic use bilinear filtering and so need to be clamped to the center
@@ -126,17 +155,67 @@
     // the domain.
     if (restrictFilterToRect) {
         *domainRect = constraintRect.makeInset(kDomainInset, kDomainInset);
-        if (domainRect->fLeft > domainRect->fRight) {
-            domainRect->fLeft = domainRect->fRight =
-                    SkScalarAve(domainRect->fLeft, domainRect->fRight);
+    } else if (contentRect) {
+        // If we got here then: there is a contentRect, the coords are limited to the
+        // constraint rect, and we're allowed to filter across the constraint rect boundary. So
+        // we check whether the filter would reach across the edge of the content area.
+        // We will only set the sides that are required.
+
+        domainRect->setLargest();
+        if (coordsLimitedToConstraintRect) {
+            // We may be able to use the fact that the texture coords are limited to the constraint
+            // rect in order to avoid having to add a domain.
+            bool needContentAreaConstraint = false;
+            if (contentRect->fLeft > 0 &&
+                contentRect->fLeft + filterHalfWidth > constraintRect.fLeft) {
+                domainRect->fLeft = contentRect->fLeft + kDomainInset;
+                needContentAreaConstraint = true;
+            }
+            if (contentRect->fTop > 0 &&
+                contentRect->fTop + filterHalfWidth > constraintRect.fTop) {
+                domainRect->fTop = contentRect->fTop + kDomainInset;
+                needContentAreaConstraint = true;
+            }
+            if ((!proxyIsExact || contentRect->fRight < proxy->width()) &&
+                contentRect->fRight - filterHalfWidth < constraintRect.fRight) {
+                domainRect->fRight = contentRect->fRight - kDomainInset;
+                needContentAreaConstraint = true;
+            }
+            if ((!proxyIsExact || contentRect->fBottom < proxy->height()) &&
+                contentRect->fBottom - filterHalfWidth < constraintRect.fBottom) {
+                domainRect->fBottom = contentRect->fBottom - kDomainInset;
+                needContentAreaConstraint = true;
+            }
+            if (!needContentAreaConstraint) {
+                return kNoDomain_DomainMode;
+            }
+        } else {
+            // Our sample coords for the texture are allowed to be outside the constraintRect so we
+            // don't consider it when computing the domain.
+            if (contentRect->fLeft > 0) {
+                domainRect->fLeft = contentRect->fLeft + kDomainInset;
+            }
+            if (contentRect->fTop > 0) {
+                domainRect->fTop = contentRect->fTop + kDomainInset;
+            }
+            if (!proxyIsExact || contentRect->fRight < proxy->width()) {
+                domainRect->fRight = contentRect->fRight - kDomainInset;
+            }
+            if (!proxyIsExact || contentRect->fBottom < proxy->height()) {
+                domainRect->fBottom = contentRect->fBottom - kDomainInset;
+            }
         }
-        if (domainRect->fTop > domainRect->fBottom) {
-            domainRect->fTop = domainRect->fBottom =
-                    SkScalarAve(domainRect->fTop, domainRect->fBottom);
-        }
-        return kDomain_DomainMode;
+    } else {
+        return kNoDomain_DomainMode;
     }
-    return kNoDomain_DomainMode;
+
+    if (domainRect->fLeft > domainRect->fRight) {
+        domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft, domainRect->fRight);
+    }
+    if (domainRect->fTop > domainRect->fBottom) {
+        domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, domainRect->fBottom);
+    }
+    return kDomain_DomainMode;
 }
 
 std::unique_ptr<GrFragmentProcessor> GrTextureProducer::CreateFragmentProcessorForDomainAndFilter(
diff --git a/src/gpu/GrTextureProducer.h b/src/gpu/GrTextureProducer.h
index 2853a88..ccc0dae 100644
--- a/src/gpu/GrTextureProducer.h
+++ b/src/gpu/GrTextureProducer.h
@@ -119,13 +119,14 @@
     };
 
     static sk_sp<GrTextureProxy> CopyOnGpu(GrContext*, sk_sp<GrTextureProxy> inputProxy,
-                                           const CopyParams& copyParams);
+                                           const SkIRect* subset, const CopyParams& copyParams);
 
     static DomainMode DetermineDomainMode(
         const SkRect& constraintRect,
         FilterConstraint filterConstraint,
         bool coordsLimitedToConstraintRect,
         GrTextureProxy*,
+        const SkIRect* textureContentArea,
         const GrSamplerParams::FilterMode* filterModeOrNullForBicubic,
         SkRect* domainRect);
 
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index a279c92..0cf2ae5 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1406,7 +1406,8 @@
     ASSERT_SINGLE_OWNER
     uint32_t pinnedUniqueID;
     if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
-        GrTextureAdjuster adjuster(this->context(), std::move(proxy), image->alphaType(),
+        GrTextureAdjuster adjuster(this->context(), std::move(proxy),
+                                   image->alphaType(), image->bounds(),
                                    pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace());
         this->drawProducerNine(&adjuster, center, dst, paint);
     } else {
@@ -1460,7 +1461,8 @@
     ASSERT_SINGLE_OWNER
     uint32_t pinnedUniqueID;
     if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) {
-        GrTextureAdjuster adjuster(this->context(), std::move(proxy), image->alphaType(),
+        GrTextureAdjuster adjuster(this->context(), std::move(proxy),
+                                   image->alphaType(), image->bounds(),
                                    pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace());
         this->drawProducerLattice(&adjuster, lattice, dst, paint);
     } else {
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
index 596f504..c861cc9 100644
--- a/src/gpu/SkGpuDevice_drawTexture.cpp
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -145,8 +145,9 @@
                             this->clip(), fRenderTargetContext.get());
         return;
     }
-    GrTextureAdjuster adjuster(this->context(), std::move(proxy), alphaType, pinnedUniqueID,
-                               colorSpace);
+    auto contentRect = SkIRect::MakeWH(proxy->width(), proxy->height());
+    GrTextureAdjuster adjuster(this->context(), std::move(proxy), alphaType, contentRect,
+                               pinnedUniqueID, colorSpace);
     this->drawTextureProducer(&adjuster, srcRect, dstRect, constraint, viewMatrix, paint);
 }
 
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 034f7bc..3458075 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -123,9 +123,9 @@
         *texColorSpace = this->fColorSpace;
     }
 
-    GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->uniqueID(),
-                               this->fColorSpace.get());
-    return adjuster.refTextureProxySafeForParams(params, scaleAdjust);
+    GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->bounds(),
+                               this->uniqueID(), this->fColorSpace.get());
+    return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust);
 }
 
 static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index cb4a5b2..5b7e83f 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -186,9 +186,10 @@
     uint32_t uniqueID;
     sk_sp<GrTextureProxy> tex = this->refPinnedTextureProxy(&uniqueID);
     if (tex) {
-        GrTextureAdjuster adjuster(context, fPinnedProxy, fBitmap.alphaType(), fPinnedUniqueID,
-                                   fBitmap.colorSpace());
-        return adjuster.refTextureProxySafeForParams(params, scaleAdjust);
+        GrTextureAdjuster adjuster(context, fPinnedProxy,
+                                   fBitmap.alphaType(), fBitmap.bounds(),
+                                   fPinnedUniqueID, fBitmap.colorSpace());
+        return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust);
     }
 
     return GrRefCachedBitmapTextureProxy(context, fBitmap, params, scaleAdjust);
diff --git a/tests/DetermineDomainModeTest.cpp b/tests/DetermineDomainModeTest.cpp
index ef1a5ad..ee9a694 100644
--- a/tests/DetermineDomainModeTest.cpp
+++ b/tests/DetermineDomainModeTest.cpp
@@ -13,10 +13,11 @@
 #include "GrTextureProducer.h"
 #include "GrTextureProxy.h"
 
-// For DetermineDomainMode (in the MDB world) we have 3 rects:
+// For DetermineDomainMode (in the MDB world) we have 4 rects:
 //      1) the final instantiated backing storage (i.e., the actual GrTexture's extent)
 //      2) the proxy's extent, which may or may not match the GrTexture's extent
-//      3) the constraint rect, which can optionally be hard or soft
+//      3) the content rect, which can be a subset of the proxy's extent or null
+//      4) the constraint rect, which can optionally be hard or soft
 // This test "fuzzes" all the combinations of these rects.
 class GrTextureProducer_TestAccess {
 public:
@@ -27,12 +28,14 @@
                                 GrTextureProducer::FilterConstraint filterConstraint,
                                 bool coordsLimitedToConstraintRect,
                                 GrTextureProxy* proxy,
+                                const SkIRect* textureContentArea,
                                 const GrSamplerParams::FilterMode* filterModeOrNullForBicubic,
                                 SkRect* domainRect) {
         return GrTextureProducer::DetermineDomainMode(constraintRect,
                                                       filterConstraint,
                                                       coordsLimitedToConstraintRect,
                                                       proxy,
+                                                      textureContentArea,
                                                       filterModeOrNullForBicubic,
                                                       domainRect);
     }
@@ -40,6 +43,22 @@
 
 using DomainMode = GrTextureProducer_TestAccess::DomainMode;
 
+#ifdef SK_DEBUG
+static bool is_irect(const SkRect& r) {
+    return SkScalarIsInt(r.fLeft)  && SkScalarIsInt(r.fTop) &&
+           SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
+}
+#endif
+
+static SkIRect to_irect(const SkRect& r) {
+    SkASSERT(is_irect(r));
+    return SkIRect::MakeLTRB(SkScalarRoundToInt(r.fLeft),
+                             SkScalarRoundToInt(r.fTop),
+                             SkScalarRoundToInt(r.fRight),
+                             SkScalarRoundToInt(r.fBottom));
+}
+
+
 class RectInfo {
 public:
     enum Side { kLeft = 0, kTop = 1, kRight = 2, kBot = 3 };
@@ -297,6 +316,20 @@
                          kInsetLeft_Flag|kInsetTop_Flag|kInsetRight_Flag|kInsetBot_Flag, name);
 }
 
+// This is only used for content rect creation. We ensure 'result' is correct but
+// return null to indicate no content area (other than what the proxy specifies).
+static const SkRect* null_rect(const RectInfo& enclosing,
+                               RectInfo* result,
+                               bool isInsetHard,
+                               bool areCoordsLimitedToRect,
+                               float insetAmount,
+                               float halfFilterWidth) {
+    static const char* name = "null";
+    generic_inset(enclosing, result, isInsetHard, areCoordsLimitedToRect,
+                  insetAmount, halfFilterWidth, 0, name);
+    return nullptr;
+}
+
 // Make a rect with no inset. This is only used for constraint rect creation.
 static const SkRect* no_inset(const RectInfo& enclosing,
                               RectInfo* result,
@@ -332,50 +365,70 @@
             sk_sp<GrTextureProxy> proxy = create_proxy(resourceProvider, isPowerOfTwoSized,
                                                        isExact, &outermost);
             SkASSERT(outermost.isHardOrBadAllAround());
-            for (auto isConstraintRectHard : { true, false }) {
-                if (!isConstraintRectHard && !isExact) {
-                    // GrTextureProducer expects that texture inexactness is expressed as a
-                    // constraint rect and asserts if not. This skips a case that never happens
-                    // through the public API.
-                    continue;
+
+            for (auto contentRectMaker : { left_only, top_only, right_only,
+                                           bot_only, full_inset, null_rect}) {
+                RectInfo contentRectStorage;
+                const SkRect* contentRect = (*contentRectMaker)(outermost,
+                                                                &contentRectStorage,
+                                                                true, false, 5.0f, -1.0f);
+                if (contentRect) {
+                    // We only have content rects if they actually reduce the extent of the content
+                    SkASSERT(!contentRect->contains(outermost.rect()));
+                    SkASSERT(outermost.rect().contains(*contentRect));
+                    SkASSERT(is_irect(*contentRect));
                 }
-                for (auto areCoordsLimitedToConstraintRect : { true, false }) {
-                    for (int filterMode = 0; filterMode < 4; ++filterMode) {
-                        for (auto constraintRectMaker : { left_only, top_only, right_only,
-                                                          bot_only, full_inset, no_inset }) {
-                            for (auto insetAmt : { 0.25f, 0.75f, 1.25f, 1.75f, 5.0f }) {
-                                RectInfo constraintRectStorage;
-                                const SkRect* constraintRect = (*constraintRectMaker)(
-                                                outermost,
-                                                &constraintRectStorage,
-                                                isConstraintRectHard,
-                                                areCoordsLimitedToConstraintRect,
-                                                insetAmt,
-                                                gHalfFilterWidth[filterMode]);
-                                SkASSERT(constraintRect); // always need one of these
-                                SkASSERT(outermost.rect().contains(*constraintRect));
+                SkASSERT(contentRectStorage.isHardOrBadAllAround());
 
-                                actualMode = GrTextureProducer_TestAccess::DetermineDomainMode(
-                                                *constraintRect,
-                                                isConstraintRectHard
-                                                    ? GrTextureProducer::kYes_FilterConstraint
-                                                    : GrTextureProducer::kNo_FilterConstraint,
-                                                areCoordsLimitedToConstraintRect,
-                                                proxy.get(),
-                                                gModePtrs[filterMode],
-                                                &actualDomainRect);
-
-                                expectedMode = DomainMode::kNoDomain_DomainMode;
-                                if (constraintRectStorage.hasABad()) {
-                                    if (3 == filterMode) {
-                                        expectedMode = DomainMode::kTightCopy_DomainMode;
+                for (auto isConstraintRectHard : { true, false }) {
+                    for (auto areCoordsLimitedToConstraintRect : { true, false }) {
+                        for (int filterMode = 0; filterMode < 4; ++filterMode) {
+                            for (auto constraintRectMaker : { left_only, top_only, right_only,
+                                                              bot_only, full_inset, no_inset }) {
+                                for (auto insetAmt : { 0.25f, 0.75f, 1.25f, 1.75f, 5.0f }) {
+                                    RectInfo constraintRectStorage;
+                                    const SkRect* constraintRect = (*constraintRectMaker)(
+                                                    contentRect ? contentRectStorage : outermost,
+                                                    &constraintRectStorage,
+                                                    isConstraintRectHard,
+                                                    areCoordsLimitedToConstraintRect,
+                                                    insetAmt,
+                                                    gHalfFilterWidth[filterMode]);
+                                    SkASSERT(constraintRect); // always need one of these
+                                    if (contentRect) {
+                                        SkASSERT(contentRect->contains(*constraintRect));
                                     } else {
-                                        expectedMode = DomainMode::kDomain_DomainMode;
+                                        SkASSERT(outermost.rect().contains(*constraintRect));
                                     }
-                                }
 
-                                REPORTER_ASSERT(reporter, expectedMode == actualMode);
-                                // TODO: add a check that the returned domain rect is correct
+                                    SkIRect contentIRect;
+                                    if (contentRect) {
+                                        contentIRect = to_irect(*contentRect);
+                                    }
+
+                                    actualMode = GrTextureProducer_TestAccess::DetermineDomainMode(
+                                                    *constraintRect,
+                                                    isConstraintRectHard
+                                                        ? GrTextureProducer::kYes_FilterConstraint
+                                                        : GrTextureProducer::kNo_FilterConstraint,
+                                                    areCoordsLimitedToConstraintRect,
+                                                    proxy.get(),
+                                                    contentRect ? &contentIRect : nullptr,
+                                                    gModePtrs[filterMode],
+                                                    &actualDomainRect);
+
+                                    expectedMode = DomainMode::kNoDomain_DomainMode;
+                                    if (constraintRectStorage.hasABad()) {
+                                        if (3 == filterMode) {
+                                            expectedMode = DomainMode::kTightCopy_DomainMode;
+                                        } else {
+                                            expectedMode = DomainMode::kDomain_DomainMode;
+                                        }
+                                    }
+
+                                    REPORTER_ASSERT(reporter, expectedMode == actualMode);
+                                    // TODO: add a check that the returned domain rect is correct
+                                }
                             }
                         }
                     }