From 43f969a9bce8019354d392f384fe10328655f924 Mon Sep 17 00:00:00 2001
From: Michael Ludwig <michaelludwig@google.com>
Date: Tue, 19 May 2026 14:53:32 -0400
Subject: [PATCH] [ganesh] Require glyph padding to use linear sampling

Bug: https://issues.chromium.org/issues/514017326
Change-Id: I9425c1f86aa8762333ba72b4ba30f5a056cdbfa9
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1239738
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
---
 src/gpu/ganesh/ops/AtlasTextOp.cpp | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

--- a/src/gpu/ganesh/ops/AtlasTextOp.cpp
+++ b/src/gpu/ganesh/ops/AtlasTextOp.cpp
@@ -473,8 +473,12 @@
     } else
 #endif
     {
-        auto filter = fNeedsGlyphTransform ? GrSamplerState::Filter::kLinear
-                                           : GrSamplerState::Filter::kNearest;
+        // Only use linear padding if the glyphs were also padded for it. If we somehow get a direct
+        // subrun with a corrupted transform, we should still use nearest neighbor since it was
+        // packed tightly.
+        const bool hasGlyphPadding = fHead->fSubRun.glyphSrcPadding() > 0;
+        auto filter = fNeedsGlyphTransform && hasGlyphPadding ? GrSamplerState::Filter::kLinear
+                                                              : GrSamplerState::Filter::kNearest;
         // Bitmap text uses a single color, combineIfPossible ensures all geometries have the same
         // color, so we can use the first's without worry.
         flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
@@ -620,8 +624,9 @@
         } else
 #endif
         {
-            auto filter = fNeedsGlyphTransform ? GrSamplerState::Filter::kLinear
-                                               : GrSamplerState::Filter::kNearest;
+            const bool hasGlyphPadding = fHead->fSubRun.glyphSrcPadding() > 0;
+            auto filter = fNeedsGlyphTransform && hasGlyphPadding
+                    ? GrSamplerState::Filter::kLinear : GrSamplerState::Filter::kNearest;
             reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewViews(views, numActiveViews, filter);
         }
     }
@@ -650,6 +655,12 @@
         return CombineResult::kCannotCombine;
     }
 
+    // We use the same filter for every Geometry that is combined, but the filter choice only looks
+    // at the head's src padding, so we can only combine if we are consistent with that.
+    if (fHead->fSubRun.glyphSrcPadding() != that->fHead->fSubRun.glyphSrcPadding()) {
+        return CombineResult::kCannotCombine;
+    }
+
     if (fProcessors != that->fProcessors) {
         return CombineResult::kCannotCombine;
     }
