[graphite] Add a PaintOptions Builder

This will eliminate a lot of the boiler plate of PaintOptions construction.

For this to work we would need to copy the contents of PaintOptionsBuilder.h/.cpp directly into Chrome and Android. I don't think it warrants being part of the Skia API.

Ultimately, I would like to not even have the trampoline functions (e.g., SolidSrcover).

Bug: b/390186667
Change-Id: I9eaa553a94285cebe334da58f0f0d99ac4e1c0bd
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1012416
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Noelle Scobie <nscobie@google.com>
diff --git a/gn/tests.gni b/gn/tests.gni
index 1319b4f..2e797f6 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -395,6 +395,8 @@
   "$_tests/graphite/precompile/AndroidPrecompileTest.cpp",
   "$_tests/graphite/precompile/ChromePrecompileTest.cpp",
   "$_tests/graphite/precompile/CombinationBuilderTest.cpp",
+  "$_tests/graphite/precompile/PaintOptionsBuilder.cpp",
+  "$_tests/graphite/precompile/PaintOptionsBuilder.h",
   "$_tests/graphite/precompile/PaintParamsKeyTest.cpp",
   "$_tests/graphite/precompile/PrecompileStatsTest.cpp",
   "$_tests/graphite/precompile/PrecompileTestUtils.cpp",
diff --git a/include/gpu/graphite/precompile/PaintOptions.h b/include/gpu/graphite/precompile/PaintOptions.h
index 4a94df3..0928a7b 100644
--- a/include/gpu/graphite/precompile/PaintOptions.h
+++ b/include/gpu/graphite/precompile/PaintOptions.h
@@ -119,6 +119,9 @@
     SkSpan<const SkBlendMode> getBlendModes() const {
         return SkSpan<const SkBlendMode>(fBlendModeOptions.data(), fBlendModeOptions.size());
     }
+    void addBlendMode(SkBlendMode bm) {
+        fBlendModeOptions.push_back(bm);
+    }
 
     /** Sets the blender options used when generating precompilation combinations.
 
@@ -155,9 +158,6 @@
     friend class PrecompileMaskFilter;  // for ProcessCombination access
 
     void addColorFilter(sk_sp<PrecompileColorFilter> cf);
-    void addBlendMode(SkBlendMode bm) {
-        fBlendModeOptions.push_back(bm);
-    }
 
     void setClipShaders(SkSpan<const sk_sp<PrecompileShader>> clipShaders);
 
diff --git a/tests/graphite/precompile/ChromePrecompileTest.cpp b/tests/graphite/precompile/ChromePrecompileTest.cpp
index 098ec2e..1b8b8de 100644
--- a/tests/graphite/precompile/ChromePrecompileTest.cpp
+++ b/tests/graphite/precompile/ChromePrecompileTest.cpp
@@ -50,7 +50,7 @@
 /* 10 */ { ImagePremulClampNoCubicDstin(),     kQuadAndNonAARect,                kBGRA_1_D },
 /* 11 */ { ImagePremulHWOnlyMatrixCFSrcover(), DrawTypeFlags::kNonAAFillRect,    kBGRA_1_D },
 /* 12 */ { ImagePremulHWOnlyPorterDuffCFSrcover(), DrawTypeFlags::kPerEdgeAAQuad,kBGRA_1_D },
-/* 13 */ { ImagePremulNoCubicSrcover(),        DrawTypeFlags::kAnalyticRRect,    kBGRA_1_D },
+/* 13 */ { ImagePremulHWOnlyAndClampSrcover(), DrawTypeFlags::kAnalyticRRect,    kBGRA_1_D },
 /* 14 */ { ImagePremulNoCubicSrcSrcover(),     kQuadAndNonAARect,                kBGRA_1_D },
 /* 15 */ { LinearGradSmSrcover(),              DrawTypeFlags::kNonAAFillRect,    kBGRA_1_D },
 /* 16 */ { SolidSrcSrcover(),                  DrawTypeFlags::kSimpleShape,      kBGRA_1_D },
@@ -66,7 +66,7 @@
 /* 24 */ { SolidSrcSrcover(),                  kRRectAndNonAARect,               kBGRA_4_D },
 /* 25 */ { ImagePremulHWOnlyDstin(),           DrawTypeFlags::kPerEdgeAAQuad,    kBGRA_4_DS },
 /* 26 */ { ImagePremulHWOnlyMatrixCFSrcover(), DrawTypeFlags::kNonAAFillRect,    kBGRA_4_DS },
