Flutter Engine
The Flutter Engine
Public Types | Public Member Functions | Public Attributes | List of all members
SkColor4fXformer Struct Reference

#include <SkGradientBaseShader.h>

Public Types

using ColorStorage = skia_private::STArray< 4, SkPMColor4f >
 
using PositionStorage = skia_private::STArray< 4, float >
 

Public Member Functions

 SkColor4fXformer (const SkGradientBaseShader *shader, SkColorSpace *dst, bool forceExplicitPositions=false)
 

Public Attributes

ColorStorage fColors
 
PositionStorage fPositionStorage
 
float * fPositions
 
sk_sp< SkColorSpacefIntermediateColorSpace
 

Detailed Description

Definition at line 173 of file SkGradientBaseShader.h.

Member Typedef Documentation

◆ ColorStorage

Definition at line 178 of file SkGradientBaseShader.h.

◆ PositionStorage

Definition at line 179 of file SkGradientBaseShader.h.

Constructor & Destructor Documentation

◆ SkColor4fXformer()

SkColor4fXformer::SkColor4fXformer ( const SkGradientBaseShader shader,
SkColorSpace dst,
bool  forceExplicitPositions = false 
)

Definition at line 783 of file SkGradientBaseShader.cpp.

785 {
788
789 int colorCount = shader->fColorCount;
790 const SkGradientShader::Interpolation interpolation = shader->fInterpolation;
791
792 // 0) Copy the shader's position pointer. Certain interpolation modes might force us to add
793 // new stops, in which case we'll allocate & edit the positions.
794 fPositions = shader->fPositions;
795
796 // 1) Determine the color space of our intermediate colors.
798
799 // 2) Convert all colors to the intermediate color space
801
802 auto dstInfo = info.makeColorSpace(fIntermediateColorSpace);
803 auto srcInfo = info.makeColorSpace(shader->fColorSpace);
804
805 fColors.reset(colorCount);
807 fColors.begin(),
808 info.minRowBytes(),
809 srcInfo,
810 shader->fColors,
811 info.minRowBytes()));
812
813 // 3) Transform to the interpolation color space (if it's special)
814 ConvertColorProc convertFn = nullptr;
815 switch (interpolation.fColorSpace) {
816 case ColorSpace::kHSL: convertFn = srgb_to_hsl; break;
817 case ColorSpace::kHWB: convertFn = srgb_to_hwb; break;
818 case ColorSpace::kLab: convertFn = xyzd50_to_lab; break;
819 case ColorSpace::kLCH: convertFn = xyzd50_to_hcl; break;
820 case ColorSpace::kOKLab: convertFn = lin_srgb_to_oklab; break;
821 case ColorSpace::kOKLabGamutMap: convertFn = lin_srgb_to_oklab; break;
822 case ColorSpace::kOKLCH: convertFn = lin_srgb_to_okhcl; break;
823 case ColorSpace::kOKLCHGamutMap: convertFn = lin_srgb_to_okhcl; break;
824 default: break;
825 }
826
827 skia_private::STArray<4, bool> hueIsPowerless;
828 bool anyPowerlessHue = false;
829 hueIsPowerless.push_back_n(colorCount, false);
830 if (convertFn) {
831 for (int i = 0; i < colorCount; ++i) {
832 fColors[i] = convertFn(fColors[i], hueIsPowerless.data() + i);
833 anyPowerlessHue = anyPowerlessHue || hueIsPowerless[i];
834 }
835 }
836
837 if (anyPowerlessHue) {
838 // In theory, if we knew we were just going to adjust the existing colors (without adding
839 // new ones), we could do it all in-place. To keep things simple, we always generate the
840 // new colors in separate storage.
841 ColorStorage newColors;
842 PositionStorage newPositions;
843
844 for (int i = 0; i < colorCount; ++i) {
845 const SkPMColor4f& curColor = fColors[i];
846 float curPos = shader->getPos(i);
847
848 if (!hueIsPowerless[i]) {
849 newColors.push_back(curColor);
850 newPositions.push_back(curPos);
851 continue;
852 }
853
854 auto colorWithHueFrom = [](const SkPMColor4f& color, const SkPMColor4f& hueColor) {
855 // If we have any powerless hue, then all colors are already in (some) polar space,
856 // and they all store their hue in the red channel.
857 return SkPMColor4f{hueColor.fR, color.fG, color.fB, color.fA};
858 };
859
860 // In each case, we might be copying a powerless (invalid) hue from the neighbor, but
861 // that should be fine, as it will match that neighbor perfectly, and any hue is ok.
862 if (i != 0) {
863 newPositions.push_back(curPos);
864 newColors.push_back(colorWithHueFrom(curColor, fColors[i - 1]));
865 }
866 if (i != colorCount - 1) {
867 newPositions.push_back(curPos);
868 newColors.push_back(colorWithHueFrom(curColor, fColors[i + 1]));
869 }
870 }
871
872 fColors.swap(newColors);
873 fPositionStorage.swap(newPositions);
875 colorCount = fColors.size();
876 }
877
878 // 4) For polar colors, adjust hue values to respect the hue method. We're using a trick here...
879 // The specification looks at adjacent colors, and adjusts one or the other. Because we store
880 // the stops in uniforms (and our backend conversions normalize the hue angle), we can
881 // instead always apply the adjustment to the *second* color. That lets us keep a running
882 // total, and do a single pass across all the colors to respect the requested hue method,
883 // without needing to do any extra work per-pixel.
884 if (color_space_is_polar(interpolation.fColorSpace)) {
885 float delta = 0;
886 for (int i = 0; i < colorCount - 1; ++i) {
887 float h1 = fColors[i].fR;
888 float& h2 = fColors[i + 1].fR;
889 h2 += delta;
890 switch (interpolation.fHueMethod) {
891 case HueMethod::kShorter:
892 if (h2 - h1 > 180) {
893 h2 -= 360; // i.e. h1 += 360
894 delta -= 360;
895 } else if (h2 - h1 < -180) {
896 h2 += 360;
897 delta += 360;
898 }
899 break;
900 case HueMethod::kLonger:
901 if ((i == 0 && shader->fFirstStopIsImplicit) ||
902 (i == colorCount - 2 && shader->fLastStopIsImplicit)) {
903 // Do nothing. We don't want to introduce a full revolution for these stops
904 // Full rationale at skbug.com/13941
905 } else if (0 < h2 - h1 && h2 - h1 < 180) {
906 h2 -= 360; // i.e. h1 += 360
907 delta -= 360;
908 } else if (-180 < h2 - h1 && h2 - h1 <= 0) {
909 h2 += 360;
910 delta += 360;
911 }
912 break;
913 case HueMethod::kIncreasing:
914 if (h2 < h1) {
915 h2 += 360;
916 delta += 360;
917 }
918 break;
919 case HueMethod::kDecreasing:
920 if (h1 < h2) {
921 h2 -= 360; // i.e. h1 += 360;
922 delta -= 360;
923 }
924 break;
925 }
926 }
927 }
928
929 // 5) Apply premultiplication
930 PremulColorProc premulFn = nullptr;
931 if (static_cast<bool>(interpolation.fInPremul)) {
932 switch (interpolation.fColorSpace) {
933 case ColorSpace::kHSL:
934 case ColorSpace::kHWB:
935 case ColorSpace::kLCH:
936 case ColorSpace::kOKLCH:
937 premulFn = premul_polar;
938 break;
939 default:
940 premulFn = premul_rgb;
941 break;
942 }
943 }
944
945 if (premulFn) {
946 for (int i = 0; i < colorCount; ++i) {
947 fColors[i] = premulFn(fColors[i]);
948 }
949 }
950
951 // Ganesh requires that the positions be explicit (rather than implicitly evenly spaced)
952 if (forceExplicitPositions && !fPositions) {
954 float posScale = 1.0f / (colorCount - 1);
955 for (int i = 0; i < colorCount; i++) {
956 fPositionStorage.push_back(i * posScale);
957 }
959 }
960}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
kUnpremul_SkAlphaType
@ kRGBA_F32_SkColorType
pixel using C float for red, green, blue, alpha; in 128-bit word
Definition: SkColorType.h:40
bool SkConvertPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRB, const SkImageInfo &srcInfo, const void *srcPixels, size_t srcRB)
static SkPMColor4f srgb_to_hwb(SkPMColor4f rgb, bool *hueIsPowerless)
static SkPMColor4f lin_srgb_to_okhcl(SkPMColor4f rgb, bool *hueIsPowerless)
static SkPMColor4f xyzd50_to_lab(SkPMColor4f xyz, bool *)
SkPMColor4f(*)(SkPMColor4f, bool *) ConvertColorProc
static SkPMColor4f srgb_to_hsl(SkPMColor4f rgb, bool *hueIsPowerless)
static bool color_space_is_polar(SkGradientShader::Interpolation::ColorSpace cs)
SkPMColor4f(*)(SkPMColor4f) PremulColorProc
static SkPMColor4f xyzd50_to_hcl(SkPMColor4f xyz, bool *hueIsPowerless)
static SkPMColor4f premul_polar(SkPMColor4f hsl)
static SkPMColor4f premul_rgb(SkPMColor4f rgb)
static SkPMColor4f lin_srgb_to_oklab(SkPMColor4f rgb, bool *)
static sk_sp< SkColorSpace > intermediate_color_space(SkGradientShader::Interpolation::ColorSpace cs, SkColorSpace *dst)
SkScalar getPos(int i) const
sk_sp< SkColorSpace > fColorSpace
T * push_back_n(int n)
Definition: SkTArray.h:267
void reset(int n)
Definition: SkTArray.h:144
int size() const
Definition: SkTArray.h:421
void swap(TArray &that)
Definition: SkTArray.h:358
void reserve_exact(int n)
Definition: SkTArray.h:181
DlColor color
ColorSpace
Definition: image.h:16
dst
Definition: cp.py:12
skia_private::STArray< 4, SkPMColor4f > ColorStorage
PositionStorage fPositionStorage
sk_sp< SkColorSpace > fIntermediateColorSpace
skia_private::STArray< 4, float > PositionStorage
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
float fR
red component
Definition: SkColor.h:263

Member Data Documentation

◆ fColors

ColorStorage SkColor4fXformer::fColors

Definition at line 181 of file SkGradientBaseShader.h.

◆ fIntermediateColorSpace

sk_sp<SkColorSpace> SkColor4fXformer::fIntermediateColorSpace

Definition at line 184 of file SkGradientBaseShader.h.

◆ fPositions

float* SkColor4fXformer::fPositions

Definition at line 183 of file SkGradientBaseShader.h.

◆ fPositionStorage

PositionStorage SkColor4fXformer::fPositionStorage

Definition at line 182 of file SkGradientBaseShader.h.


The documentation for this struct was generated from the following files: