Merge changes I468fe3ef,I7632c4af into main

* changes:
  Fix colorspace transform with multitexture color text.
  [ganesh] Add colorspace conversion for color emoji
diff --git a/src/gpu/ganesh/effects/GrAtlasedShaderHelpers.h b/src/gpu/ganesh/effects/GrAtlasedShaderHelpers.h
index 2a2fce7..1e9ae1b 100644
--- a/src/gpu/ganesh/effects/GrAtlasedShaderHelpers.h
+++ b/src/gpu/ganesh/effects/GrAtlasedShaderHelpers.h
@@ -90,11 +90,13 @@
     // conditionally load from the indexed texture sampler
     for (int i = 0; i < numTextureSamplers-1; ++i) {
         args.fFragBuilder->codeAppendf("if (%s == %d) { %s = ", texIdx.fsIn(), i, colorName);
-        args.fFragBuilder->appendTextureLookup(args.fTexSamplers[i], coordName);
+        args.fFragBuilder->appendTextureLookup(args.fTexSamplers[i],
+                                               coordName);
         args.fFragBuilder->codeAppend("; } else ");
     }
     args.fFragBuilder->codeAppendf("{ %s = ", colorName);
-    args.fFragBuilder->appendTextureLookup(args.fTexSamplers[numTextureSamplers - 1], coordName);
+    args.fFragBuilder->appendTextureLookup(args.fTexSamplers[numTextureSamplers - 1],
+                                           coordName);
     args.fFragBuilder->codeAppend("; }");
 }
 
diff --git a/src/gpu/ganesh/effects/GrBitmapTextGeoProc.cpp b/src/gpu/ganesh/effects/GrBitmapTextGeoProc.cpp
index 59e4870..4168152 100644
--- a/src/gpu/ganesh/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/ganesh/effects/GrBitmapTextGeoProc.cpp
@@ -12,6 +12,7 @@
 #include "src/gpu/ganesh/GrShaderCaps.h"
 #include "src/gpu/ganesh/GrTexture.h"
 #include "src/gpu/ganesh/effects/GrAtlasedShaderHelpers.h"
+#include "src/gpu/ganesh/glsl/GrGLSLColorSpaceXformHelper.h"
 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
@@ -42,6 +43,7 @@
         }
 
         SetTransform(pdman, shaderCaps, fLocalMatrixUniform, btgp.fLocalMatrix, &fLocalMatrix);
+        fColorSpaceXformHelper.setData(pdman, btgp.fColorSpaceXform.get());
     }
 
 private:
@@ -52,6 +54,9 @@
         GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
         GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
 
+        fColorSpaceXformHelper.emitCode(uniformHandler,
+                                        btgp.fColorSpaceXform.get());
+
         // emit attributes
         varyingHandler->emitAttributes(btgp);
 
@@ -91,6 +96,11 @@
         fragBuilder->codeAppend("half4 texColor;");
         append_multitexture_lookup(args, btgp.numTextureSamplers(),
                                    texIdx, uv.fsIn(), "texColor");
+        if (!fColorSpaceXformHelper.isNoop()) {
+            fragBuilder->codeAppend("texColor = ");
+            fragBuilder->appendColorGamutXform("texColor", &fColorSpaceXformHelper);
+            fragBuilder->codeAppend(";");
+        }
 
         if (btgp.fMaskFormat == MaskFormat::kARGB) {
             // modulate by color
@@ -109,6 +119,8 @@
     UniformHandle fColorUniform;
     UniformHandle fAtlasDimensionsInvUniform;
     UniformHandle fLocalMatrixUniform;
+
+    GrGLSLColorSpaceXformHelper fColorSpaceXformHelper;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -116,6 +128,7 @@
 GrBitmapTextGeoProc::GrBitmapTextGeoProc(const GrShaderCaps& caps,
                                          const SkPMColor4f& color,
                                          bool wideColor,
+                                         sk_sp<GrColorSpaceXform> colorSpaceXform,
                                          const GrSurfaceProxyView* views,
                                          int numActiveViews,
                                          GrSamplerState params,
@@ -124,6 +137,7 @@
                                          bool usesW)
         : INHERITED(kGrBitmapTextGeoProc_ClassID)
         , fColor(color)
+        , fColorSpaceXform(std::move(colorSpaceXform))
         , fLocalMatrix(localMatrix)
         , fUsesW(usesW)
         , fMaskFormat(format) {
@@ -187,6 +201,7 @@
                ProgramImpl::ComputeMatrixKey(caps, fLocalMatrix),
                "localMatrixType");
     b->add32(this->numTextureSamplers(), "numTextures");
+    b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get()), "colorSpaceXform");
 }
 
 std::unique_ptr<GrGeometryProcessor::ProgramImpl> GrBitmapTextGeoProc::makeProgramImpl(
@@ -229,7 +244,7 @@
     bool usesW = d->fRandom->nextBool();
     return GrBitmapTextGeoProc::Make(d->allocator(), *d->caps()->shaderCaps(),
                                      SkPMColor4f::FromBytes_RGBA(color),
-                                     wideColor,
+                                     wideColor, /*colorSpaceXform=*/nullptr,
                                      &view, 1, samplerState, format,
                                      localMatrix, usesW);
 }
