diff options
-rw-r--r-- | gm/gradients.cpp | 148 | ||||
-rw-r--r-- | include/core/SkPicture.h | 6 | ||||
-rw-r--r-- | include/effects/SkGradientShader.h | 88 | ||||
-rw-r--r-- | src/core/SkReadBuffer.h | 1 | ||||
-rw-r--r-- | src/effects/gradients/SkGradientShader.cpp | 361 | ||||
-rw-r--r-- | src/effects/gradients/SkGradientShaderPriv.h | 7 | ||||
-rw-r--r-- | src/effects/gradients/SkLinearGradient.cpp | 5 | ||||
-rw-r--r-- | src/effects/gradients/SkRadialGradient.cpp | 5 | ||||
-rw-r--r-- | src/effects/gradients/SkSweepGradient.cpp | 5 | ||||
-rw-r--r-- | src/effects/gradients/SkTwoPointConicalGradient.cpp | 5 |
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); } |