Just a refactor - reimplements the shader xforms with makeColorSpace().
11 gms have diffs. Some are down to floating precision. The old
implementation would go float->fixed->float in some cases. Others
are due to improvements with gradient shaders inside local matrix
shaders.
Bug: skia:6516
Change-Id: I424406990c5c58a47833cf4c9ef146cd3ea6c37e
Reviewed-on: https://skia-review.googlesource.com/13769
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Matt Sarett <msarett@google.com>
class SkArenaAlloc;
class SkColorFilter;
class SkColorSpace;
+class SkColorSpaceXformer;
class SkImage;
class SkPath;
class SkPicture;
const SkMatrix&, const SkPaint&,
const SkMatrix* /*local matrix*/) const;
+ /**
+ * Returns a shader transformed into a new color space via the |xformer|.
+ */
+ sk_sp<SkShader> makeColorSpace(SkColorSpaceXformer* xformer) const {
+ return this->onMakeColorSpace(xformer);
+ }
+ virtual sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer*) const {
+ return sk_ref_sp(const_cast<SkShader*>(this));
+ }
+
private:
// This is essentially const, but not officially so it can be modified in
// constructors.
// So the SkLocalMatrixShader can whack fLocalMatrix in its SkReadBuffer constructor.
friend class SkLocalMatrixShader;
friend class SkBitmapProcLegacyShader; // for computeTotalInverse()
+ friend class SkComposeShader;
+ friend class SkColorSpaceXformer;
typedef SkFlattenable INHERITED;
};
}
#endif
+sk_sp<SkShader> SkColor4Shader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
+ return SkShader::MakeColorShader(xformer->apply(fCachedByteColor));
+}
+
sk_sp<SkShader> SkShader::MakeColorShader(const SkColor4f& color, sk_sp<SkColorSpace> space) {
if (!SkScalarsAreFinite(color.vec(), 4)) {
return nullptr;
#ifndef SkColorShader_DEFINED
#define SkColorShader_DEFINED
+#include "SkColorSpaceXformer.h"
#include "SkShader.h"
#include "SkPM4f.h"
bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
const SkMatrix& ctm, const SkPaint&, const SkMatrix*) const override;
+ sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override {
+ return SkShader::MakeColorShader(xformer->apply(fColor));
+ }
+
private:
SkColor fColor;
bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
const SkMatrix& ctm, const SkPaint&, const SkMatrix*) const override;
+ sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
+
private:
sk_sp<SkColorSpace> fColorSpace;
const SkColor4f fColor4;
return xformed;
}
-// TODO: Is this introspection going to be enough, or do we need a new SkShader method?
-sk_sp<SkShader> SkColorSpaceXformer::apply(const SkShader* shader) {
- SkColor color;
- if (shader->isConstant() && shader->asLuminanceColor(&color)) {
- return SkShader::MakeColorShader(this->apply(color))
- ->makeWithLocalMatrix(shader->getLocalMatrix());
- }
-
- SkShader::TileMode xy[2];
- SkMatrix local;
- if (auto img = shader->isAImage(&local, xy)) {
- return this->apply(img)->makeShader(xy[0], xy[1], &local);
- }
-
- SkShader::ComposeRec compose;
- if (shader->asACompose(&compose)) {
- auto A = this->apply(compose.fShaderA),
- B = this->apply(compose.fShaderB);
- if (A && B) {
- return SkShader::MakeComposeShader(std::move(A), std::move(B), compose.fBlendMode)
- ->makeWithLocalMatrix(shader->getLocalMatrix());
- }
- }
-
- SkShader::GradientInfo gradient;
- sk_bzero(&gradient, sizeof(gradient));
- if (auto type = shader->asAGradient(&gradient)) {
- SkSTArray<8, SkColor> colors(gradient.fColorCount);
- SkSTArray<8, SkScalar> pos(gradient.fColorCount);
-
- gradient.fColors = colors.begin();
- gradient.fColorOffsets = pos.begin();
- shader->asAGradient(&gradient);
-
- SkSTArray<8, SkColor> xformed(gradient.fColorCount);
- this->apply(xformed.begin(), gradient.fColors, gradient.fColorCount);
-
- switch (type) {
- case SkShader::kNone_GradientType:
- case SkShader::kColor_GradientType:
- SkASSERT(false); // Should be unreachable.
- break;
-
- case SkShader::kLinear_GradientType:
- return SkGradientShader::MakeLinear(gradient.fPoint,
- xformed.begin(),
- gradient.fColorOffsets,
- gradient.fColorCount,
- gradient.fTileMode,
- gradient.fGradientFlags,
- &shader->getLocalMatrix());
- case SkShader::kRadial_GradientType:
- return SkGradientShader::MakeRadial(gradient.fPoint[0],
- gradient.fRadius[0],
- xformed.begin(),
- gradient.fColorOffsets,
- gradient.fColorCount,
- gradient.fTileMode,
- gradient.fGradientFlags,
- &shader->getLocalMatrix());
- case SkShader::kSweep_GradientType:
- return SkGradientShader::MakeSweep(gradient.fPoint[0].fX,
- gradient.fPoint[0].fY,
- xformed.begin(),
- gradient.fColorOffsets,
- gradient.fColorCount,
- gradient.fGradientFlags,
- &shader->getLocalMatrix());
- case SkShader::kConical_GradientType:
- return SkGradientShader::MakeTwoPointConical(gradient.fPoint[0],
- gradient.fRadius[0],
- gradient.fPoint[1],
- gradient.fRadius[1],
- xformed.begin(),
- gradient.fColorOffsets,
- gradient.fColorCount,
- gradient.fTileMode,
- gradient.fGradientFlags,
- &shader->getLocalMatrix());
- }
- }
-
- return sk_ref_sp(const_cast<SkShader*>(shader));
-}
-
const SkPaint& SkColorSpaceXformer::apply(const SkPaint& src) {
const SkPaint* result = &src;
auto get_dst = [&] {
}
if (auto shader = src.getShader()) {
- if (auto replacement = this->apply(shader)) {
+ auto replacement = shader->makeColorSpace(this);
+ if (replacement.get() != shader) {
get_dst()->setShader(std::move(replacement));
}
}
}
if (auto looper = src.getDrawLooper()) {
- get_dst()->setDrawLooper(looper->makeColorSpace(this));
+ auto replacement = looper->makeColorSpace(this);
+ if (replacement.get() != looper) {
+ get_dst()->setDrawLooper(std::move(replacement));
+ }
}
if (auto imageFilter = src.getImageFilter()) {
- get_dst()->setImageFilter(imageFilter->makeColorSpace(this));
+ auto replacement = imageFilter->makeColorSpace(this);
+ if (replacement.get() != imageFilter) {
+ get_dst()->setImageFilter(std::move(replacement));
+ }
}
return *result;
sk_sp<SkImage> apply(const SkImage* src);
sk_sp<SkImage> apply(const SkBitmap& bitmap);
- sk_sp<SkColorFilter> apply(const SkColorFilter* shader);
+ sk_sp<SkColorFilter> apply(const SkColorFilter* filter);
const SkPaint* apply(const SkPaint* src);
const SkPaint& apply(const SkPaint& src);
void apply(SkColor dst[], const SkColor src[], int n);
sk_sp<SkColorSpace> dst() const { return fDst; }
private:
- sk_sp<SkShader> apply(const SkShader* shader);
-
SkColorSpaceXformer() {}
sk_sp<SkColorSpace> fDst;
#include "SkShader.h"
#include "SkBlendMode.h"
+class SkColorSpacXformer;
+
///////////////////////////////////////////////////////////////////////////////////////////
/** \class SkComposeShader
SkComposeShader(SkReadBuffer&);
void flatten(SkWriteBuffer&) const override;
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
+ sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override {
+ return SkShader::MakeComposeShader(fShaderA->makeColorSpace(xformer),
+ fShaderB->makeColorSpace(xformer), fMode);
+ }
private:
sk_sp<SkShader> fShaderA;
class GrFragmentProcessor;
class SkArenaAlloc;
+class SkColorSpaceXformer;
class SkLocalMatrixShader : public SkShader {
public:
bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
const SkMatrix&, const SkPaint&, const SkMatrix*) const override;
+ sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override {
+ return fProxyShader->makeColorSpace(xformer)->makeWithLocalMatrix(this->getLocalMatrix());
+ }
+
#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
bool onIsABitmap(SkBitmap* bitmap, SkMatrix* matrix, TileMode* mode) const override {
return fProxyShader->isABitmap(bitmap, matrix, mode);
*/
#include "Sk4fLinearGradient.h"
+#include "SkColorSpaceXformer.h"
#include "SkLinearGradient.h"
#include "SkRefCnt.h"
return true;
}
+sk_sp<SkShader> SkLinearGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
+ SkPoint pts[2] = { fStart, fEnd };
+ SkSTArray<8, SkColor> xformedColors(fColorCount);
+ xformer->apply(xformedColors.begin(), fOrigColors, fColorCount);
+ return SkGradientShader::MakeLinear(pts, xformedColors.begin(), fOrigPos, fColorCount,
+ fTileMode, fGradFlags, &this->getLocalMatrix());
+}
+
// This swizzles SkColor into the same component order as SkPMColor, but does not actually
// "pre" multiply the color components.
//
bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
const SkMatrix&, const SkPaint&, const SkMatrix*) const override;
+ sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
+
private:
class LinearGradient4fContext;
* found in the LICENSE file.
*/
+#include "SkColorSpaceXformer.h"
#include "SkRadialGradient.h"
#include "SkNx.h"
#endif
+sk_sp<SkShader> SkRadialGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
+ SkSTArray<8, SkColor> xformedColors(fColorCount);
+ xformer->apply(xformedColors.begin(), fOrigColors, fColorCount);
+ return SkGradientShader::MakeRadial(fCenter, fRadius, xformedColors.begin(), fOrigPos,
+ fColorCount, fTileMode, fGradFlags,
+ &this->getLocalMatrix());
+}
+
#ifndef SK_IGNORE_TO_STRING
void SkRadialGradient::toString(SkString* str) const {
str->append("SkRadialGradient: (");
SkRadialGradient(SkReadBuffer& buffer);
void flatten(SkWriteBuffer& buffer) const override;
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
+ sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
private:
const SkPoint fCenter;
* found in the LICENSE file.
*/
+#include "SkColorSpaceXformer.h"
#include "SkSweepGradient.h"
#include <algorithm>
#endif
+sk_sp<SkShader> SkSweepGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
+ SkSTArray<8, SkColor> xformedColors(fColorCount);
+ xformer->apply(xformedColors.begin(), fOrigColors, fColorCount);
+ return SkGradientShader::MakeSweep(fCenter.fX, fCenter.fY, xformedColors.begin(), fOrigPos,
+ fColorCount, fGradFlags, &this->getLocalMatrix());
+}
+
#ifndef SK_IGNORE_TO_STRING
void SkSweepGradient::toString(SkString* str) const {
str->append("SkSweepGradient: (");
protected:
void flatten(SkWriteBuffer& buffer) const override;
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
+ sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
private:
const SkPoint fCenter;
#endif
+sk_sp<SkShader> SkTwoPointConicalGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
+ SkSTArray<8, SkColor> origColorsStorage(fColorCount);
+ SkSTArray<8, SkScalar> origPosStorage(fColorCount);
+ SkSTArray<8, SkColor> xformedColorsStorage(fColorCount);
+ SkColor* origColors = origColorsStorage.begin();
+ SkScalar* origPos = fOrigPos ? origPosStorage.begin() : nullptr;
+ SkColor* xformedColors = xformedColorsStorage.begin();
+
+ // Flip if necessary
+ SkPoint center1 = fFlippedGrad ? fCenter2 : fCenter1;
+ SkPoint center2 = fFlippedGrad ? fCenter1 : fCenter2;
+ SkScalar radius1 = fFlippedGrad ? fRadius2 : fRadius1;
+ SkScalar radius2 = fFlippedGrad ? fRadius1 : fRadius2;
+ for (int i = 0; i < fColorCount; i++) {
+ origColors[i] = fFlippedGrad ? fOrigColors[fColorCount - i - 1] : fOrigColors[i];
+ if (origPos) {
+ origPos[i] = fFlippedGrad ? 1.0f - fOrigPos[fColorCount - i - 1] : fOrigPos[i];
+ }
+ }
+
+ xformer->apply(xformedColors, origColors, fColorCount);
+ return SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, xformedColors,
+ origPos, fColorCount, fTileMode, fGradFlags,
+ &this->getLocalMatrix());
+}
+
+
#ifndef SK_IGNORE_TO_STRING
void SkTwoPointConicalGradient::toString(SkString* str) const {
str->append("SkTwoPointConicalGradient: (");
#ifndef SkTwoPointConicalGradient_DEFINED
#define SkTwoPointConicalGradient_DEFINED
+#include "SkColorSpaceXformer.h"
#include "SkGradientShaderPriv.h"
// TODO(dominikg): Worth making it truly immutable (i.e. set values in constructor)?
SkTwoPointConicalGradient(SkReadBuffer& buffer);
void flatten(SkWriteBuffer& buffer) const override;
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
+ sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
private:
SkPoint fCenter1;
#ifndef SkImageShader_DEFINED
#define SkImageShader_DEFINED
+#include "SkBitmapProcShader.h"
+#include "SkColorSpaceXformer.h"
#include "SkImage.h"
#include "SkShader.h"
-#include "SkBitmapProcShader.h"
class SkImageShader : public SkShader {
public:
bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
const SkMatrix& ctm, const SkPaint&, const SkMatrix*) const override;
+ sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override {
+ return xformer->apply(fImage.get())->makeShader(fTileModeX, fTileModeY,
+ &this->getLocalMatrix());
+ }
+
sk_sp<SkImage> fImage;
const TileMode fTileModeX;
const TileMode fTileModeY;