diff --git a/src/gpu/ganesh/effects/GrBitmapTextGeoProc.h b/src/gpu/ganesh/effects/GrBitmapTextGeoProc.h
index b406da3..a0cfcad 100644
--- a/src/gpu/ganesh/effects/GrBitmapTextGeoProc.h
+++ b/src/gpu/ganesh/effects/GrBitmapTextGeoProc.h
@@ -8,12 +8,16 @@
 #ifndef GrBitmapTextGeoProc_DEFINED
 #define GrBitmapTextGeoProc_DEFINED
 
+#include "include/core/SkRefCnt.h"
 #include "src/base/SkArenaAlloc.h"
 #include "src/gpu/AtlasTypes.h"
+#include "src/gpu/ganesh/GrColorSpaceXform.h"
 #include "src/gpu/ganesh/GrGeometryProcessor.h"
 #include "src/gpu/ganesh/GrProcessor.h"
 #include "src/gpu/ganesh/GrProcessorUnitTest.h"
 
+#include <utility>
+
 class GrGLBitmapTextGeoProc;
 class GrInvariantOutput;
 class GrSurfaceProxyView;
@@ -31,6 +35,7 @@
                                      const GrShaderCaps& caps,
                                      const SkPMColor4f& color,
                                      bool wideColor,
+                                     sk_sp<GrColorSpaceXform> colorSpaceXform,
                                      const GrSurfaceProxyView* views,
                                      int numActiveViews,
                                      GrSamplerState p,
@@ -38,7 +43,8 @@
                                      const SkMatrix& localMatrix,
                                      bool usesW) {
         return arena->make([&](void* ptr) {
-            return new (ptr) GrBitmapTextGeoProc(caps, color, wideColor, views, numActiveViews,
+            return new (ptr) GrBitmapTextGeoProc(caps, color, wideColor, std::move(colorSpaceXform),
+                                                 views, numActiveViews,
                                                  p, format, localMatrix, usesW);
         });
     }
@@ -57,6 +63,7 @@
     class Impl;
 
     GrBitmapTextGeoProc(const GrShaderCaps&, const SkPMColor4f&, bool wideColor,
+                        sk_sp<GrColorSpaceXform> colorSpaceXform,
                         const GrSurfaceProxyView* views, int numViews, GrSamplerState params,
                         skgpu::MaskFormat format, const SkMatrix& localMatrix, bool usesW);
 
@@ -64,15 +71,16 @@
 
     const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
 
-    SkPMColor4f      fColor;
-    SkMatrix         fLocalMatrix;
-    bool             fUsesW;
-    SkISize          fAtlasDimensions;  // dimensions for all textures used with fTextureSamplers[].
-    TextureSampler   fTextureSamplers[kMaxTextures];
-    Attribute        fInPosition;
-    Attribute        fInColor;
-    Attribute        fInTextureCoords;
-    skgpu::MaskFormat     fMaskFormat;
+    SkPMColor4f              fColor;
+    sk_sp<GrColorSpaceXform> fColorSpaceXform;
+    SkMatrix                 fLocalMatrix;
+    bool                     fUsesW;
+    SkISize                  fAtlasDimensions;  // dims for all textures used with fTextureSamplers
+    TextureSampler           fTextureSamplers[kMaxTextures];
+    Attribute                fInPosition;
+    Attribute                fInColor;
+    Attribute                fInTextureCoords;
+    skgpu::MaskFormat        fMaskFormat;
 
     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
 
diff --git a/src/gpu/ganesh/ops/AtlasTextOp.cpp b/src/gpu/ganesh/ops/AtlasTextOp.cpp
index ae222ad..3e6a7c2 100644
--- a/src/gpu/ganesh/ops/AtlasTextOp.cpp
+++ b/src/gpu/ganesh/ops/AtlasTextOp.cpp
@@ -15,6 +15,7 @@
 #include "src/core/SkMatrixProvider.h"
 #include "src/core/SkStrikeCache.h"
 #include "src/gpu/ganesh/GrCaps.h"
+#include "src/gpu/ganesh/GrColorSpaceXform.h"
 #include "src/gpu/ganesh/GrMemoryPool.h"
 #include "src/gpu/ganesh/GrOpFlushState.h"
 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
@@ -70,6 +71,7 @@
                          int glyphCount,
                          SkRect deviceRect,
                          Geometry* geo,
+                         const GrColorInfo& dstColorInfo,
                          GrPaint&& paint)
         : INHERITED{ClassID()}
         , fProcessors(std::move(paint))