-/* 27 */ { ImagePremulNoCubicSrcover(),        kQuadAndNonAARect,                kBGRA_4_DS },
+/* 27 */ { ImagePremulHWOnlyAndClampSrcover(), kQuadAndNonAARect,                kBGRA_4_DS },
 /* 28 */ { SolidClearSrcSrcover(),             DrawTypeFlags::kNonAAFillRect,    kBGRA_4_DS },
 /* 29 */ { SolidSrcover(),                     DrawTypeFlags::kNonSimpleShape,   kBGRA_4_DS },
 /* 30 */ { SolidSrcover(),                     DrawTypeFlags::kAnalyticRRect,    kBGRA_4_DS },
diff --git a/tests/graphite/precompile/PaintOptionsBuilder.cpp b/tests/graphite/precompile/PaintOptionsBuilder.cpp
new file mode 100644
index 0000000..add369a
--- /dev/null
+++ b/tests/graphite/precompile/PaintOptionsBuilder.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2025 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkTypes.h"
+
+#if defined(SK_GRAPHITE)
+
+#include "tests/graphite/precompile/PaintOptionsBuilder.h"
+
+#include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
+#include "include/gpu/graphite/precompile/PrecompileShader.h"
+
+namespace PaintOptionsUtils {
+
+using namespace skgpu::graphite;
+using PrecompileShaders::GradientShaderFlags;
+using PrecompileShaders::ImageShaderFlags;
+using PrecompileShaders::YUVImageShaderFlags;
+
+Builder& Builder::hwImg(ImgColorInfo ci, ImgTileModeOptions tmOptions) {
+    static const SkColorInfo kAlphaInfo(kAlpha_8_SkColorType,
+                                        kUnpremul_SkAlphaType,
+                                        nullptr);
+    static const SkColorInfo kAlphaSRGBInfo(kAlpha_8_SkColorType,
+                                            kUnpremul_SkAlphaType,
+                                            SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
+                                                                  SkNamedGamut::kAdobeRGB));
+    static const SkColorInfo kPremulInfo(kRGBA_8888_SkColorType,
+                                         kPremul_SkAlphaType,
+                                         nullptr);
+    static const SkColorInfo kSRGBInfo(kRGBA_8888_SkColorType,
+                                       kPremul_SkAlphaType,
+                                       SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
+                                                             SkNamedGamut::kAdobeRGB));
+
+    SkSpan<const SkColorInfo> ciSpan;
+    switch (ci) {
+        case kAlpha:     ciSpan = { &kAlphaInfo, 1 };    break;
+        case kAlphaSRGB: ciSpan = { &kAlphaSRGBInfo, 1}; break;
+        case kPremul:    ciSpan = { &kPremulInfo, 1 };   break;
+        case kSRGB:      ciSpan = { &kSRGBInfo, 1 };     break;
+    }
+
+    static const SkTileMode kClampTM  = SkTileMode::kClamp;
+    static const SkTileMode kRepeatTM = SkTileMode::kRepeat;
+
+    SkSpan<const SkTileMode> tmSpan;
+    switch (tmOptions) {
+        case kNone:                               break;
+        case kClamp:  tmSpan = { &kClampTM,  1 }; break;
+        case kRepeat: tmSpan = { &kRepeatTM, 1 }; break;
+    }
+
+    sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
+                                                           ciSpan,
+                                                           tmSpan);
+    fPaintOptions.setShaders({ std::move(img) });
+    return *this;
+}
+
+Builder& Builder::yuv(YUVSamplingOptions options) {
+    static const SkColorInfo kSRGBInfo(kRGBA_8888_SkColorType,
+                                       kPremul_SkAlphaType,
+                                       SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
+                                                             SkNamedGamut::kAdobeRGB));
+
+    YUVImageShaderFlags flags = YUVImageShaderFlags::kNone;
+    switch (options) {
+        case kNoCubic:     flags = YUVImageShaderFlags::kExcludeCubic;           break;
+        case kHWAndShader: flags = YUVImageShaderFlags::kNoCubicNoNonSwizzledHW; break;
+    }
+
+    sk_sp<PrecompileShader> img = PrecompileShaders::YUVImage(flags, { &kSRGBInfo, 1 });
+    fPaintOptions.setShaders({ std::move(img) });
+    return *this;
+}
+
+Builder& Builder::linearGrad(LinearGradientOptions options) {
+    sk_sp<PrecompileShader> gradient;
+
+    if (options == kSmall) {
+        gradient = PrecompileShaders::LinearGradient(GradientShaderFlags::kSmall);
+    } else if (options == kComplex) {
+        gradient = PrecompileShaders::LinearGradient(
+                GradientShaderFlags::kNoLarge,
+                { SkGradientShader::Interpolation::InPremul::kNo,
+                  SkGradientShader::Interpolation::ColorSpace::kSRGB,
+                  SkGradientShader::Interpolation::HueMethod::kShorter });
+    }
+
+    fPaintOptions.setShaders({ std::move(gradient) });
+    return *this;
+}
+
+Builder& Builder::blend() {
+    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
+    sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
+                                                           { &ci, 1 },
+                                                           {});
+    SkBlendMode kBlendModes = SkBlendMode::kPlus;
+    fPaintOptions.setShaders({ PrecompileShaders::Blend({ &kBlendModes, 1 },
+                                                        { std::move(img) },
+                                                        { PrecompileShaders::Color() }) });
+    return *this;
+}
+
+Builder& Builder::matrixCF() {
+    fPaintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
+    return *this;
+}
+
+Builder& Builder::porterDuffCF() {
+    fPaintOptions.setColorFilters({ PrecompileColorFilters::Blend({ SkBlendMode::kSrcOver }) });
+    return *this;
+}
+
+} // namespace PaintOptionsUtils
+
+#endif // SK_GRAPHITE
diff --git a/tests/graphite/precompile/PaintOptionsBuilder.h b/tests/graphite/precompile/PaintOptionsBuilder.h
new file mode 100644
index 0000000..ed1264f
--- /dev/null
+++ b/tests/graphite/precompile/PaintOptionsBuilder.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2025 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef PaintOptionsBuilder_DEFINED
+#define PaintOptionsBuilder_DEFINED
+
+#include "include/gpu/graphite/precompile/PaintOptions.h"
+
+namespace PaintOptionsUtils {
+
+enum ImgColorInfo {
+    kAlpha,
+    kAlphaSRGB,
+    kPremul,
+    kSRGB,
+};
+
+enum ImgTileModeOptions {
+    kNone,
+    kClamp,
+    kRepeat,
+};
+
+// This enum directly maps to YUVImageShaderFlags but, crucially, is more compact.
+enum YUVSamplingOptions {
+    kNoCubic,         // YUVImageShaderFlags::kExcludeCubic
+    kHWAndShader,     // YUVImageShaderFlags::kNoCubicNoNonSwizzledHW
+};
+
+enum LinearGradientOptions {
+    kSmall,
+    kComplex,  // idiosyncratic case - c.f. Builder::linearGrad
+};
+
+// This is a minimal builder object that allows for compact construction of the most common
+// PaintOptions combinations - eliminating a lot of boilerplate.
+class Builder {
+public:
+    Builder() {}
+
+    // Shaders
+    Builder& hwImg(ImgColorInfo ci, ImgTileModeOptions tmOptions = kNone);
+    Builder& yuv(YUVSamplingOptions options);
+    Builder& linearGrad(LinearGradientOptions options);
+    Builder& blend();
+
+    // ColorFilters
+    Builder& matrixCF();
+    Builder& porterDuffCF();
+
+    // Blendmodes
+    Builder& clear()   { return this->addBlendMode(SkBlendMode::kClear);   }
+    Builder& dstIn()   { return this->addBlendMode(SkBlendMode::kDstIn);   }
+    Builder& src()     { return this->addBlendMode(SkBlendMode::kSrc);     }
+    Builder& srcOver() { return this->addBlendMode(SkBlendMode::kSrcOver); }
+
+    // Misc settings
+    Builder& transparent() { fPaintOptions.setPaintColorIsOpaque(false); return *this; }
+    Builder& dither()      { fPaintOptions.setDither(true);              return *this; }
+
+    operator skgpu::graphite::PaintOptions() const { return fPaintOptions; }
+
+private:
+    skgpu::graphite::PaintOptions fPaintOptions;
+
+    Builder& addBlendMode(SkBlendMode bm) {
+        fPaintOptions.addBlendMode(bm);
+        return *this;
+    }
+};
+
+} // namespace PaintOptionsUtils
+
+#endif // PaintOptionsBuilder_DEFINED
diff --git a/tests/graphite/precompile/PrecompileTestUtils.cpp b/tests/graphite/precompile/PrecompileTestUtils.cpp
index c19a85f..f2e5a51 100644
--- a/tests/graphite/precompile/PrecompileTestUtils.cpp
+++ b/tests/graphite/precompile/PrecompileTestUtils.cpp
@@ -19,6 +19,7 @@
 #include "src/gpu/graphite/PrecompileContextPriv.h"
 #include "src/gpu/graphite/RenderPassDesc.h"
 #include "src/gpu/graphite/RendererProvider.h"
+#include "tests/graphite/precompile/PaintOptionsBuilder.h"
 #include "tests/graphite/precompile/PrecompileTestUtils.h"
 #include "tools/graphite/UniqueKeyUtils.h"
 
@@ -33,11 +34,9 @@
 #include <set>
 
 using namespace skgpu::graphite;
-using PrecompileShaders::GradientShaderFlags;
+using namespace PaintOptionsUtils;
 using PrecompileShaders::ImageShaderFlags;
-using PrecompileShaders::YUVImageShaderFlags;
 
-using ::skgpu::graphite::DepthStencilFlags;
 using ::skgpu::graphite::DrawTypeFlags;
 using ::skgpu::graphite::PaintOptions;
 using ::skgpu::graphite::RenderPassProperties;
@@ -45,427 +44,139 @@
 namespace PrecompileTestUtils {
 
 PaintOptions ImagePremulHWOnlyPlusColorSrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                           { &ci, 1 },
-                                                           {});
-    SkBlendMode kBlendModes = SkBlendMode::kPlus;
-    paintOptions.setShaders({ PrecompileShaders::Blend({ &kBlendModes, 1 },
-                                                       { std::move(img) },
-                                                       { PrecompileShaders::Color() }) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().blend().srcOver();
 }
 
 PaintOptions TransparentPaintImagePremulHWOnlyPlusColorSrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                           { &ci, 1 },
-                                                           {});
-    SkBlendMode kBlendModes = SkBlendMode::kPlus;
-    paintOptions.setShaders({ PrecompileShaders::Blend({ &kBlendModes, 1 },
-                                                       { std::move(img) },
-                                                       { PrecompileShaders::Color() }) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    paintOptions.setPaintColorIsOpaque(false);
-    return paintOptions;
+    return Builder().transparent().blend().srcOver();
 }
 
 PaintOptions SolidSrcover() {
-    PaintOptions paintOptions;
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().srcOver();
 }
 
 PaintOptions LinearGradSmSrcover() {
-    PaintOptions paintOptions;
-    paintOptions.setShaders({ PrecompileShaders::LinearGradient(GradientShaderFlags::kSmall) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().linearGrad(kSmall).srcOver();
 }
 
 PaintOptions LinearGradSRGBSmMedDitherSrcover() {
-    PaintOptions paintOptions;
-    paintOptions.setShaders({ PrecompileShaders::LinearGradient(
-            GradientShaderFlags::kNoLarge,
-            { SkGradientShader::Interpolation::InPremul::kNo,
-              SkGradientShader::Interpolation::ColorSpace::kSRGB,
-              SkGradientShader::Interpolation::HueMethod::kShorter }) });
-
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    paintOptions.setDither(true);
-
-    return paintOptions;
+    return Builder().linearGrad(kComplex).dither().srcOver();
 }
 
 PaintOptions TransparentPaintImagePremulHWAndClampSrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    SkTileMode tm = SkTileMode::kClamp;
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       { &tm, 1 }) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    paintOptions.setPaintColorIsOpaque(false);
-    return paintOptions;
+    return Builder().transparent().hwImg(kPremul, kClamp).srcOver();
 }
 
 PaintOptions TransparentPaintImagePremulHWOnlyMatrixCFSrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    paintOptions.setPaintColorIsOpaque(false);
-    return paintOptions;
+    return Builder().transparent().hwImg(kPremul).matrixCF().srcOver();
 }
 
 PaintOptions TransparentPaintImagePremulHWOnlyMatrixCFDitherSrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    paintOptions.setPaintColorIsOpaque(false);
-    paintOptions.setDither(true);
-    return paintOptions;
+    return Builder().transparent().hwImg(kPremul).matrixCF().dither().srcOver();
 }
 
 PaintOptions TransparentPaintImageSRGBHWOnlyMatrixCFDitherSrcover() {
-    SkColorInfo ci { kRGBA_8888_SkColorType,
-                     kPremul_SkAlphaType,
-                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
-
-    PaintOptions paintOptions;
-
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    paintOptions.setPaintColorIsOpaque(false);
-    paintOptions.setDither(true);
-    return paintOptions;
+    return Builder().transparent().hwImg(kSRGB).matrixCF().dither().srcOver();
 }
 
 PaintOptions TransparentPaintImagePremulHWOnlySrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    paintOptions.setPaintColorIsOpaque(false);
-    return paintOptions;
+    return Builder().transparent().hwImg(kPremul).srcOver();
 }
 
 PaintOptions TransparentPaintImageSRGBHWOnlySrcover() {
-    SkColorInfo ci { kRGBA_8888_SkColorType,
-                     kPremul_SkAlphaType,
-                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
-
-    PaintOptions paintOptions;
-
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    paintOptions.setPaintColorIsOpaque(false);
-    return paintOptions;
+    return Builder().transparent().hwImg(kSRGB).srcOver();
 }
 
 PaintOptions TransparentPaintSrcover() {
-    PaintOptions paintOptions;
-
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    paintOptions.setPaintColorIsOpaque(false);
-    return paintOptions;
+    return Builder().transparent().srcOver();
 }
 
 PaintOptions SolidClearSrcSrcover() {
-    PaintOptions paintOptions;
-    paintOptions.setBlendModes({ SkBlendMode::kClear,
-                                 SkBlendMode::kSrc,
-                                 SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().clear().src().srcOver();
 }
 
 PaintOptions SolidSrcSrcover() {
-    PaintOptions paintOptions;
-    paintOptions.setBlendModes({ SkBlendMode::kSrc, SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().src().srcOver();
 }
 
-PaintOptions ImagePremulNoCubicSrcover() {
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    SkTileMode tm = SkTileMode::kClamp;
-    PaintOptions paintOptions;
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       { &tm, 1 }) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+PaintOptions ImagePremulHWOnlyAndClampSrcover() {
+    return Builder().hwImg(kPremul, kClamp).srcOver();
 }
 
 PaintOptions ImagePremulHWOnlySrc() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrc });
-    return paintOptions;
+    return Builder().hwImg(kPremul).src();
 }
 
 PaintOptions ImagePremulHWOnlySrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().hwImg(kPremul).srcOver();
 }
 
 PaintOptions ImagePremulClampNoCubicDstin() {
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    SkTileMode tm = SkTileMode::kClamp;
-    PaintOptions paintOptions;
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       { &tm, 1}) });
-    paintOptions.setBlendModes({ SkBlendMode::kDstIn });
-    return paintOptions;
+    return Builder().hwImg(kPremul, kClamp).dstIn();
 }
 
 PaintOptions ImagePremulHWOnlyDstin() {
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    PaintOptions paintOptions;
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setBlendModes({ SkBlendMode::kDstIn });
-    return paintOptions;
+    return Builder().hwImg(kPremul).dstIn();
 }
 
 PaintOptions YUVImageSRGBNoCubicSrcover() {
-    SkColorInfo ci { kRGBA_8888_SkColorType,
-                     kPremul_SkAlphaType,
-                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
-
-    PaintOptions paintOptions;
-    paintOptions.setShaders({ PrecompileShaders::YUVImage(YUVImageShaderFlags::kExcludeCubic,
-                                                          { &ci, 1 }) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().yuv(kNoCubic).srcOver();
 }
 
 PaintOptions YUVImageSRGBSrcover() {
-    SkColorInfo ci { kRGBA_8888_SkColorType,
-                     kPremul_SkAlphaType,
-                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
-
-    PaintOptions paintOptions;
-    paintOptions.setShaders({ PrecompileShaders::YUVImage(
-                                                YUVImageShaderFlags::kNoCubicNoNonSwizzledHW,
-                                                { &ci, 1 }) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().yuv(kHWAndShader).srcOver();
 }
 
 PaintOptions ImagePremulNoCubicSrcSrcover() {
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    PaintOptions paintOptions;
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrc,
-                                 SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().hwImg(kPremul).src().srcOver();
 }
 
 PaintOptions ImageSRGBNoCubicSrc() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType,
-                     kPremul_SkAlphaType,
-                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
-                                           SkNamedGamut::kAdobeRGB) };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrc });
-    return paintOptions;
+    return Builder().hwImg(kSRGB).src();
 }
 
 PaintOptions ImageAlphaHWOnlySrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kAlpha_8_SkColorType, kUnpremul_SkAlphaType, nullptr };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().hwImg(kAlpha).srcOver();
 }
 
 PaintOptions ImageAlphaPremulHWOnlyMatrixCFSrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kAlpha_8_SkColorType, kUnpremul_SkAlphaType, nullptr };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
-
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().hwImg(kAlpha).matrixCF().srcOver();
 }
 
 PaintOptions ImageAlphaSRGBHWOnlyMatrixCFSrcover() {
-    // Note: this is different from the other SRGB ColorInfos
-    SkColorInfo ci { kAlpha_8_SkColorType,
-                     kUnpremul_SkAlphaType,
-                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
-
-    PaintOptions paintOptions;
-
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
-
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().hwImg(kAlphaSRGB).matrixCF().srcOver();
 }
 
 PaintOptions ImageAlphaNoCubicSrc() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kAlpha_8_SkColorType, kUnpremul_SkAlphaType, nullptr };
-    SkTileMode tm = SkTileMode::kRepeat;
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       { &tm, 1}) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrc });
-    return paintOptions;
+    return Builder().hwImg(kAlpha, kRepeat).src();
 }
 
 PaintOptions ImageAlphaClampNoCubicSrc() {
-    SkColorInfo ci { kAlpha_8_SkColorType, kUnpremul_SkAlphaType, nullptr };
-    SkTileMode tm = SkTileMode::kClamp;
-
-    PaintOptions paintOptions;
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       { &tm, 1 }) });
-    paintOptions.setBlendModes({ SkBlendMode::kSrc });
-    return paintOptions;
+    return Builder().hwImg(kAlpha, kClamp).src();
 }
 
 PaintOptions ImagePremulHWOnlyPorterDuffCFSrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setColorFilters(
-                { PrecompileColorFilters::Blend({ SkBlendMode::kSrcOver }) });
-
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().hwImg(kPremul).porterDuffCF().srcOver();
 }
 
 PaintOptions ImagePremulHWOnlyMatrixCFSrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
