aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/gradients.cpp148
-rw-r--r--include/core/SkPicture.h6
-rw-r--r--include/effects/SkGradientShader.h88
-rw-r--r--src/core/SkReadBuffer.h1
-rw-r--r--src/effects/gradients/SkGradientShader.cpp361
-rw-r--r--src/effects/gradients/SkGradientShaderPriv.h7
-rw-r--r--src/effects/gradients/SkLinearGradient.cpp5
-rw-r--r--src/effects/gradients/SkRadialGradient.cpp5
-rw-r--r--src/effects/gradients/SkSweepGradient.cpp5
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient.cpp5
10 files changed, 489 insertions, 142 deletions
diff --git a/gm/gradients.cpp b/gm/gradients.cpp
index 4a68702559..d563814704 100644
--- a/gm/gradients.cpp
+++ b/gm/gradients.cpp
@@ -12,14 +12,22 @@
namespace skiagm {
struct GradData {
- int fCount;
- const SkColor* fColors;
- const SkScalar* fPos;
+ int fCount;
+ const SkColor* fColors;
+ const SkColor4f* fColors4f;
+ const SkScalar* fPos;
};
constexpr SkColor gColors[] = {
SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
};
+constexpr SkColor4f gColors4f[] ={
+ { 1.0f, 0.0f, 0.0f, 1.0f }, // Red
+ { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
+ { 0.0f, 0.0f, 1.0f, 1.0f }, // Blue
+ { 1.0f, 1.0f, 1.0f, 1.0f }, // White
+ { 0.0f, 0.0f, 0.0f, 1.0f } // Black
+};
constexpr SkScalar gPos0[] = { 0, SK_Scalar1 };
constexpr SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
constexpr SkScalar gPos2[] = {
@@ -30,14 +38,19 @@ constexpr SkScalar gPosClamp[] = {0.0f, 0.0f, 1.0f, 1.0f};
constexpr SkColor gColorClamp[] = {
SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLUE
};
-
+constexpr SkColor4f gColor4fClamp[] ={
+ { 1.0f, 0.0f, 0.0f, 1.0f }, // Red
+ { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
+ { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
+ { 0.0f, 0.0f, 1.0f, 1.0f } // Blue
+};
constexpr GradData gGradData[] = {
- { 2, gColors, nullptr },
- { 2, gColors, gPos0 },
- { 2, gColors, gPos1 },
- { 5, gColors, nullptr },
- { 5, gColors, gPos2 },
- { 4, gColorClamp, gPosClamp }
+ { 2, gColors, gColors4f, nullptr },
+ { 2, gColors, gColors4f, gPos0 },
+ { 2, gColors, gColors4f, gPos1 },
+ { 5, gColors, gColors4f, nullptr },
+ { 5, gColors, gColors4f, gPos2 },
+ { 4, gColorClamp, gColor4fClamp, gPosClamp }
};
static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data,
@@ -46,6 +59,13 @@ static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data,
&localMatrix);
}
+static sk_sp<SkShader> MakeLinear4f(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, const SkMatrix& localMatrix) {
+ auto srgb = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)->makeLinearGamma();
+ return SkGradientShader::MakeLinear(pts, data.fColors4f, srgb, data.fPos, data.fCount, tm, 0,
+ &localMatrix);
+}
+
static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data,
SkShader::TileMode tm, const SkMatrix& localMatrix) {
SkPoint center;
@@ -55,6 +75,16 @@ static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data,
tm, 0, &localMatrix);
}
+static sk_sp<SkShader> MakeRadial4f(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, const SkMatrix& localMatrix) {
+ SkPoint center;
+ center.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ auto srgb = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)->makeLinearGamma();
+ return SkGradientShader::MakeRadial(center, center.fX, data.fColors4f, srgb, data.fPos,
+ data.fCount, tm, 0, &localMatrix);
+}
+
static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data,
SkShader::TileMode, const SkMatrix& localMatrix) {
SkPoint center;
@@ -64,6 +94,16 @@ static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data,
0, &localMatrix);
}
+static sk_sp<SkShader> MakeSweep4f(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode, const SkMatrix& localMatrix) {
+ SkPoint center;
+ center.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ auto srgb = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)->makeLinearGamma();
+ return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors4f, srgb, data.fPos,
+ data.fCount, 0, &localMatrix);
+}
+
static sk_sp<SkShader> Make2Radial(const SkPoint pts[2], const GradData& data,
SkShader::TileMode tm, const SkMatrix& localMatrix) {
SkPoint center0, center1;
@@ -77,8 +117,22 @@ static sk_sp<SkShader> Make2Radial(const SkPoint pts[2], const GradData& data,
0, &localMatrix);
}
+static sk_sp<SkShader> Make2Radial4f(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, const SkMatrix& localMatrix) {
+ SkPoint center0, center1;
+ center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3) / 5),
+ SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1) / 4));
+ auto srgb = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)->makeLinearGamma();
+ return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
+ center0, (pts[1].fX - pts[0].fX) / 2,
+ data.fColors4f, srgb, data.fPos, data.fCount, tm,
+ 0, &localMatrix);
+}
+
static sk_sp<SkShader> Make2Conical(const SkPoint pts[2], const GradData& data,
- SkShader::TileMode tm, const SkMatrix& localMatrix) {
+ SkShader::TileMode tm, const SkMatrix& localMatrix) {
SkPoint center0, center1;
SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
@@ -89,11 +143,27 @@ static sk_sp<SkShader> Make2Conical(const SkPoint pts[2], const GradData& data,
data.fCount, tm, 0, &localMatrix);
}
+static sk_sp<SkShader> Make2Conical4f(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, const SkMatrix& localMatrix) {
+ SkPoint center0, center1;
+ SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
+ SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
+ center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
+ center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
+ auto srgb = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)->makeLinearGamma();
+ return SkGradientShader::MakeTwoPointConical(center1, radius1, center0, radius0,
+ data.fColors4f, srgb, data.fPos,
+ data.fCount, tm, 0, &localMatrix);
+}
+
typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data,
SkShader::TileMode tm, const SkMatrix& localMatrix);
constexpr GradMaker gGradMakers[] = {
MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical
};
+constexpr GradMaker gGradMakers4f[] ={
+ MakeLinear4f, MakeRadial4f, MakeSweep4f, Make2Radial4f, Make2Conical4f
+};
///////////////////////////////////////////////////////////////////////////////
@@ -152,6 +222,62 @@ private:
DEF_GM( return new GradientsGM(true); )
DEF_GM( return new GradientsGM(false); )
+// Like the original gradients GM, but using the SkColor4f shader factories. Should be identical.
+class Gradients4fGM : public GM {
+public:
+ Gradients4fGM(bool dither) : fDither(dither) {
+ this->setBGColor(sk_tool_utils::color_to_565(0xFFDDDDDD));
+ }
+
+protected:
+
+ SkString onShortName() {
+ return SkString(fDither ? "gradients4f" : "gradients4f_nodither");
+ }
+
+ virtual SkISize onISize() { return SkISize::Make(840, 815); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+
+ SkPoint pts[2] ={
+ { 0, 0 },
+ { SkIntToScalar(100), SkIntToScalar(100) }
+ };
+ SkShader::TileMode tm = SkShader::kClamp_TileMode;
+ SkRect r ={ 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setDither(fDither);
+
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
+ canvas->save();
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers4f); j++) {
+ SkMatrix scale = SkMatrix::I();
+
+ if (i == 5) { // if the clamp case
+ scale.setScale(0.5f, 0.5f);
+ scale.postTranslate(25.f, 25.f);
+ }
+
+ paint.setShader(gGradMakers4f[j](pts, gGradData[i], tm, scale));
+ canvas->drawRect(r, paint);
+ canvas->translate(0, SkIntToScalar(120));
+ }
+ canvas->restore();
+ canvas->translate(SkIntToScalar(120), 0);
+ }
+ }
+
+protected:
+ bool fDither;
+
+private:
+ typedef GM INHERITED;
+};
+DEF_GM(return new Gradients4fGM(true); )
+DEF_GM(return new Gradients4fGM(false); )
+
// Based on the original gradient slide, but with perspective applied to the
// gradient shaders' local matrices
class GradientsLocalPerspectiveGM : public GM {
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index c8de7daf84..1dcbcc5b75 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -223,10 +223,11 @@ private:
// V46: Add drawTextRSXform
// V47: Add occluder rect to SkBlurMaskFilter
// V48: Read and write extended SkTextBlobs.
+ // V49: Gradients serialized as SkColor4f + SkColorSpace
// Only SKPs within the min/current picture version range (inclusive) can be read.
static const uint32_t MIN_PICTURE_VERSION = 35; // Produced by Chrome M39.
- static const uint32_t CURRENT_PICTURE_VERSION = 48;
+ static const uint32_t CURRENT_PICTURE_VERSION = 49;
static_assert(MIN_PICTURE_VERSION <= 41,
"Remove kFontFileName and related code from SkFontDescriptor.cpp.");
@@ -240,6 +241,9 @@ private:
static_assert(MIN_PICTURE_VERSION <= 45,
"Remove decoding of old SkTypeface::Style from SkFontDescriptor.cpp.");
+ static_assert(MIN_PICTURE_VERSION <= 48,
+ "Remove legacy gradient deserialization code from SkGradientShader.cpp.");
+
static bool IsValidPictInfo(const SkPictInfo& info);
static sk_sp<SkPicture> Forwardport(const SkPictInfo&,
const SkPictureData*,
diff --git a/include/effects/SkGradientShader.h b/include/effects/SkGradientShader.h
index 6b86f441eb..2fcce75c30 100644
--- a/include/effects/SkGradientShader.h
+++ b/include/effects/SkGradientShader.h
@@ -48,6 +48,28 @@ public:
return MakeLinear(pts, colors, pos, count, mode, 0, NULL);
}
+ /** Returns a shader that generates a linear gradient between the two specified points.
+ <p />
+ @param pts The start and end points for the gradient.
+ @param colors The array[count] of colors, to be distributed between the two points
+ @param pos May be NULL. array[count] of SkScalars, or NULL, of the relative position of
+ each corresponding color in the colors array. If this is NULL,
+ the the colors are distributed evenly between the start and end point.
+ If this is not null, the values must begin with 0, end with 1.0, and
+ intermediate values must be strictly increasing.
+ @param count Must be >=2. The number of colors (and pos if not NULL) entries.
+ @param mode The tiling mode
+ */
+ static sk_sp<SkShader> MakeLinear(const SkPoint pts[2],
+ const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], int count, SkShader::TileMode mode,
+ uint32_t flags, const SkMatrix* localMatrix);
+ static sk_sp<SkShader> MakeLinear(const SkPoint pts[2],
+ const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], int count, SkShader::TileMode mode) {
+ return MakeLinear(pts, colors, std::move(colorSpace), pos, count, mode, 0, NULL);
+ }
+
/** Returns a shader that generates a radial gradient given the center and radius.
<p />
@param center The center of the circle for this gradient
@@ -71,6 +93,29 @@ public:
return MakeRadial(center, radius, colors, pos, count, mode, 0, NULL);
}
+ /** Returns a shader that generates a radial gradient given the center and radius.
+ <p />
+ @param center The center of the circle for this gradient
+ @param radius Must be positive. The radius of the circle for this gradient
+ @param colors The array[count] of colors, to be distributed between the center and edge of the circle
+ @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of
+ each corresponding color in the colors array. If this is NULL,
+ the the colors are distributed evenly between the center and edge of the circle.
+ If this is not null, the values must begin with 0, end with 1.0, and
+ intermediate values must be strictly increasing.
+ @param count Must be >= 2. The number of colors (and pos if not NULL) entries
+ @param mode The tiling mode
+ */
+ static sk_sp<SkShader> MakeRadial(const SkPoint& center, SkScalar radius,
+ const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], int count, SkShader::TileMode mode,
+ uint32_t flags, const SkMatrix* localMatrix);
+ static sk_sp<SkShader> MakeRadial(const SkPoint& center, SkScalar radius,
+ const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], int count, SkShader::TileMode mode) {
+ return MakeRadial(center, radius, colors, std::move(colorSpace), pos, count, mode, 0, NULL);
+ }
+
/**
* Returns a shader that generates a conical gradient given two circles, or
* returns NULL if the inputs are invalid. The gradient interprets the
@@ -90,6 +135,27 @@ public:
0, NULL);
}
+ /**
+ * Returns a shader that generates a conical gradient given two circles, or
+ * returns NULL if the inputs are invalid. The gradient interprets the
+ * two circles according to the following HTML spec.
+ * http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient
+ */
+ static sk_sp<SkShader> MakeTwoPointConical(const SkPoint& start, SkScalar startRadius,
+ const SkPoint& end, SkScalar endRadius,
+ const SkColor4f colors[],
+ sk_sp<SkColorSpace> colorSpace, const SkScalar pos[],
+ int count, SkShader::TileMode mode,
+ uint32_t flags, const SkMatrix* localMatrix);
+ static sk_sp<SkShader> MakeTwoPointConical(const SkPoint& start, SkScalar startRadius,
+ const SkPoint& end, SkScalar endRadius,
+ const SkColor4f colors[],
+ sk_sp<SkColorSpace> colorSpace, const SkScalar pos[],
+ int count, SkShader::TileMode mode) {
+ return MakeTwoPointConical(start, startRadius, end, endRadius, colors,
+ std::move(colorSpace), pos, count, mode, 0, NULL);
+ }
+
/** Returns a shader that generates a sweep gradient given a center.
<p />
@param cx The X coordinate of the center of the sweep
@@ -110,6 +176,28 @@ public:
return MakeSweep(cx, cy, colors, pos, count, 0, NULL);
}
+ /** Returns a shader that generates a sweep gradient given a center.
+ <p />
+ @param cx The X coordinate of the center of the sweep
+ @param cx The Y coordinate of the center of the sweep
+ @param colors The array[count] of colors, to be distributed around the center.
+ @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of
+ each corresponding color in the colors array. If this is NULL,
+ the the colors are distributed evenly between the center and edge of the circle.
+ If this is not null, the values must begin with 0, end with 1.0, and
+ intermediate values must be strictly increasing.
+ @param count Must be >= 2. The number of colors (and pos if not NULL) entries
+ */
+ static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
+ const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], int count,
+ uint32_t flags, const SkMatrix* localMatrix);
+ static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
+ const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], int count) {
+ return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, 0, NULL);
+ }
+
#ifdef SK_SUPPORT_LEGACY_CREATESHADER_PTR
static SkShader* CreateLinear(const SkPoint pts[2],
const SkColor colors[], const SkScalar pos[], int count,
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index d29fef842f..3e6742fde0 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -68,6 +68,7 @@ public:
kAnnotationsMovedToCanvas_Version = 44,
kLightingShaderWritesInvNormRotation = 45,
kBlurMaskFilterWritesOccluder = 47,
+ kGradientShaderFloatColor_Version = 49,
};
/**
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 0faf006d73..df230394ad 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -13,57 +13,134 @@
#include "SkTwoPointConicalGradient.h"
#include "SkSweepGradient.h"
+enum GradientSerializationFlags {
+ // Bits 29:31 used for various boolean flags
+ kHasPosition_GSF = 0x80000000,
+ kHasLocalMatrix_GSF = 0x40000000,
+ kHasColorSpace_GSF = 0x20000000,
+
+ // Bits 12:28 unused
+
+ // Bits 8:11 for fTileMode
+ kTileModeShift_GSF = 8,
+ kTileModeMask_GSF = 0xF,
+
+ // Bits 0:7 for fGradFlags (note that kForce4fContext_PrivateFlag is 0x80)
+ kGradFlagsShift_GSF = 0,
+ kGradFlagsMask_GSF = 0xFF,
+};
+
void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const {
- buffer.writeColorArray(fColors, fCount);
- // TODO: Flatten fColors4f and fColorSpace
+ uint32_t flags = 0;
+ if (fPos) {
+ flags |= kHasPosition_GSF;
+ }
+ if (fLocalMatrix) {
+ flags |= kHasLocalMatrix_GSF;
+ }
+ sk_sp<SkData> colorSpaceData = fColorSpace ? fColorSpace->serialize() : nullptr;
+ if (colorSpaceData) {
+ flags |= kHasColorSpace_GSF;
+ }
+ SkASSERT(static_cast<uint32_t>(fTileMode) <= kTileModeMask_GSF);
+ flags |= (fTileMode << kTileModeShift_GSF);
+ SkASSERT(fGradFlags <= kGradFlagsMask_GSF);
+ flags |= (fGradFlags << kGradFlagsShift_GSF);
+
+ buffer.writeUInt(flags);
+
+ buffer.writeColor4fArray(fColors, fCount);
+ if (colorSpaceData) {
+ buffer.writeDataAsByteArray(colorSpaceData.get());
+ }
if (fPos) {
- buffer.writeBool(true);
buffer.writeScalarArray(fPos, fCount);
- } else {
- buffer.writeBool(false);
}
- buffer.write32(fTileMode);
- buffer.write32(fGradFlags);
if (fLocalMatrix) {
- buffer.writeBool(true);
buffer.writeMatrix(*fLocalMatrix);
- } else {
- buffer.writeBool(false);
}
}
bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) {
- // TODO: Unflatten fColors4f and fColorSpace
- fCount = buffer.getArrayCount();
- if (fCount > kStorageCount) {
- size_t allocSize = (sizeof(SkColor) + sizeof(SkScalar)) * fCount;
- fDynamicStorage.reset(allocSize);
- fColors = (SkColor*)fDynamicStorage.get();
- fPos = (SkScalar*)(fColors + fCount);
- } else {
- fColors = fColorStorage;
- fPos = fPosStorage;
- }
+ if (buffer.isVersionLT(SkReadBuffer::kGradientShaderFloatColor_Version)) {
+ fCount = buffer.getArrayCount();
+ if (fCount > kStorageCount) {
+ size_t allocSize = (sizeof(SkColor4f) + sizeof(SkScalar)) * fCount;
+ fDynamicStorage.reset(allocSize);
+ fColors = (SkColor4f*)fDynamicStorage.get();
+ fPos = (SkScalar*)(fColors + fCount);
+ } else {
+ fColors = fColorStorage;
+ fPos = fPosStorage;
+ }
- if (!buffer.readColorArray(const_cast<SkColor*>(fColors), fCount)) {
- return false;
- }
- if (buffer.readBool()) {
- if (!buffer.readScalarArray(const_cast<SkScalar*>(fPos), fCount)) {
+ // Old gradients serialized SkColor. Read that to a temporary location, then convert.
+ SkSTArray<2, SkColor, true> colors;
+ colors.resize_back(fCount);
+ if (!buffer.readColorArray(colors.begin(), fCount)) {
return false;
}
- } else {
- fPos = nullptr;
- }
+ for (int i = 0; i < fCount; ++i) {
+ mutableColors()[i] = SkColor4f::FromColor(colors[i]);
+ }
+
+ if (buffer.readBool()) {
+ if (!buffer.readScalarArray(const_cast<SkScalar*>(fPos), fCount)) {
+ return false;
+ }
+ } else {
+ fPos = nullptr;
+ }
- fTileMode = (SkShader::TileMode)buffer.read32();
- fGradFlags = buffer.read32();
+ fColorSpace = nullptr;
+ fTileMode = (SkShader::TileMode)buffer.read32();
+ fGradFlags = buffer.read32();
- if (buffer.readBool()) {
- fLocalMatrix = &fLocalMatrixStorage;
- buffer.readMatrix(&fLocalMatrixStorage);
+ if (buffer.readBool()) {
+ fLocalMatrix = &fLocalMatrixStorage;
+ buffer.readMatrix(&fLocalMatrixStorage);
+ } else {
+ fLocalMatrix = nullptr;
+ }
} else {
- fLocalMatrix = nullptr;
+ // New gradient format. Includes floating point color, color space, densely packed flags
+ uint32_t flags = buffer.readUInt();
+
+ fTileMode = (SkShader::TileMode)((flags >> kTileModeShift_GSF) & kTileModeMask_GSF);
+ fGradFlags = (flags >> kGradFlagsShift_GSF) & kGradFlagsMask_GSF;
+
+ fCount = buffer.getArrayCount();
+ if (fCount > kStorageCount) {
+ size_t allocSize = (sizeof(SkColor4f) + sizeof(SkScalar)) * fCount;
+ fDynamicStorage.reset(allocSize);
+ fColors = (SkColor4f*)fDynamicStorage.get();
+ fPos = (SkScalar*)(fColors + fCount);
+ } else {
+ fColors = fColorStorage;
+ fPos = fPosStorage;
+ }
+ if (!buffer.readColor4fArray(mutableColors(), fCount)) {
+ return false;
+ }
+ if (SkToBool(flags & kHasColorSpace_GSF)) {
+ sk_sp<SkData> data = buffer.readByteArrayAsData();
+ fColorSpace = SkColorSpace::Deserialize(data->data(), data->size());
+ } else {
+ fColorSpace = nullptr;
+ }
+ if (SkToBool(flags & kHasPosition_GSF)) {
+ if (!buffer.readScalarArray(mutablePos(), fCount)) {
+ return false;
+ }
+ } else {
+ fPos = nullptr;
+ }
+ if (SkToBool(flags & kHasLocalMatrix_GSF)) {
+ fLocalMatrix = &fLocalMatrixStorage;
+ buffer.readMatrix(&fLocalMatrixStorage);
+ } else {
+ fLocalMatrix = nullptr;
+ }
}
return buffer.isValid();
}
@@ -110,8 +187,7 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatri
if (desc.fPos) {
size += sizeof(SkScalar);
}
- fOrigColors = reinterpret_cast<SkColor*>(
- sk_malloc_throw(size * fColorCount));
+ fOrigColors = reinterpret_cast<SkColor*>(sk_malloc_throw(size * fColorCount));
}
else {
fOrigColors = fStorage;
@@ -119,50 +195,31 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatri
fOrigColors4f = (SkColor4f*)(fOrigColors + fColorCount);
- // We should have been supplied with either fColors *or* (fColors4f and fColorSpace)
- if (desc.fColors) {
- // TODO: Should we support alternate gamma-encoded colorspaces with SkColor inputs?
- SkASSERT(!desc.fColors4f && !desc.fColorSpace);
-
- // Now copy over the colors, adding the dummies as needed
- SkColor* origColors = fOrigColors;
- if (dummyFirst) {
- *origColors++ = desc.fColors[0];
- }
- memcpy(origColors, desc.fColors, desc.fCount * sizeof(SkColor));
- if (dummyLast) {
- origColors += desc.fCount;
- *origColors = desc.fColors[desc.fCount - 1];
- }
+ // Now copy over the colors, adding the dummies as needed
+ SkColor4f* origColors = fOrigColors4f;
+ if (dummyFirst) {
+ *origColors++ = desc.fColors[0];
+ }
+ memcpy(origColors, desc.fColors, desc.fCount * sizeof(SkColor4f));
+ if (dummyLast) {
+ origColors += desc.fCount;
+ *origColors = desc.fColors[desc.fCount - 1];
+ }
- // Convert our SkColor colors to SkColor4f as well
- for (int i = 0; i < fColorCount; ++i) {
- fOrigColors4f[i] = SkColor4f::FromColor(fOrigColors[i]);
- }
+ // Convert our SkColor4f colors to SkColor as well. Note that this is incorrect if the
+ // source colors are not in sRGB gamut. We would need to do a gamut transformation, but
+ // SkColorSpaceXform can't do that (yet). GrColorSpaceXform can, but we may not have GPU
+ // support compiled in here. For the common case (sRGB colors), this does the right thing.
+ for (int i = 0; i < fColorCount; ++i) {
+ fOrigColors[i] = fOrigColors4f[i].toSkColor();
+ }
- // Color space refers to fColors4f, so it's always linear gamma
+ if (!desc.fColorSpace) {
+ // This happens if we were constructed from SkColors, so our colors are really sRGB
fColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named);
} else {
- SkASSERT(desc.fColors4f && desc.fColorSpace && desc.fColorSpace->gammaIsLinear());
-
- // Now copy over the colors, adding the dummies as needed
- SkColor4f* origColors = fOrigColors4f;
- if (dummyFirst) {
- *origColors++ = desc.fColors4f[0];
- }
- memcpy(origColors, desc.fColors4f, desc.fCount * sizeof(SkColor4f));
- if (dummyLast) {
- origColors += desc.fCount;
- *origColors = desc.fColors4f[desc.fCount - 1];
- }
-
- // Convert our SkColor4f colors to SkColor as well. Note that this is incorrect if the
- // source colors are not in sRGB gamut. We would need to do a gamut transformation, but
- // SkColorSpaceXform can't do that (yet). GrColorSpaceXform can, but we may not have GPU
- // support compiled in here.
- for (int i = 0; i < fColorCount; ++i) {
- fOrigColors[i] = fOrigColors4f[i].toSkColor();
- }
+ // The color space refers to the float colors, so it must be linear gamma
+ SkASSERT(desc.fColorSpace->gammaIsLinear());
fColorSpace = desc.fColorSpace;
}
@@ -256,8 +313,7 @@ void SkGradientShaderBase::initCommon() {
void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
Descriptor desc;
- desc.fColors = fOrigColors;
- desc.fColors4f = fOrigColors4f;
+ desc.fColors = fOrigColors4f;
desc.fColorSpace = fColorSpace;
desc.fPos = fOrigPos;
desc.fCount = fColorCount;
@@ -772,18 +828,19 @@ void SkGradientShaderBase::toString(SkString* str) const {
// Return true if these parameters are valid/legal/safe to construct a gradient
//
-static bool valid_grad(const SkColor colors[], const SkScalar pos[], int count, unsigned tileMode) {
+static bool valid_grad(const SkColor4f colors[], const SkScalar pos[], int count,
+ unsigned tileMode) {
return nullptr != colors && count >= 1 && tileMode < (unsigned)SkShader::kTileModeCount;
}
static void desc_init(SkGradientShaderBase::Descriptor* desc,
- const SkColor colors[], const SkScalar pos[], int colorCount,
+ const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], int colorCount,
SkShader::TileMode mode, uint32_t flags, const SkMatrix* localMatrix) {
SkASSERT(colorCount > 1);
desc->fColors = colors;
- desc->fColors4f = nullptr;
- desc->fColorSpace = nullptr; // SkColor is always sRGB
+ desc->fColorSpace = std::move(colorSpace);
desc->fPos = pos;
desc->fCount = colorCount;
desc->fTileMode = mode;
@@ -791,9 +848,9 @@ static void desc_init(SkGradientShaderBase::Descriptor* desc,
desc->fLocalMatrix = localMatrix;
}
-// assumes colors is SkColor* and pos is SkScalar*
+// assumes colors is SkColor4f* and pos is SkScalar*
#define EXPAND_1_COLOR(count) \
- SkColor tmp[2]; \
+ SkColor4f tmp[2]; \
do { \
if (1 == count) { \
tmp[0] = tmp[1] = colors[0]; \
@@ -804,7 +861,7 @@ static void desc_init(SkGradientShaderBase::Descriptor* desc,
} while (0)
struct ColorStopOptimizer {
- ColorStopOptimizer(const SkColor* colors, const SkScalar* pos,
+ ColorStopOptimizer(const SkColor4f* colors, const SkScalar* pos,
int count, SkShader::TileMode mode)
: fColors(colors)
, fPos(pos)
@@ -841,9 +898,19 @@ struct ColorStopOptimizer {
}
}
- const SkColor* fColors;
- const SkScalar* fPos;
- int fCount;
+ const SkColor4f* fColors;
+ const SkScalar* fPos;
+ int fCount;
+};
+
+struct ColorConverter {
+ ColorConverter(const SkColor* colors, int count) {
+ for (int i = 0; i < count; ++i) {
+ fColors4f.push_back(SkColor4f::FromColor(colors[i]));
+ }
+ }
+
+ SkSTArray<2, SkColor4f, true> fColors4f;
};
sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
@@ -852,6 +919,18 @@ sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
SkShader::TileMode mode,
uint32_t flags,
const SkMatrix* localMatrix) {
+ ColorConverter converter(colors, colorCount);
+ return MakeLinear(pts, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, flags,
+ localMatrix);
+}
+
+sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
+ const SkColor4f colors[],
+ sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], int colorCount,
+ SkShader::TileMode mode,
+ uint32_t flags,
+ const SkMatrix* localMatrix) {
if (!pts || !SkScalarIsFinite((pts[1] - pts[0]).length())) {
return nullptr;
}
@@ -859,22 +938,35 @@ sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
return nullptr;
}
if (1 == colorCount) {
- return SkShader::MakeColorShader(colors[0]);
+ return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
}
ColorStopOptimizer opt(colors, pos, colorCount, mode);
SkGradientShaderBase::Descriptor desc;
- desc_init(&desc, opt.fColors, opt.fPos, opt.fCount, mode, flags, localMatrix);
+ desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
+ localMatrix);
return sk_make_sp<SkLinearGradient>(pts, desc);
}
sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
- const SkColor colors[],
- const SkScalar pos[], int colorCount,
- SkShader::TileMode mode,
- uint32_t flags,
- const SkMatrix* localMatrix) {
+ const SkColor colors[],
+ const SkScalar pos[], int colorCount,
+ SkShader::TileMode mode,
+ uint32_t flags,
+ const SkMatrix* localMatrix) {
+ ColorConverter converter(colors, colorCount);
+ return MakeRadial(center, radius, converter.fColors4f.begin(), nullptr, pos, colorCount, mode,
+ flags, localMatrix);
+}
+
+sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
+ const SkColor4f colors[],
+ sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[], int colorCount,
+ SkShader::TileMode mode,
+ uint32_t flags,
+ const SkMatrix* localMatrix) {
if (radius <= 0) {
return nullptr;
}
@@ -882,26 +974,43 @@ sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar rad
return nullptr;
}
if (1 == colorCount) {
- return SkShader::MakeColorShader(colors[0]);
+ return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
}
ColorStopOptimizer opt(colors, pos, colorCount, mode);
SkGradientShaderBase::Descriptor desc;
- desc_init(&desc, opt.fColors, opt.fPos, opt.fCount, mode, flags, localMatrix);
+ desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
+ localMatrix);
return sk_make_sp<SkRadialGradient>(center, radius, desc);
}
sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
- SkScalar startRadius,
- const SkPoint& end,
- SkScalar endRadius,
- const SkColor colors[],
- const SkScalar pos[],
- int colorCount,
- SkShader::TileMode mode,
- uint32_t flags,
- const SkMatrix* localMatrix) {
+ SkScalar startRadius,
+ const SkPoint& end,
+ SkScalar endRadius,
+ const SkColor colors[],
+ const SkScalar pos[],
+ int colorCount,
+ SkShader::TileMode mode,
+ uint32_t flags,
+ const SkMatrix* localMatrix) {
+ ColorConverter converter(colors, colorCount);
+ return MakeTwoPointConical(start, startRadius, end, endRadius, converter.fColors4f.begin(),
+ nullptr, pos, colorCount, mode, flags, localMatrix);
+}
+
+sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
+ SkScalar startRadius,
+ const SkPoint& end,
+ SkScalar endRadius,
+ const SkColor4f colors[],
+ sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[],
+ int colorCount,
+ SkShader::TileMode mode,
+ uint32_t flags,
+ const SkMatrix* localMatrix) {
if (startRadius < 0 || endRadius < 0) {
return nullptr;
}
@@ -922,11 +1031,12 @@ sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
SkGradientShaderBase::Descriptor desc;
if (!flipGradient) {
- desc_init(&desc, opt.fColors, opt.fPos, opt.fCount, mode, flags, localMatrix);
+ desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
+ localMatrix);
return sk_make_sp<SkTwoPointConicalGradient>(start, startRadius, end, endRadius,
flipGradient, desc);
} else {
- SkAutoSTArray<8, SkColor> colorsNew(opt.fCount);
+ SkAutoSTArray<8, SkColor4f> colorsNew(opt.fCount);
SkAutoSTArray<8, SkScalar> posNew(opt.fCount);
for (int i = 0; i < opt.fCount; ++i) {
colorsNew[i] = opt.fColors[opt.fCount - i - 1];
@@ -936,9 +1046,11 @@ sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
for (int i = 0; i < opt.fCount; ++i) {
posNew[i] = 1 - opt.fPos[opt.fCount - i - 1];
}
- desc_init(&desc, colorsNew.get(), posNew.get(), opt.fCount, mode, flags, localMatrix);
+ desc_init(&desc, colorsNew.get(), std::move(colorSpace), posNew.get(), opt.fCount, mode,
+ flags, localMatrix);
} else {
- desc_init(&desc, colorsNew.get(), nullptr, opt.fCount, mode, flags, localMatrix);
+ desc_init(&desc, colorsNew.get(), std::move(colorSpace), nullptr, opt.fCount, mode,
+ flags, localMatrix);
}
return sk_make_sp<SkTwoPointConicalGradient>(end, endRadius, start, startRadius,
@@ -947,16 +1059,28 @@ sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
}
sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
- const SkColor colors[],
- const SkScalar pos[],
- int colorCount,
- uint32_t flags,
- const SkMatrix* localMatrix) {
+ const SkColor colors[],
+ const SkScalar pos[],
+ int colorCount,
+ uint32_t flags,
+ const SkMatrix* localMatrix) {
+ ColorConverter converter(colors, colorCount);
+ return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount, flags,
+ localMatrix);
+}
+
+sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
+ const SkColor4f colors[],
+ sk_sp<SkColorSpace> colorSpace,
+ const SkScalar pos[],
+ int colorCount,
+ uint32_t flags,
+ const SkMatrix* localMatrix) {
if (!valid_grad(colors, pos, colorCount, SkShader::kClamp_TileMode)) {
return nullptr;
}
if (1 == colorCount) {
- return SkShader::MakeColorShader(colors[0]);
+ return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
}
auto mode = SkShader::kClamp_TileMode;
@@ -964,7 +1088,8 @@ sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
ColorStopOptimizer opt(colors, pos, colorCount, mode);
SkGradientShaderBase::Descriptor desc;
- desc_init(&desc, opt.fColors, opt.fPos, opt.fCount, mode, flags, localMatrix);
+ desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
+ localMatrix);
return sk_make_sp<SkSweepGradient>(cx, cy, desc);
}
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 4e6a325c8a..df7ac786f4 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -84,8 +84,7 @@ public:
}
const SkMatrix* fLocalMatrix;
- const SkColor* fColors;
- const SkColor4f* fColors4f;
+ const SkColor4f* fColors;
sk_sp<SkColorSpace> fColorSpace;
const SkScalar* fPos;
int fCount;
@@ -103,14 +102,14 @@ public:
// fColors and fPos always point into local memory, so they can be safely mutated
//
- SkColor* mutableColors() { return const_cast<SkColor*>(fColors); }
+ SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); }
SkScalar* mutablePos() { return const_cast<SkScalar*>(fPos); }
private:
enum {
kStorageCount = 16
};
- SkColor fColorStorage[kStorageCount];
+ SkColor4f fColorStorage[kStorageCount];
SkScalar fPosStorage[kStorageCount];
SkMatrix fLocalMatrixStorage;
SkAutoMalloc fDynamicStorage;
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 4bf5e3cc20..3372499a63 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -63,8 +63,9 @@ sk_sp<SkFlattenable> SkLinearGradient::CreateProc(SkReadBuffer& buffer) {
SkPoint pts[2];
pts[0] = buffer.readPoint();
pts[1] = buffer.readPoint();
- return SkGradientShader::MakeLinear(pts, desc.fColors, desc.fPos, desc.fCount, desc.fTileMode,
- desc.fGradFlags, desc.fLocalMatrix);
+ return SkGradientShader::MakeLinear(pts, desc.fColors, std::move(desc.fColorSpace), desc.fPos,
+ desc.fCount, desc.fTileMode, desc.fGradFlags,
+ desc.fLocalMatrix);
}
void SkLinearGradient::flatten(SkWriteBuffer& buffer) const {
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index 6eaecffedd..15d2da40f2 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -67,8 +67,9 @@ sk_sp<SkFlattenable> SkRadialGradient::CreateProc(SkReadBuffer& buffer) {
}
const SkPoint center = buffer.readPoint();
const SkScalar radius = buffer.readScalar();
- return SkGradientShader::MakeRadial(center, radius, desc.fColors, desc.fPos, desc.fCount,
- desc.fTileMode, desc.fGradFlags, desc.fLocalMatrix);
+ return SkGradientShader::MakeRadial(center, radius, desc.fColors, std::move(desc.fColorSpace),
+ desc.fPos, desc.fCount, desc.fTileMode, desc.fGradFlags,
+ desc.fLocalMatrix);
}
void SkRadialGradient::flatten(SkWriteBuffer& buffer) const {
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 58bb8aa8ed..9ca207a5d5 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -35,8 +35,9 @@ sk_sp<SkFlattenable> SkSweepGradient::CreateProc(SkReadBuffer& buffer) {
return nullptr;
}
const SkPoint center = buffer.readPoint();
- return SkGradientShader::MakeSweep(center.x(), center.y(), desc.fColors, desc.fPos,
- desc.fCount, desc.fGradFlags, desc.fLocalMatrix);
+ return SkGradientShader::MakeSweep(center.x(), center.y(), desc.fColors,
+ std::move(desc.fColorSpace), desc.fPos, desc.fCount,
+ desc.fGradFlags, desc.fLocalMatrix);
}
void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index 8e3671b1f9..fd48a62679 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -318,7 +318,7 @@ sk_sp<SkFlattenable> SkTwoPointConicalGradient::CreateProc(SkReadBuffer& buffer)
SkTSwap(c1, c2);
SkTSwap(r1, r2);
- SkColor* colors = desc.mutableColors();
+ SkColor4f* colors = desc.mutableColors();
SkScalar* pos = desc.mutablePos();
const int last = desc.fCount - 1;
const int half = desc.fCount >> 1;
@@ -337,7 +337,8 @@ sk_sp<SkFlattenable> SkTwoPointConicalGradient::CreateProc(SkReadBuffer& buffer)
}
}
- return SkGradientShader::MakeTwoPointConical(c1, r1, c2, r2, desc.fColors, desc.fPos,
+ return SkGradientShader::MakeTwoPointConical(c1, r1, c2, r2, desc.fColors,
+ std::move(desc.fColorSpace), desc.fPos,
desc.fCount, desc.fTileMode, desc.fGradFlags,
desc.fLocalMatrix);
}