@@ -85,6 +87,10 @@
     // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds
     // we treat this as a set of non-AA rects rendered with a texture.
     this->setBounds(deviceRect, HasAABloat::kNo, IsHairline::kNo);
+    if (maskType == MaskType::kColorBitmap) {
+        // We assume that color emoji use the sRGB colorspace
+        fColorSpaceXform = dstColorInfo.refColorSpaceXformFromSRGB();
+    }
 }
 
 AtlasTextOp::AtlasTextOp(MaskType maskType,
@@ -259,7 +265,8 @@
         // color, so we can use the first's without worry.
         flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
                 target->allocator(), *target->caps().shaderCaps(), fHead->fColor,
-                false, views, numActiveViews, filter, maskFormat, localMatrix, fHasPerspective);
+                /*wideColor=*/false, fColorSpaceXform, views, numActiveViews, filter,
+                maskFormat, localMatrix, fHasPerspective);
     }
 
     const int vertexStride = (int)flushInfo.fGeometryProcessor->vertexStride();
diff --git a/src/gpu/ganesh/ops/AtlasTextOp.h b/src/gpu/ganesh/ops/AtlasTextOp.h
index 1f73e70..964afa5 100644
--- a/src/gpu/ganesh/ops/AtlasTextOp.h
+++ b/src/gpu/ganesh/ops/AtlasTextOp.h
@@ -9,6 +9,7 @@
 #define skgpu_ganesh_AtlasTextOp_DEFINED
 
 #include "src/gpu/AtlasTypes.h"
+#include "src/gpu/ganesh/GrColorSpaceXform.h"
 #include "src/gpu/ganesh/effects/GrDistanceFieldGeoProc.h"
 #include "src/gpu/ganesh/ops/GrMeshDrawOp.h"
 #include "src/text/gpu/TextBlob.h"
@@ -132,6 +133,7 @@
                 int glyphCount,
                 SkRect deviceRect,
                 Geometry* geo,
+                const GrColorInfo& dstColorInfo,
                 GrPaint&& paint);
 
     AtlasTextOp(MaskType maskType,
@@ -254,6 +256,9 @@
     static_assert(kInvalid_DistanceFieldEffectFlag <= (1 << 9), "DFGP Flags do not fit in 10 bits");
 #endif
 
+    // Only needed for color emoji
+    sk_sp<GrColorSpaceXform> fColorSpaceXform;
+
     // Only used for distance fields; per-channel luminance for LCD, or gamma-corrected luminance
     // for single-channel distance fields.
     const SkColor fLuminanceColor{0};
diff --git a/src/gpu/ganesh/ops/SmallPathRenderer.cpp b/src/gpu/ganesh/ops/SmallPathRenderer.cpp
index 4245160..faf09b3 100644
--- a/src/gpu/ganesh/ops/SmallPathRenderer.cpp
+++ b/src/gpu/ganesh/ops/SmallPathRenderer.cpp
@@ -193,8 +193,8 @@
         } else {
             flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
                     target->allocator(), *target->caps().shaderCaps(), this->color(), fWideColor,
-                    views, numActiveProxies, GrSamplerState::Filter::kNearest,
-                    MaskFormat::kA8, invert, false);
+                    /*colorSpaceXform=*/nullptr, views, numActiveProxies,
+                    GrSamplerState::Filter::kNearest, MaskFormat::kA8, invert, false);
         }
 
         // allocate vertices
diff --git a/src/text/gpu/SubRunContainer.cpp b/src/text/gpu/SubRunContainer.cpp
index d99bf17..981ddd8 100644
--- a/src/text/gpu/SubRunContainer.cpp
+++ b/src/text/gpu/SubRunContainer.cpp
@@ -1461,6 +1461,7 @@
                                              this->glyphCount(),
                                              subRunDeviceBounds,
                                              geometry,
+                                             sdc->colorInfo(),
                                              std::move(grPaint));
     return {clip, std::move(op)};
 }
@@ -1803,6 +1804,7 @@
                                                  this->glyphCount(),
                                                  this->deviceRect(positionMatrix),
                                                  geometry,
+                                                 sdc->colorInfo(),
                                                  std::move(grPaint));
         return {clip, std::move(op)};
     }