Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(212)

Unified Diff: src/effects/gradients/SkGradientShader.cpp

Issue 2370063002: Gradients are serialized (and can be constructed) as SkColor4f + SkColorSpace (Closed)
Patch Set: Widen storage for flags. Shift used bits to be contiguous. Document layout. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkReadBuffer.h ('k') | src/effects/gradients/SkGradientShaderPriv.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/effects/gradients/SkGradientShader.cpp
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 0faf006d73b9de01f7d363be6114a3b48876c33b..df230394ad3aa0e56e600a4a0a92926de243826b 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);
}
« no previous file with comments | « src/core/SkReadBuffer.h ('k') | src/effects/gradients/SkGradientShaderPriv.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698