• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkColorFilter.h"
9 #include "SkColorSpaceXformer.h"
10 #include "SkColorSpaceXform_Base.h"
11 #include "SkDrawLooper.h"
12 #include "SkGradientShader.h"
13 #include "SkImage_Base.h"
14 #include "SkImagePriv.h"
15 #include "SkMakeUnique.h"
16 
Make(sk_sp<SkColorSpace> dst)17 std::unique_ptr<SkColorSpaceXformer> SkColorSpaceXformer::Make(sk_sp<SkColorSpace> dst) {
18     std::unique_ptr<SkColorSpaceXform> fromSRGB = SkColorSpaceXform_Base::New(
19             SkColorSpace::MakeSRGB().get(), dst.get(), SkTransferFunctionBehavior::kIgnore);
20     if (!fromSRGB) {
21         return nullptr;
22     }
23 
24     auto xformer = std::unique_ptr<SkColorSpaceXformer>(new SkColorSpaceXformer());
25     xformer->fDst      = std::move(dst);
26     xformer->fFromSRGB = std::move(fromSRGB);
27     return xformer;
28 }
29 
apply(const SkImage * src)30 sk_sp<SkImage> SkColorSpaceXformer::apply(const SkImage* src) {
31     return as_IB(src)->makeColorSpace(fDst);
32 }
33 
apply(const SkBitmap & src)34 sk_sp<SkImage> SkColorSpaceXformer::apply(const SkBitmap& src) {
35     sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(src, kNever_SkCopyPixelsMode);
36     if (!image) {
37         return nullptr;
38     }
39 
40     sk_sp<SkImage> xformed = as_IB(image)->makeColorSpace(fDst);
41     // We want to be sure we don't let the kNever_SkCopyPixelsMode image escape this stack frame.
42     SkASSERT(xformed != image);
43     return xformed;
44 }
45 
apply(SkColor * xformed,const SkColor * srgb,int n)46 void SkColorSpaceXformer::apply(SkColor* xformed, const SkColor* srgb, int n) {
47     SkAssertResult(fFromSRGB->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, xformed,
48                                     SkColorSpaceXform::kBGRA_8888_ColorFormat, srgb,
49                                     n, kUnpremul_SkAlphaType));
50 }
51 
apply(SkColor srgb)52 SkColor SkColorSpaceXformer::apply(SkColor srgb) {
53     SkColor xformed;
54     this->apply(&xformed, &srgb, 1);
55     return xformed;
56 }
57 
58 // TODO: Is this introspection going to be enough, or do we need a new SkShader method?
apply(const SkShader * shader)59 sk_sp<SkShader> SkColorSpaceXformer::apply(const SkShader* shader) {
60     SkColor color;
61     if (shader->isConstant() && shader->asLuminanceColor(&color)) {
62         return SkShader::MakeColorShader(this->apply(color))
63                 ->makeWithLocalMatrix(shader->getLocalMatrix());
64     }
65 
66     SkShader::TileMode xy[2];
67     SkMatrix local;
68     if (auto img = shader->isAImage(&local, xy)) {
69         return this->apply(img)->makeShader(xy[0], xy[1], &local);
70     }
71 
72     SkShader::ComposeRec compose;
73     if (shader->asACompose(&compose)) {
74         auto A = this->apply(compose.fShaderA),
75              B = this->apply(compose.fShaderB);
76         if (A && B) {
77             return SkShader::MakeComposeShader(std::move(A), std::move(B), compose.fBlendMode)
78                     ->makeWithLocalMatrix(shader->getLocalMatrix());
79         }
80     }
81 
82     SkShader::GradientInfo gradient;
83     sk_bzero(&gradient, sizeof(gradient));
84     if (auto type = shader->asAGradient(&gradient)) {
85         SkSTArray<8, SkColor>  colors(gradient.fColorCount);
86         SkSTArray<8, SkScalar>    pos(gradient.fColorCount);
87 
88         gradient.fColors       = colors.begin();
89         gradient.fColorOffsets =    pos.begin();
90         shader->asAGradient(&gradient);
91 
92         SkSTArray<8, SkColor> xformed(gradient.fColorCount);
93         this->apply(xformed.begin(), gradient.fColors, gradient.fColorCount);
94 
95         switch (type) {
96             case SkShader::kNone_GradientType:
97             case SkShader::kColor_GradientType:
98                 SkASSERT(false);  // Should be unreachable.
99                 break;
100 
101             case SkShader::kLinear_GradientType:
102                 return SkGradientShader::MakeLinear(gradient.fPoint,
103                                                     xformed.begin(),
104                                                     gradient.fColorOffsets,
105                                                     gradient.fColorCount,
106                                                     gradient.fTileMode,
107                                                     gradient.fGradientFlags,
108                                                     &shader->getLocalMatrix());
109             case SkShader::kRadial_GradientType:
110                 return SkGradientShader::MakeRadial(gradient.fPoint[0],
111                                                     gradient.fRadius[0],
112                                                     xformed.begin(),
113                                                     gradient.fColorOffsets,
114                                                     gradient.fColorCount,
115                                                     gradient.fTileMode,
116                                                     gradient.fGradientFlags,
117                                                     &shader->getLocalMatrix());
118             case SkShader::kSweep_GradientType:
119                 return SkGradientShader::MakeSweep(gradient.fPoint[0].fX,
120                                                    gradient.fPoint[0].fY,
121                                                    xformed.begin(),
122                                                    gradient.fColorOffsets,
123                                                    gradient.fColorCount,
124                                                    gradient.fGradientFlags,
125                                                    &shader->getLocalMatrix());
126             case SkShader::kConical_GradientType:
127                 return SkGradientShader::MakeTwoPointConical(gradient.fPoint[0],
128                                                              gradient.fRadius[0],
129                                                              gradient.fPoint[1],
130                                                              gradient.fRadius[1],
131                                                              xformed.begin(),
132                                                              gradient.fColorOffsets,
133                                                              gradient.fColorCount,
134                                                              gradient.fTileMode,
135                                                              gradient.fGradientFlags,
136                                                              &shader->getLocalMatrix());
137         }
138     }
139 
140     return sk_ref_sp(const_cast<SkShader*>(shader));
141 }
142 
apply(const SkPaint & src)143 SkPaint SkColorSpaceXformer::apply(const SkPaint& src) {
144     SkPaint dst = src;
145 
146     // All SkColorSpaces have the same black point.
147     if (src.getColor() & 0xffffff) {
148         dst.setColor(this->apply(src.getColor()));
149     }
150 
151     if (auto shader = src.getShader()) {
152         dst.setShader(this->apply(shader));
153     }
154 
155     // As far as I know, SkModeColorFilter is the only color filter that holds a color.
156     if (auto cf = src.getColorFilter()) {
157         SkColor color;
158         SkBlendMode mode;
159         if (cf->asColorMode(&color, &mode)) {
160             dst.setColorFilter(SkColorFilter::MakeModeFilter(this->apply(color), mode));
161         }
162     }
163 
164     if (auto looper = src.getDrawLooper()) {
165         dst.setDrawLooper(looper->makeColorSpace(this));
166     }
167 
168     // TODO:
169     //    - image filters?
170     return dst;
171 }
172