-
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().hwImg(kPremul).matrixCF().srcOver();
 }
 
 PaintOptions ImageSRGBHWOnlyMatrixCFSrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType,
-                     kPremul_SkAlphaType,
-                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
-
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
-
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().hwImg(kSRGB).matrixCF().srcOver();
 }
 
 PaintOptions ImagePremulHWOnlyMatrixCFDitherSrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
-
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    paintOptions.setDither(true);
-
-    return paintOptions;
+    return Builder().hwImg(kPremul).matrixCF().dither().srcOver();
 }
 
 PaintOptions ImageSRGBHWOnlyMatrixCFDitherSrcover() {
-    SkColorInfo ci { kRGBA_8888_SkColorType,
-                     kPremul_SkAlphaType,
-                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB) };
-
-    PaintOptions paintOptions;
-
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-    paintOptions.setColorFilters({ PrecompileColorFilters::Matrix() });
-
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    paintOptions.setDither(true);
-
-    return paintOptions;
+    return Builder().hwImg(kSRGB).matrixCF().dither().srcOver();
 }
 
 PaintOptions ImageHWOnlySRGBSrcover() {
-    PaintOptions paintOptions;
-
-    SkColorInfo ci { kRGBA_8888_SkColorType,
-                     kPremul_SkAlphaType,
-                     SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
-                                           SkNamedGamut::kAdobeRGB) };
-    paintOptions.setShaders({ PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
-                                                       { &ci, 1 },
-                                                       {}) });
-
-    paintOptions.setBlendModes({ SkBlendMode::kSrcOver });
-    return paintOptions;
+    return Builder().hwImg(kSRGB).srcOver();
 }
 
 namespace {
diff --git a/tests/graphite/precompile/PrecompileTestUtils.h b/tests/graphite/precompile/PrecompileTestUtils.h
index 8778d31..937132b 100644
--- a/tests/graphite/precompile/PrecompileTestUtils.h
+++ b/tests/graphite/precompile/PrecompileTestUtils.h
@@ -125,7 +125,7 @@
 skgpu::graphite::PaintOptions TransparentPaintSrcover();
 skgpu::graphite::PaintOptions SolidClearSrcSrcover();
 skgpu::graphite::PaintOptions SolidSrcSrcover();
-skgpu::graphite::PaintOptions ImagePremulNoCubicSrcover();
+skgpu::graphite::PaintOptions ImagePremulHWOnlyAndClampSrcover();
 skgpu::graphite::PaintOptions ImagePremulHWOnlySrc();
 skgpu::graphite::PaintOptions ImagePremulHWOnlySrcover();
 skgpu::graphite::PaintOptions ImagePremulClampNoCubicDstin();