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

Side by Side Diff: src/core/SkColorSpaceXform_A2B.cpp

Issue 2449243003: Initial implementation of a SkColorSpace_A2B xform (Closed)
Patch Set: build error+forgot to premuliplty last 0-3 pixels of a line+whitespace warnings Created 4 years, 1 month 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 unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 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 "SkColorSpaceXform_A2B.h"
9
10 #include "SkColorPriv.h"
11 #include "SkColorSpace_A2B.h"
12 #include "SkColorSpace_XYZ.h"
13 #include "SkColorSpacePriv.h"
14 #include "SkColorSpaceXformPriv.h"
15 #include "SkMakeUnique.h"
16 #include "SkNx.h"
17 #include "SkSRGB.h"
18 #include "SkTypes.h"
19
20 class SkColorSpaceXform_A2B::ProcessingElement {
21 public:
22 virtual ~ProcessingElement() {}
23 virtual void apply(Sk4f* rSrc, Sk4f* gSrc, Sk4f* bSrc, int len) = 0;
24 virtual bool merge(ProcessingElement* other) = 0;
25
26 enum class Type {
27 kGamma,
28 kGammaTable,
29 kMatrix,
30 kCLUT,
31 kLabToXYZ
32 };
33 virtual Type type() const = 0;
34 };
35
36 class SkColorSpaceXform_A2B::ApplyCLUT : public SkColorSpaceXform_A2B::Processin gElement {
37 public:
38 ApplyCLUT(const SkColorLookUpTable* clut)
39 : fCLUT(sk_ref_sp(clut))
40 {}
41
42 void apply(Sk4f* rSrc, Sk4f* gSrc, Sk4f* bSrc, int len) override {
msarett 2016/10/26 20:43:29 This feels like a really good place to use SkRaste
raftias 2016/10/27 18:39:39 Acknowledged.
43 while (len > 0) {
44 // unpack into float[3] = {r, g, b} arrays like interp_3d_clut() nee ds
msarett 2016/10/26 20:43:29 If it's convenient, you are welcome to change the
raftias 2016/10/27 18:39:38 It involved look-up tables so without constructing
45 float rgb[4][3] = {
46 {(*rSrc)[0], (*gSrc)[0], (*bSrc)[0]},
47 {(*rSrc)[1], (*gSrc)[1], (*bSrc)[1]},
48 {(*rSrc)[2], (*gSrc)[2], (*bSrc)[2]},
49 {(*rSrc)[3], (*gSrc)[3], (*bSrc)[3]}
50 };
51 for (int i = 0; i < 4; ++i) {
52 interp_3d_clut(rgb[i], rgb[i], fCLUT.get());
53 }
54 *rSrc = Sk4f(rgb[0][0], rgb[1][0], rgb[2][0], rgb[3][0]);
55 *gSrc = Sk4f(rgb[0][1], rgb[1][1], rgb[2][1], rgb[3][1]);
56 *bSrc = Sk4f(rgb[0][2], rgb[1][2], rgb[2][2], rgb[3][2]);
57 ++rSrc;
58 ++gSrc;
59 ++bSrc;
60 --len;
61 }
62 }
63
64 bool merge(ProcessingElement*) override { return false; }
65
66 Type type() const override { return Type::kCLUT; }
67
68 private:
69 sk_sp<const SkColorLookUpTable> fCLUT;
70 };
71
72 class SkColorSpaceXform_A2B::LabToXYZ : public SkColorSpaceXform_A2B::Processing Element {
73 public:
74 void apply(Sk4f* rSrc, Sk4f* gSrc, Sk4f* bSrc, int len) override {
75 while (len > 0) {
76 // convert from Lab to XYZ
77 Sk4f Y = *rSrc*(100.f/116.f) + (16.f/116.f);
78 Sk4f X = *gSrc * (255.f/500.f) - (128.f/500.f) + Y;
79 Sk4f Z = Y - *bSrc * (255.f/200.f) - (128.f/200.f);
80
81 /*const Sk4f l = *rSrc * 100.f;
82 const Sk4f a = *gSrc * 255.f - 128.f;
83 const Sk4f b = *bSrc * 255.f - 128.f;
84 Sk4f Y = (l + 16.f) * (1.f/116.f);
85 Sk4f X = a * (1.f/500.f) + Y;
86 Sk4f Z = Y - (b * (1.f/200.f));*/
87
88
89 Sk4f cubed;
90 cubed = X*X*X;
91 X = (cubed > 0.008856f).thenElse(cubed, (X - (16.f/116.f)) * (1.f/7. 787f));
92 cubed = Y*Y*Y;
93 Y = (cubed > 0.008856f).thenElse(cubed, (Y - (16.f/116.f)) * (1.f/7. 787f));
94 cubed = Z*Z*Z;
95 Z = (cubed > 0.008856f).thenElse(cubed, (Z - (16.f/116.f)) * (1.f/7. 787f));
96
97 // adjust to D50 illuminant
98 X *= 0.96422f;
99 Y *= 1.00000f;
100 Z *= 0.82521f;
101
102 *rSrc = X;
103 *gSrc = Y;
104 *bSrc = Z;
105 ++rSrc;
106 ++gSrc;
107 ++bSrc;
108 --len;
109 }
110 }
111
112 bool merge(ProcessingElement*) override { return false; }
113
114 Type type() const override { return Type::kLabToXYZ; }
115 };
116
117 class SkColorSpaceXform_A2B::ApplyMatrix : public SkColorSpaceXform_A2B::Process ingElement {
118 public:
119 ApplyMatrix(const SkMatrix44& matrix)
120 : fMatrix(matrix)
121 {}
122
123 void apply(Sk4f* rSrc, Sk4f* gSrc, Sk4f* bSrc, int len) override {
124 Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT;
125 float colMajor[16];
126 fMatrix.asColMajorf(colMajor);
127 load_matrix(colMajor, rXgXbX, rYgYbY, rZgZbZ, rTgTbT);
128 while (len > 0) {
129 Sk4f dr, dg, db, a; // a is ignored
130 transform_gamut(*rSrc, *gSrc, *bSrc, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, a);
131 translate_gamut(rTgTbT, dr, dg, db);
132 *rSrc = dr;
133 *gSrc = dg;
134 *bSrc = db;
135 ++rSrc;
136 ++gSrc;
137 ++bSrc;
138 --len;
139 }
140 }
141 bool merge(ProcessingElement* other) override {
142 if (other->type() == Type::kMatrix) {
143 fMatrix.preConcat(static_cast<ApplyMatrix*>(other)->fMatrix);
144 return true;
145 }
146 return false;
147 }
148 Type type() const override {
149 return Type::kMatrix;
150 }
151 private:
152 SkMatrix44 fMatrix;
153 };
154
155
156
157 // adapted from the integer-input version in SkSRGB.h
158 template <int N>
159 static inline SkNx<N,float> sk_linear_from_float_srgb_math(const SkNx<N,float>& x) {
msarett 2016/10/26 20:43:29 Let's move this to SkSRGB.h. I think the int->flo
raftias 2016/10/27 18:39:38 Removed function entirely. Will consider this if/w
160 // Non-linear segment of sRGB curve approximated by
161 // l = 0.0025 + 0.6975x^2 + 0.3x^3
162 const SkNx<N,float> k0 = 0.0025f,
163 k2 = 0.6975f,
164 k3 = 0.3000f;
165 auto hi = x*x*(x*k3 + k2) + k0;
166
167 // Linear segment of sRGB curve: the normal slope, extended a little further than normal.
168 auto lo = x * (1.f/12.92f);
169
170 return (x < (14.025f / 255.f)).thenElse(lo, hi);
171 }
172
173
174 class SkColorSpaceXform_A2B::ApplyGammaSRGB : public SkColorSpaceXform_A2B::Proc essingElement {
175 public:
176 void apply(Sk4f* rSrc, Sk4f* gSrc, Sk4f* bSrc, int len) override {
177 while (len > 0) {
178 *rSrc = sk_linear_from_float_srgb_math(*rSrc);
179 *gSrc = sk_linear_from_float_srgb_math(*gSrc);
180 *bSrc = sk_linear_from_float_srgb_math(*bSrc);
181 ++rSrc;
182 ++gSrc;
183 ++bSrc;
184 --len;
185 }
186 }
187 bool merge(ProcessingElement* other) override { return false; }
188 Type type() const override { return Type::kGamma; }
189 };
190
191 static inline Sk4f linear_from_2dot2(const Sk4f& x) {
192
193 // x^(141/64) = x^(2.20312) is a great approximation of the true value, x^(2 .2).
194 auto x16 = x.rsqrt().rsqrt().rsqrt().rsqrt(); // x^(1/16) = x^(4/64);
195 auto x64 = x16.rsqrt().rsqrt(); // x^(1/64)
196
197 // x^(35/16) = x^(2.1875) is an okay one as well and would be quicker:
msarett 2016/10/26 20:43:29 Please remove this comment. It's not a bad point,
raftias 2016/10/27 18:39:39 Removed function entirely. Will consider this if/w
198 // (both pass ColorSpaceXformTests's +/-1 difference vs x^2.2)
199 // return x*x * x16*x16*x16;
200
201 // x^(141/64) = x^(128/64) * x^(12/64) * x^(1/64)
202 return x*x * x16*x16*x16 * x64;
203 }
204
205 class SkColorSpaceXform_A2B::ApplyGamma2Dot2 : public SkColorSpaceXform_A2B::Pro cessingElement {
206 public:
207 void apply(Sk4f* rSrc, Sk4f* gSrc, Sk4f* bSrc, int len) override {
208 while (len > 0) {
209 *rSrc = linear_from_2dot2(*rSrc);
210 *gSrc = linear_from_2dot2(*gSrc);
211 *bSrc = linear_from_2dot2(*bSrc);
212 ++rSrc;
213 ++gSrc;
214 ++bSrc;
215 --len;
216 }
217 }
218 bool merge(ProcessingElement* other) override { return false; }
219 Type type() const override { return Type::kGamma; }
220 };
221
222 // TODO(raftias): See if there's some actually-vectorized implementation somewhe re?
msarett 2016/10/26 20:43:29 As far I know, there's not. I don't even think th
223 // or remove once all powf() calling transforms (value, param) are converted int o tables
224 static inline Sk4f SkNx_powf(const Sk4f& x, float exp) {
225 return Sk4f{::powf(x[0], exp), ::powf(x[1], exp), ::powf(x[2], exp), ::powf( x[3], exp)};
226 }
227
228 // TODO(raftias): remove and store in tables
229 class SkColorSpaceXform_A2B::ApplyGammaValue : public SkColorSpaceXform_A2B::Pro cessingElement {
230 public:
231 ApplyGammaValue(float rExp, float gExp, float bExp)
232 : fRExp(rExp)
233 , fGExp(gExp)
234 , fBExp(bExp)
235 {}
236 void apply(Sk4f* rSrc, Sk4f* gSrc, Sk4f* bSrc, int len) override {
237 while (len > 0) {
238 *rSrc = SkNx_powf(*rSrc, fRExp);
239 *gSrc = SkNx_powf(*gSrc, fGExp);
240 *bSrc = SkNx_powf(*bSrc, fBExp);
241 ++rSrc;
242 ++gSrc;
243 ++bSrc;
244 --len;
245 }
246 }
247 bool merge(ProcessingElement* other) override { return false; }
248 Type type() const override { return Type::kGamma; }
249 private:
250 float fRExp;
251 float fGExp;
252 float fBExp;
253 };
254
255 // TODO(raftias): remove and store in tables?
256 class SkColorSpaceXform_A2B::ApplyGammaParams : public SkColorSpaceXform_A2B::Pr ocessingElement {
257 public:
258 ApplyGammaParams(const SkColorSpaceTransferFn& rParams, const SkColorSpaceTr ansferFn& gParams,
259 const SkColorSpaceTransferFn& bParams)
260 : fRP(rParams)
261 , fGP(gParams)
262 , fBP(bParams)
263 {}
264 void apply(Sk4f* rSrc, Sk4f* gSrc, Sk4f* bSrc, int len) override {
265 // TODO(raftias): profile against a non-vectorized implementation, since if the (short)
266 // linear segment is hit a lot then there's a lot of unnecessary powf() calls.
267 // Or just remove these and cache into tables.
268 while (len > 0) {
269 *rSrc = (*rSrc <= fRP.fD).thenElse(fRP.fE * (*rSrc) + fRP.fF,
270 SkNx_powf(*rSrc*fRP.fA + fRP.fB, fRP.fG) + fRP.fC);
271 *gSrc = (*gSrc <= fGP.fD).thenElse(fGP.fE * (*gSrc) + fGP.fF,
272 SkNx_powf(*gSrc*fGP.fA + fGP.fB, fGP.fG) + fGP.fC);
273 *bSrc = (*bSrc <= fBP.fD).thenElse(fBP.fE * (*bSrc) + fBP.fF,
274 SkNx_powf(*bSrc*fBP.fA + fBP.fB, fBP.fG) + fBP.fC);
275 ++rSrc;
276 ++gSrc;
277 ++bSrc;
278 --len;
279 }
280 }
281 bool merge(ProcessingElement* other) override { return false; }
282 Type type() const override { return Type::kGamma; }
283 private:
284 const SkColorSpaceTransferFn fRP;
285 const SkColorSpaceTransferFn fGP;
286 const SkColorSpaceTransferFn fBP;
287 };
288
289 class SkColorSpaceXform_A2B::ApplyGammaTable : public SkColorSpaceXform_A2B::Pro cessingElement {
290 public:
291 ApplyGammaTable(const SkGammas* gammas) {
292 // TODO(raftias): use 1 table if all channels point to the same table
293 const int numTables = 3;
294 const size_t tableBytes = numTables * kDstGammaTableSize * sizeof(float) ;
295 const float tableStep = 1.f / (float)(kDstGammaTableSize - 1);
296 fStorage.reset(tableBytes);
297 float* outTable = fStorage.get();
298 for (int i = 0; i < numTables; ++i) {
299 SkASSERT(gammas->isTable(i));
300 const float* inTable = gammas->table(i);
301 const int inTableSize = gammas->data(i).fTable.fSize;
302 fGammaTables[i] = outTable;
303 if (kDstGammaTableSize == inTableSize) {
304 memcpy(outTable, inTable, sizeof(float) * kDstGammaTableSize);
305 return;
306 }
307
308 for (float x = 0.0f; x <= 1.0f; x += tableStep) {
309 *outTable++ = interp_lut(x, inTable, inTableSize);
310 }
311 }
312 }
313
314 void apply(Sk4f* rSrc, Sk4f* gSrc, Sk4f* bSrc, int len) override {
315 const float maxIndex = kDstGammaTableSize - 1;
316 while (len > 0) {
317 *rSrc = Sk4f::Min(Sk4f::Max(maxIndex * (*rSrc), 0.f), maxIndex);
318 *gSrc = Sk4f::Min(Sk4f::Max(maxIndex * (*gSrc), 0.f), maxIndex);
319 *bSrc = Sk4f::Min(Sk4f::Max(maxIndex * (*bSrc), 0.f), maxIndex);
320 const Sk4i ir = Sk4f_round(*rSrc);
321 const Sk4i ig = Sk4f_round(*gSrc);
322 const Sk4i ib = Sk4f_round(*bSrc);
323 *rSrc = Sk4f((float) fGammaTables[0][ir[0]],
324 (float) fGammaTables[0][ir[1]],
325 (float) fGammaTables[0][ir[2]],
326 (float) fGammaTables[0][ir[3]]);
327 *gSrc = Sk4f((float) fGammaTables[1][ig[0]],
328 (float) fGammaTables[1][ig[1]],
329 (float) fGammaTables[1][ig[2]],
330 (float) fGammaTables[1][ig[3]]);
331 *bSrc = Sk4f((float) fGammaTables[2][ib[0]],
332 (float) fGammaTables[2][ib[1]],
333 (float) fGammaTables[2][ib[2]],
334 (float) fGammaTables[2][ib[3]]);
335 ++rSrc;
336 ++gSrc;
337 ++bSrc;
338 --len;
339 }
340 }
341
342 bool merge(ProcessingElement* other) override {
343 if (Type::kGammaTable == other->type()) {
344 auto otherGamma = static_cast<const SkColorSpaceXform_A2B::ApplyGamm aTable*>(other);
345 const int numTables = 3; // set to 1 if matching
346 for (int table = 0; table < numTables; ++table) {
347 for (int i = 0; i < kDstGammaTableSize; ++i) {
348 const int indexIntoOther = (int)(fGammaTables[table][i] + 0. 5f);
349 fGammaTables[table][i] = otherGamma->fGammaTables[table][ind exIntoOther];
350 }
351 }
352 return true;
353 }
354 return false;
355 }
356
357 Type type() const override { return Type::kGammaTable; }
358
359 private:
360 SkAutoTMalloc<float> fStorage;
361 float* fGammaTables[3];
362 };
363
364 //////////////////////////////////////////////////////////////////////////////// ///////////////////
365
366
367 bool SkColorSpaceXform_A2B::onApply(ColorFormat dstFormat, void* dst, ColorForma t srcFormat,
368 const void* src, int count, SkAlphaType alph aType) const {
369 LoadFn load;
370 const bool loadAlpha = (kPremul_SkAlphaType == alphaType) ||
371 (kRGBA_F16_ColorFormat == dstFormat) ||
372 (kRGBA_F32_ColorFormat == dstFormat);
373
374 switch (srcFormat) {
375 case kRGBA_8888_ColorFormat:
376 load = loadAlpha ? load_rgba_linear<kRGBA_Order>
377 : load_rgb_linear<kRGBA_Order>;
378 break;
379 case kBGRA_8888_ColorFormat:
380 load = loadAlpha ? load_rgba_linear<kBGRA_Order>
381 : load_rgb_linear<kBGRA_Order>;
382 break;
383 default:
384 SkCSXformPrintf("F16/F32 source color format not supported\n");
385 return false;
386 }
387
388 StoreFn store = store_linear<kRGBA_Order>;
389 size_t sizeOfDstPixel = 0;
390 switch (dstFormat) {
391 case kRGBA_8888_ColorFormat:
392 switch (fDstGamma) {
393 case kLinear_SkGammaNamed:
394 store = store_linear<kRGBA_Order>;
395 break;
396 case kSRGB_SkGammaNamed:
397 store = store_srgb<kRGBA_Order>;
398 break;
399 case k2Dot2Curve_SkGammaNamed:
400 store = store_2dot2<kRGBA_Order>;
401 break;
402 default:
403 store = store_generic<kRGBA_Order>;
404 break;
405 }
406 sizeOfDstPixel = 4;
407 break;
408 case kBGRA_8888_ColorFormat:
409 switch (fDstGamma) {
410 case kLinear_SkGammaNamed:
411 store = store_linear<kBGRA_Order>;
412 break;
413 case kSRGB_SkGammaNamed:
414 store = store_srgb<kBGRA_Order>;
415 break;
416 case k2Dot2Curve_SkGammaNamed:
417 store = store_2dot2<kBGRA_Order>;
418 break;
419 default:
420 store = store_generic<kBGRA_Order>;
421 break;
422 }
423 sizeOfDstPixel = 4;
424 break;
425 case kRGBA_F16_ColorFormat:
426 if (fDstGamma != kLinear_SkGammaNamed) {
427 return false;
428 }
429 store = (kOpaque_SkAlphaType == alphaType) ? store_f16_opaque<kRGBA_ Order>
430 : store_f16<kRGBA_Order>;
431 sizeOfDstPixel = 8;
432 break;
433 case kRGBA_F32_ColorFormat:
434 if (fDstGamma != kLinear_SkGammaNamed) {
435 return false;
436 }
437 store = store_f32<kRGBA_Order>;
438 sizeOfDstPixel = 16;
439 break;
440 }
441 SkASSERT(sizeOfDstPixel > 0);
442
443 const int allocLen = (count + 3) / 4;
444 SkAutoTMalloc<Sk4f> rSrc(allocLen);
445 SkAutoTMalloc<Sk4f> gSrc(allocLen);
446 SkAutoTMalloc<Sk4f> bSrc(allocLen);
447 Sk4f ignore;
448 const uint32_t* loadSrc = (const uint32_t*)src;
449 int loadLen = count;
450 Sk4f* loadRSrc = rSrc.get();
451 Sk4f* loadGSrc = gSrc.get();
452 Sk4f* loadBSrc = bSrc.get();
453 while (loadLen >= 4) {
454 load(loadSrc, *loadRSrc, *loadGSrc, *loadBSrc, ignore, nullptr);
455 loadSrc += 4;
456 loadLen -= 4;
457 ++loadRSrc;
458 ++loadGSrc;
459 ++loadBSrc;
460 }
461 if (loadLen > 0) {
462 // read the last 1-3 RGBA values into a buffer and load all 4 RGBA
463 // values out of the buffer, letting the last 1-3 be arbitrary values
464 // (all byte combos are valid RGBA values)
465 uint32_t readOverrun[16];
466 memcpy(readOverrun, loadSrc, loadLen * sizeof(uint32_t));
467 load(readOverrun, *loadRSrc, *loadGSrc, *loadBSrc, ignore, nullptr);
468 }
469
470 for (const std::unique_ptr<ProcessingElement>& element : fProcessingElements ) {
471 element->apply(rSrc.get(), gSrc.get(), bSrc.get(), allocLen);
472 }
473
474 Sk4f* storeRSrc = rSrc.get();
475 Sk4f* storeGSrc = gSrc.get();
476 Sk4f* storeBSrc = bSrc.get();
477 loadSrc = (const uint32_t*)src;
478 Sk4f alpha;
479 while (count >= 4) {
480 // load the alpha from the source image since our transformations only a ffected R/G/B
481 load(loadSrc, ignore, ignore, ignore, alpha, nullptr);
482
483 if (kPremul_SkAlphaType == alphaType) {
484 premultiply(*storeRSrc, *storeGSrc, *storeBSrc, alpha);
485 }
486
487 store(dst, (const uint32_t*)src, *storeRSrc, *storeGSrc, *storeBSrc, alp ha,
488 fDstGammaTables);
489 dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
490 count -= 4;
491 loadSrc += 4; // to load alpha
492 ++storeRSrc;
493 ++storeGSrc;
494 ++storeBSrc;
495 }
496 if (count > 0) {
497 const int maxSizeOfDstPixel = 16;
498 SkASSERT(sizeOfDstPixel <= maxSizeOfDstPixel);
499 uint32_t writeOverrun[4*maxSizeOfDstPixel];
500
501 load(loadSrc, ignore, ignore, ignore, alpha, nullptr);
502
503 if (kPremul_SkAlphaType == alphaType) {
504 premultiply(*storeRSrc, *storeGSrc, *storeBSrc, alpha);
505 }
506
507 store(writeOverrun, (const uint32_t*)src, *storeRSrc, *storeGSrc, *store BSrc, alpha,
508 fDstGammaTables);
509 memcpy(dst, writeOverrun, count * sizeOfDstPixel);
510 }
511 return true;
512 }
513
514 SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace,
515 SkColorSpace_XYZ* dstSpace) {
516 #if (SkCSXformPrintfDefined)
517 static const char* debugGammaNamed[4] = {
518 "Linear", "SRGB", "2.2", "NonStandard"
519 };
520 static const char* debugGammas[5] = {
521 "None", "Named", "Value", "Table", "Param"
522 };
523 #endif
524 // add in all device -> PCS xforms
525 for (size_t i = 0; i < srcSpace->count(); ++i) {
526 const SkColorSpace_A2B::Element& e = srcSpace->element(i);
527 switch (e.type()) {
528 case SkColorSpace_A2B::Element::Type::kGammaNamed:
529 SkCSXformPrintf("Gamma element added: %s\n",
530 debugGammaNamed[(int)e.gammaNamed()]);
531 switch (e.gammaNamed()) {
532 case kLinear_SkGammaNamed:
533 // there is no point in adding a transform here
534 break;
535 case kSRGB_SkGammaNamed:
536 fProcessingElements.push_back(skstd::make_unique<ApplyGa mmaSRGB>());
537 break;
538 case k2Dot2Curve_SkGammaNamed:
539 fProcessingElements.push_back(skstd::make_unique<ApplyGa mma2Dot2>());
540 break;
541 case kNonStandard_SkGammaNamed:
542 SkASSERT(false);
543 break;
544 }
545 break;
546 case SkColorSpace_A2B::Element::Type::kGammas: {
547 const SkGammas* gammas = &e.gammas();
548 SkCSXformPrintf("Adding gamma element:");
549 for (int channel = 0; channel < 3; ++channel) {
550 SkCSXformPrintf(" %s", debugGammas[(int)gammas->type(ch annel)]);
551 }
552 SkCSXformPrintf("\n");
553 if (gammas->type(0) != gammas->type(1) || gammas->type(0) != gammas->type(2)) {
554 SkCSXformPrintf("Mixed gamma types are not supported rig ht now.");
555 SkCSXformPrintf(" Using only 1st gamma channel.\n");
556 }
557 switch (gammas->type(0))
558 {
559 case SkGammas::Type::kNone_Type:
560 SkCSXformPrintf("Invalid gamma type\n");
561 break;
562 case SkGammas::Type::kNamed_Type:
563 switch (gammas->data(0).fNamed) {
564 case kLinear_SkGammaNamed:
565 // there is no point in adding a transform h ere
566 break;
567 case kSRGB_SkGammaNamed:
568 fProcessingElements.push_back(
569 skstd::make_unique<ApplyGammaSRGB>() );
570 break;
571 case k2Dot2Curve_SkGammaNamed:
572 fProcessingElements.push_back(
573 skstd::make_unique<ApplyGamma2Dot2>( ));
574 break;
575 case kNonStandard_SkGammaNamed:
576 SkASSERT(false);
577 break;
578 }
579 break;
580 case SkGammas::Type::kValue_Type:
581 // TODO(raftias): pre-compute and cache these into a table
582 fProcessingElements.push_back(skstd::make_unique<App lyGammaValue>(
583 gammas->data(0).fValue, gammas->data(1).fVal ue,
584 gammas->data(2).fValue));
585 break;
586 case SkGammas::Type::kTable_Type:
587 fProcessingElements.push_back(
588 skstd::make_unique<ApplyGammaTable>(gammas));
589 break;
590 case SkGammas::Type::kParam_Type: {
591 // TODO(raftias): pre-compute and cache these into a table?
592 const SkColorSpaceTransferFn& pr = gammas->params(0) ;
593 const SkColorSpaceTransferFn& pg = gammas->params(1) ;
594 const SkColorSpaceTransferFn& pb = gammas->params(2) ;
595 fProcessingElements.push_back(skstd::make_unique<App lyGammaParams>(
596 pr, pg, pb));
597 }
598 break;
599 }
600 }
601 break;
602 case SkColorSpace_A2B::Element::Type::kCLUT:
603 fProcessingElements.push_back(skstd::make_unique<ApplyCLUT>(&e.c olorLUT()));
604 break;
605 case SkColorSpace_A2B::Element::Type::kMatrix:
606 if (!e.matrix().isIdentity()) {
607 fProcessingElements.push_back(skstd::make_unique<ApplyMatrix >(e.matrix()));
608 }
609 break;
610 }
611 }
612
613 // Lab PCS -> XYZ PCS
614 if (SkColorSpace_A2B::PCS::kLAB == srcSpace->pcs()) {
615 SkCSXformPrintf("Lab -> XYZ element added\n");
616 fProcessingElements.push_back(skstd::make_unique<LabToXYZ>());
617 }
618
619 // and XYZ PCS -> device xforms
620 if (!dstSpace->fromXYZD50()->isIdentity()) {
621 fProcessingElements.push_back(skstd::make_unique<ApplyMatrix>(*dstSpace- >fromXYZD50()));
622 }
623
624 //concatTransforms();
msarett 2016/10/26 20:43:29 Let's drop this for now if it's not being used yet
raftias 2016/10/27 18:39:39 Done.
625
626 const int numDstTables = num_tables(dstSpace);
627 dstSpace->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables);
628 fDstGamma = dstSpace->gammaNamed();
629 }
630
631 void SkColorSpaceXform_A2B::concatTransforms() {
632 uint32_t i = 0;
633 while (i + 1 < fProcessingElements.size()) {
634 if (fProcessingElements[i]->merge(fProcessingElements[i + 1].get())) {
635 // We could just reset the (i+1)th element then do 1 pass at the end
636 // to remove null elements to get O(n) instead of O(n^2), but n shou ld
637 // be very small so this should not matter
638 fProcessingElements.erase(fProcessingElements.begin() + i + 1);
639 } else {
640 ++i;
641 }
642 }
643 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698