Fix nearest neighbor sampling of YUV[A] images

Change-Id: If07ded029ddfe4c1d3cc1a6f206f9aca75fbb8bd
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/295568
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/effects/GrTextureEffect.cpp b/src/gpu/effects/GrTextureEffect.cpp
index 4159250..b04e8a2 100644
--- a/src/gpu/effects/GrTextureEffect.cpp
+++ b/src/gpu/effects/GrTextureEffect.cpp
@@ -31,7 +31,8 @@
              const SkRect&,
              const SkRect*,
              const float border[4],
-             const GrCaps&);
+             const GrCaps&,
+             SkVector bilerpInset = {0.5f, 0.5f});
     inline bool hasBorderAlpha() const;
 };
 
@@ -40,7 +41,8 @@
                                     const SkRect& subset,
                                     const SkRect* domain,
                                     const float border[4],
-                                    const GrCaps& caps) {
+                                    const GrCaps& caps,
+                                    SkVector bilerpInset) {
     struct Span {
         float fA = 0.f, fB = 0.f;
 
@@ -64,7 +66,7 @@
     auto type = proxy.asTextureProxy()->textureType();
     auto filter = sampler.filter();
 
-    auto resolve = [type, &caps, filter, &border](int size, Mode mode, Span subset, Span domain) {
+    auto resolve = [&](int size, Mode mode, Span subset, Span domain, float bilerpInset) {
         Result1D r;
         bool canDoModeInHW = true;
         // TODO: Use HW border color when available.
@@ -96,7 +98,7 @@
             // and GPU-specific snapping at the boundary).
             r.fShaderClamp = isubset.makeInset(0.5f);
         } else {
-            r.fShaderClamp = subset.makeInset(0.5f);
+            r.fShaderClamp = subset.makeInset(bilerpInset);
             if (r.fShaderClamp.contains(domain)) {
                 domainIsSafe = true;
             }
@@ -120,12 +122,12 @@
     Span subsetX{subset.fLeft, subset.fRight};
     auto domainX = domain ? Span{domain->fLeft, domain->fRight}
                           : Span{SK_FloatNegativeInfinity, SK_FloatInfinity};
-    auto x = resolve(dim.width(), sampler.wrapModeX(), subsetX, domainX);
+    auto x = resolve(dim.width(), sampler.wrapModeX(), subsetX, domainX, bilerpInset.fX);
 
     Span subsetY{subset.fTop, subset.fBottom};
     auto domainY = domain ? Span{domain->fTop, domain->fBottom}
                           : Span{SK_FloatNegativeInfinity, SK_FloatInfinity};
-    auto y = resolve(dim.height(), sampler.wrapModeY(), subsetY, domainY);
+    auto y = resolve(dim.height(), sampler.wrapModeY(), subsetY, domainY, bilerpInset.fY);
 
     fHWSampler = {x.fHWMode, y.fHWMode, filter};
     fShaderModes[0] = x.fShaderMode;
@@ -257,6 +259,26 @@
                                                                           lazyProxyNormalization)));
 }
 
+std::unique_ptr<GrFragmentProcessor> GrTextureEffect::MakeBilerpWithInset(
+        GrSurfaceProxyView view,
+        SkAlphaType alphaType,
+        const SkMatrix& matrix,
+        GrSamplerState::WrapMode wx,
+        GrSamplerState::WrapMode wy,
+        const SkRect& subset,
+        SkVector inset,
+        const GrCaps& caps,
+        const float border[4]) {
+    GrSamplerState sampler(wx, wy, GrSamplerState::Filter::kBilerp);
+    Sampling sampling(*view.proxy(), sampler, subset, nullptr, border, caps, inset);
+    SkMatrix final;
+    bool lazyProxyNormalization;
+    get_matrix(matrix, view, &final, &lazyProxyNormalization);
+    return GrMatrixEffect::Make(
+            final, std::unique_ptr<GrFragmentProcessor>(new GrTextureEffect(
+                           std::move(view), alphaType, sampling, lazyProxyNormalization)));
+}
+
 GrTextureEffect::ShaderMode GrTextureEffect::GetShaderMode(GrSamplerState::WrapMode mode,
                                                            GrSamplerState::Filter filter) {
     switch (mode) {