OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkColorPriv.h" | 8 #include "SkColorPriv.h" |
9 #include "SkColorSpace_Base.h" | 9 #include "SkColorSpace_Base.h" |
10 #include "SkColorSpaceXform.h" | 10 #include "SkColorSpaceXform.h" |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 v = v * 255.0f; | 257 v = v * 255.0f; |
258 if (v >= 254.5f) { | 258 if (v >= 254.5f) { |
259 return 255; | 259 return 255; |
260 } else if (v >= 0.5f) { | 260 } else if (v >= 0.5f) { |
261 return (uint8_t) (v + 0.5f); | 261 return (uint8_t) (v + 0.5f); |
262 } else { | 262 } else { |
263 return 0; | 263 return 0; |
264 } | 264 } |
265 } | 265 } |
266 | 266 |
267 static void build_table_linear_to_gamma(uint8_t* outTable, int outTableSize, flo
at exponent) { | 267 static void build_table_linear_to_gamma(uint8_t* outTable, float exponent) { |
268 float toGammaExp = 1.0f / exponent; | 268 float toGammaExp = 1.0f / exponent; |
269 | 269 |
270 for (int i = 0; i < outTableSize; i++) { | 270 for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) { |
271 float x = ((float) i) * (1.0f / ((float) (outTableSize - 1))); | 271 float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTable
Size - 1))); |
272 outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp)); | 272 outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp)); |
273 } | 273 } |
274 } | 274 } |
275 | 275 |
276 // Inverse table lookup. Ex: what index corresponds to the input value? This w
ill | 276 // Inverse table lookup. Ex: what index corresponds to the input value? This w
ill |
277 // have strange results when the table is non-increasing. But any sane gamma | 277 // have strange results when the table is non-increasing. But any sane gamma |
278 // function will be increasing. | 278 // function will be increasing. |
279 static float inverse_interp_lut(float input, float* table, int tableSize) { | 279 static float inverse_interp_lut(float input, const float* table, int tableSize)
{ |
280 if (input <= table[0]) { | 280 if (input <= table[0]) { |
281 return table[0]; | 281 return table[0]; |
282 } else if (input >= table[tableSize - 1]) { | 282 } else if (input >= table[tableSize - 1]) { |
283 return 1.0f; | 283 return 1.0f; |
284 } | 284 } |
285 | 285 |
286 for (int i = 1; i < tableSize; i++) { | 286 for (int i = 1; i < tableSize; i++) { |
287 if (table[i] >= input) { | 287 if (table[i] >= input) { |
288 // We are guaranteed that input is greater than table[i - 1]. | 288 // We are guaranteed that input is greater than table[i - 1]. |
289 float diff = input - table[i - 1]; | 289 float diff = input - table[i - 1]; |
290 float distance = table[i] - table[i - 1]; | 290 float distance = table[i] - table[i - 1]; |
291 float index = (i - 1) + diff / distance; | 291 float index = (i - 1) + diff / distance; |
292 return index / (tableSize - 1); | 292 return index / (tableSize - 1); |
293 } | 293 } |
294 } | 294 } |
295 | 295 |
296 // Should be unreachable, since we'll return before the loop if input is | 296 // Should be unreachable, since we'll return before the loop if input is |
297 // larger than the last entry. | 297 // larger than the last entry. |
298 SkASSERT(false); | 298 SkASSERT(false); |
299 return 0.0f; | 299 return 0.0f; |
300 } | 300 } |
301 | 301 |
302 static void build_table_linear_to_gamma(uint8_t* outTable, int outTableSize, flo
at* inTable, | 302 static void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable, |
303 int inTableSize) { | 303 int inTableSize) { |
304 for (int i = 0; i < outTableSize; i++) { | 304 for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) { |
305 float x = ((float) i) * (1.0f / ((float) (outTableSize - 1))); | 305 float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTable
Size - 1))); |
306 float y = inverse_interp_lut(x, inTable, inTableSize); | 306 float y = inverse_interp_lut(x, inTable, inTableSize); |
307 outTable[i] = clamp_normalized_float_to_byte(y); | 307 outTable[i] = clamp_normalized_float_to_byte(y); |
308 } | 308 } |
309 } | 309 } |
310 | 310 |
311 static float inverse_parametric(float x, float g, float a, float b, float c, flo
at d, float e, | 311 static float inverse_parametric(float x, float g, float a, float b, float c, flo
at d, float e, |
312 float f) { | 312 float f) { |
313 // We need to take the inverse of the following piecewise function. | 313 // We need to take the inverse of the following piecewise function. |
314 // Y = (aX + b)^g + c for X >= d | 314 // Y = (aX + b)^g + c for X >= d |
315 // Y = eX + f otherwise | 315 // Y = eX + f otherwise |
(...skipping 16 matching lines...) Expand all Loading... |
332 // X = ((Y - C)^(1 / G) - B) / A | 332 // X = ((Y - C)^(1 / G) - B) / A |
333 if (0.0f == a || 0.0f == g) { | 333 if (0.0f == a || 0.0f == g) { |
334 // The gamma curve for this segment is constant, so the inverse is undef
ined. | 334 // The gamma curve for this segment is constant, so the inverse is undef
ined. |
335 // Since this is the upper segment, guess one. | 335 // Since this is the upper segment, guess one. |
336 return 1.0f; | 336 return 1.0f; |
337 } | 337 } |
338 | 338 |
339 return (powf(x - c, 1.0f / g) - b) / a; | 339 return (powf(x - c, 1.0f / g) - b) / a; |
340 } | 340 } |
341 | 341 |
342 static void build_table_linear_to_gamma(uint8_t* outTable, int outTableSize, flo
at g, float a, | 342 static void build_table_linear_to_gamma(uint8_t* outTable, float g, float a, |
343 float b, float c, float d, float e, floa
t f) { | 343 float b, float c, float d, float e, floa
t f) { |
344 for (int i = 0; i < outTableSize; i++) { | 344 for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) { |
345 float x = ((float) i) * (1.0f / ((float) (outTableSize - 1))); | 345 float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTable
Size - 1))); |
346 float y = inverse_parametric(x, g, a, b, c, d, e, f); | 346 float y = inverse_parametric(x, g, a, b, c, d, e, f); |
347 outTable[i] = clamp_normalized_float_to_byte(y); | 347 outTable[i] = clamp_normalized_float_to_byte(y); |
348 } | 348 } |
349 } | 349 } |
350 | 350 |
351 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 351 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
352 | 352 |
| 353 template <typename T> |
| 354 struct GammaFns { |
| 355 const T* fSRGBTable; |
| 356 const T* f2Dot2Table; |
| 357 |
| 358 void (*fBuildFromValue)(T*, float); |
| 359 void (*fBuildFromTable)(T*, const float*, int); |
| 360 void (*fBuildFromParam)(T*, float, float, float, float, float, float, float)
; |
| 361 }; |
| 362 |
| 363 static const GammaFns<float> kToLinear { |
| 364 sk_linear_from_srgb, |
| 365 sk_linear_from_2dot2, |
| 366 &build_table_linear_from_gamma, |
| 367 &build_table_linear_from_gamma, |
| 368 &build_table_linear_from_gamma, |
| 369 }; |
| 370 |
| 371 static const GammaFns<uint8_t> kFromLinear { |
| 372 linear_to_srgb, |
| 373 linear_to_2dot2, |
| 374 &build_table_linear_to_gamma, |
| 375 &build_table_linear_to_gamma, |
| 376 &build_table_linear_to_gamma, |
| 377 }; |
| 378 |
| 379 // Build tables to transform src gamma to linear. |
| 380 template <typename T> |
| 381 static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage,
int gammaTableSize, |
| 382 const sk_sp<SkColorSpace>& space, const GammaFns<
T>& fns) { |
| 383 switch (space->gammaNamed()) { |
| 384 case SkColorSpace::kSRGB_GammaNamed: |
| 385 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRG
BTable; |
| 386 break; |
| 387 case SkColorSpace::k2Dot2Curve_GammaNamed: |
| 388 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Do
t2Table; |
| 389 break; |
| 390 case SkColorSpace::kLinear_GammaNamed: |
| 391 (*fns.fBuildFromValue)(gammaTableStorage, 1.0f); |
| 392 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = gammaTab
leStorage; |
| 393 break; |
| 394 default: { |
| 395 const SkGammas* gammas = as_CSB(space)->gammas(); |
| 396 SkASSERT(gammas); |
| 397 |
| 398 for (int i = 0; i < 3; i++) { |
| 399 if (i > 0) { |
| 400 // Check if this curve matches the first curve. In this cas
e, we can |
| 401 // share the same table pointer. This should almost always
be true. |
| 402 // I've never seen a profile where all three gamma curves di
dn't match. |
| 403 // But it is possible that they won't. |
| 404 if (gammas->data(0) == gammas->data(i)) { |
| 405 outGammaTables[i] = outGammaTables[0]; |
| 406 continue; |
| 407 } |
| 408 } |
| 409 |
| 410 if (gammas->isNamed(i)) { |
| 411 switch (gammas->data(i).fNamed) { |
| 412 case SkColorSpace::kSRGB_GammaNamed: |
| 413 outGammaTables[i] = fns.fSRGBTable; |
| 414 break; |
| 415 case SkColorSpace::k2Dot2Curve_GammaNamed: |
| 416 outGammaTables[i] = fns.f2Dot2Table; |
| 417 break; |
| 418 case SkColorSpace::kLinear_GammaNamed: |
| 419 (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaT
ableSize], 1.0f); |
| 420 outGammaTables[i] = &gammaTableStorage[i * gammaTabl
eSize]; |
| 421 break; |
| 422 default: |
| 423 SkASSERT(false); |
| 424 break; |
| 425 } |
| 426 } else if (gammas->isValue(i)) { |
| 427 (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize
], |
| 428 gammas->data(i).fValue); |
| 429 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; |
| 430 } else if (gammas->isTable(i)) { |
| 431 (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize
], gammas->table(i), |
| 432 gammas->data(i).fTable.fSize); |
| 433 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; |
| 434 } else { |
| 435 SkASSERT(gammas->isParametric(i)); |
| 436 const SkGammas::Params& params = gammas->params(i); |
| 437 (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize
], params.fG, |
| 438 params.fA, params.fB, params.fC, para
ms.fD, params.fE, |
| 439 params.fF); |
| 440 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; |
| 441 } |
| 442 } |
| 443 } |
| 444 } |
| 445 } |
| 446 |
| 447 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 448 |
353 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, | 449 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, |
354 const sk_sp<SkColorSpa
ce>& dstSpace) { | 450 const sk_sp<SkColorSpa
ce>& dstSpace) { |
355 if (!srcSpace || !dstSpace) { | 451 if (!srcSpace || !dstSpace) { |
356 // Invalid input | 452 // Invalid input |
357 return nullptr; | 453 return nullptr; |
358 } | 454 } |
359 | 455 |
360 if (as_CSB(dstSpace)->colorLUT()) { | 456 if (as_CSB(dstSpace)->colorLUT()) { |
361 // It would be really weird for a dst profile to have a color LUT. I do
n't think | 457 // It would be really weird for a dst profile to have a color LUT. I do
n't think |
362 // we need to support this. | 458 // we need to support this. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
413 srcToDstArray[9] = srcToDstMatrix.getFloat(2, 1); | 509 srcToDstArray[9] = srcToDstMatrix.getFloat(2, 1); |
414 srcToDstArray[10] = srcToDstMatrix.getFloat(2, 2); | 510 srcToDstArray[10] = srcToDstMatrix.getFloat(2, 2); |
415 srcToDstArray[11] = 0.0f; | 511 srcToDstArray[11] = 0.0f; |
416 } | 512 } |
417 | 513 |
418 template <SkColorSpace::GammaNamed Dst> | 514 template <SkColorSpace::GammaNamed Dst> |
419 SkFastXform<Dst>::SkFastXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatri
x44& srcToDst, | 515 SkFastXform<Dst>::SkFastXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatri
x44& srcToDst, |
420 const sk_sp<SkColorSpace>& dstSpace) | 516 const sk_sp<SkColorSpace>& dstSpace) |
421 { | 517 { |
422 build_src_to_dst(fSrcToDst, srcToDst); | 518 build_src_to_dst(fSrcToDst, srcToDst); |
423 | 519 build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kT
oLinear); |
424 // Build tables to transform src gamma to linear. | 520 build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, SkDefaultXform::k
DstGammaTableSize, |
425 switch (srcSpace->gammaNamed()) { | 521 dstSpace, kFromLinear); |
426 case SkColorSpace::kSRGB_GammaNamed: | |
427 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = sk_li
near_from_srgb; | |
428 break; | |
429 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
430 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = sk_li
near_from_2dot2; | |
431 break; | |
432 case SkColorSpace::kLinear_GammaNamed: | |
433 build_table_linear_from_gamma(fSrcGammaTableStorage, 1.0f); | |
434 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = fSrcG
ammaTableStorage; | |
435 break; | |
436 default: { | |
437 const SkGammas* gammas = as_CSB(srcSpace)->gammas(); | |
438 SkASSERT(gammas); | |
439 | |
440 for (int i = 0; i < 3; i++) { | |
441 const SkGammaCurve& curve = (*gammas)[i]; | |
442 | |
443 if (i > 0) { | |
444 // Check if this curve matches the first curve. In this cas
e, we can | |
445 // share the same table pointer. Logically, this should alm
ost always | |
446 // be true. I've never seen a profile where all three gamma
curves | |
447 // didn't match. But it is possible that they won't. | |
448 // TODO (msarett): | |
449 // This comparison won't catch the case where each gamma cur
ve has a | |
450 // pointer to its own look-up table, but the tables actually
match. | |
451 // Should we perform a deep compare of gamma tables here? O
r should | |
452 // we catch this when parsing the profile? Or should we not
worry | |
453 // about a bit of redundant work? | |
454 if (curve.quickEquals((*gammas)[0])) { | |
455 fSrcGammaTables[i] = fSrcGammaTables[0]; | |
456 continue; | |
457 } | |
458 } | |
459 | |
460 if (curve.isNamed()) { | |
461 switch (curve.fNamed) { | |
462 case SkColorSpace::kSRGB_GammaNamed: | |
463 fSrcGammaTables[i] = sk_linear_from_srgb; | |
464 break; | |
465 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
466 fSrcGammaTables[i] = sk_linear_from_2dot2; | |
467 break; | |
468 case SkColorSpace::kLinear_GammaNamed: | |
469 build_table_linear_from_gamma(&fSrcGammaTableStorage
[i * 256], 1.0f); | |
470 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]
; | |
471 break; | |
472 default: | |
473 SkASSERT(false); | |
474 break; | |
475 } | |
476 } else if (curve.isValue()) { | |
477 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], curve.fValue); | |
478 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
479 } else if (curve.isTable()) { | |
480 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], | |
481 curve.fTable.get(), curve.fTab
leSize); | |
482 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
483 } else { | |
484 SkASSERT(curve.isParametric()); | |
485 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], curve.fG, | |
486 curve.fA, curve.fB, curve.fC,
curve.fD, curve.fE, | |
487 curve.fF); | |
488 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
489 } | |
490 } | |
491 } | |
492 } | |
493 | |
494 // Build tables to transform linear to dst gamma. | |
495 // FIXME (msarett): | |
496 // Should we spend all of this time bulding the dst gamma tables when the cl
ient only | |
497 // wants to convert to F16? | |
498 switch (dstSpace->gammaNamed()) { | |
499 case SkColorSpace::kSRGB_GammaNamed: | |
500 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
501 break; | |
502 case SkColorSpace::kLinear_GammaNamed: | |
503 build_table_linear_to_gamma(fDstGammaTableStorage, kDstGammaTableSiz
e, 1.0f); | |
504 fDstGammaTables[0] = fDstGammaTables[1] = fDstGammaTables[2] = fDstG
ammaTableStorage; | |
505 break; | |
506 default: { | |
507 const SkGammas* gammas = as_CSB(dstSpace)->gammas(); | |
508 SkASSERT(gammas); | |
509 | |
510 for (int i = 0; i < 3; i++) { | |
511 const SkGammaCurve& curve = (*gammas)[i]; | |
512 | |
513 if (i > 0) { | |
514 // Check if this curve matches the first curve. In this cas
e, we can | |
515 // share the same table pointer. Logically, this should alm
ost always | |
516 // be true. I've never seen a profile where all three gamma
curves | |
517 // didn't match. But it is possible that they won't. | |
518 // TODO (msarett): | |
519 // This comparison won't catch the case where each gamma cur
ve has a | |
520 // pointer to its own look-up table (but the tables actually
match). | |
521 // Should we perform a deep compare of gamma tables here? O
r should | |
522 // we catch this when parsing the profile? Or should we not
worry | |
523 // about a bit of redundant work? | |
524 if (curve.quickEquals((*gammas)[0])) { | |
525 fDstGammaTables[i] = fDstGammaTables[0]; | |
526 continue; | |
527 } | |
528 } | |
529 | |
530 if (curve.isNamed()) { | |
531 switch (curve.fNamed) { | |
532 case SkColorSpace::kSRGB_GammaNamed: | |
533 fDstGammaTables[i] = linear_to_srgb; | |
534 break; | |
535 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
536 fDstGammaTables[i] = linear_to_2dot2; | |
537 break; | |
538 case SkColorSpace::kLinear_GammaNamed: | |
539 build_table_linear_to_gamma( | |
540 &fDstGammaTableStorage[i * kDstGammaTableSiz
e], | |
541 kDstGammaTableSize, 1.0f); | |
542 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDst
GammaTableSize]; | |
543 break; | |
544 default: | |
545 SkASSERT(false); | |
546 break; | |
547 } | |
548 } else if (curve.isValue()) { | |
549 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
550 kDstGammaTableSize, curve.fValue
); | |
551 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
552 } else if (curve.isTable()) { | |
553 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
554 kDstGammaTableSize, curve.fTable
.get(), | |
555 curve.fTableSize); | |
556 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
557 } else { | |
558 SkASSERT(curve.isParametric()); | |
559 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
560 kDstGammaTableSize, curve.fG, cu
rve.fA, curve.fB, | |
561 curve.fC, curve.fD, curve.fE, cu
rve.fF); | |
562 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
563 } | |
564 } | |
565 } | |
566 } | |
567 } | 522 } |
568 | 523 |
569 template <> | 524 template <> |
570 void SkFastXform<SkColorSpace::kSRGB_GammaNamed> | 525 void SkFastXform<SkColorSpace::kSRGB_GammaNamed> |
571 ::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const | 526 ::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const |
572 { | 527 { |
573 SkOpts::color_xform_RGB1_to_srgb(dst, src, len, fSrcGammaTables, fSrcToDst); | 528 SkOpts::color_xform_RGB1_to_srgb(dst, src, len, fSrcGammaTables, fSrcToDst); |
574 } | 529 } |
575 | 530 |
576 template <> | 531 template <> |
(...skipping 17 matching lines...) Expand all Loading... |
594 SkOpts::color_xform_RGB1_to_linear(dst, src, len, fSrcGammaTables, fSrcToDst
); | 549 SkOpts::color_xform_RGB1_to_linear(dst, src, len, fSrcGammaTables, fSrcToDst
); |
595 } | 550 } |
596 | 551 |
597 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 552 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
598 | 553 |
599 SkDefaultXform::SkDefaultXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatr
ix44& srcToDst, | 554 SkDefaultXform::SkDefaultXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatr
ix44& srcToDst, |
600 const sk_sp<SkColorSpace>& dstSpace) | 555 const sk_sp<SkColorSpace>& dstSpace) |
601 : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) | 556 : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) |
602 , fSrcToDst(srcToDst) | 557 , fSrcToDst(srcToDst) |
603 { | 558 { |
604 // Build tables to transform src gamma to linear. | 559 build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kT
oLinear); |
605 switch (srcSpace->gammaNamed()) { | 560 build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, SkDefaultXform::k
DstGammaTableSize, |
606 case SkColorSpace::kSRGB_GammaNamed: | 561 dstSpace, kFromLinear); |
607 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = sk_li
near_from_srgb; | |
608 break; | |
609 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
610 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = sk_li
near_from_2dot2; | |
611 break; | |
612 case SkColorSpace::kLinear_GammaNamed: | |
613 build_table_linear_from_gamma(fSrcGammaTableStorage, 1.0f); | |
614 fSrcGammaTables[0] = fSrcGammaTables[1] = fSrcGammaTables[2] = fSrcG
ammaTableStorage; | |
615 break; | |
616 default: { | |
617 const SkGammas* gammas = as_CSB(srcSpace)->gammas(); | |
618 SkASSERT(gammas); | |
619 | |
620 for (int i = 0; i < 3; i++) { | |
621 const SkGammaCurve& curve = (*gammas)[i]; | |
622 | |
623 if (i > 0) { | |
624 // Check if this curve matches the first curve. In this cas
e, we can | |
625 // share the same table pointer. Logically, this should alm
ost always | |
626 // be true. I've never seen a profile where all three gamma
curves | |
627 // didn't match. But it is possible that they won't. | |
628 // TODO (msarett): | |
629 // This comparison won't catch the case where each gamma cur
ve has a | |
630 // pointer to its own look-up table, but the tables actually
match. | |
631 // Should we perform a deep compare of gamma tables here? O
r should | |
632 // we catch this when parsing the profile? Or should we not
worry | |
633 // about a bit of redundant work? | |
634 if (curve.quickEquals((*gammas)[0])) { | |
635 fSrcGammaTables[i] = fSrcGammaTables[0]; | |
636 continue; | |
637 } | |
638 } | |
639 | |
640 if (curve.isNamed()) { | |
641 switch (curve.fNamed) { | |
642 case SkColorSpace::kSRGB_GammaNamed: | |
643 fSrcGammaTables[i] = sk_linear_from_srgb; | |
644 break; | |
645 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
646 fSrcGammaTables[i] = sk_linear_from_2dot2; | |
647 break; | |
648 case SkColorSpace::kLinear_GammaNamed: | |
649 build_table_linear_from_gamma(&fSrcGammaTableStorage
[i * 256], 1.0f); | |
650 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]
; | |
651 break; | |
652 default: | |
653 SkASSERT(false); | |
654 break; | |
655 } | |
656 } else if (curve.isValue()) { | |
657 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], curve.fValue); | |
658 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
659 } else if (curve.isTable()) { | |
660 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], | |
661 curve.fTable.get(), curve.fTab
leSize); | |
662 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
663 } else { | |
664 SkASSERT(curve.isParametric()); | |
665 build_table_linear_from_gamma(&fSrcGammaTableStorage[i * 256
], curve.fG, | |
666 curve.fA, curve.fB, curve.fC,
curve.fD, curve.fE, | |
667 curve.fF); | |
668 fSrcGammaTables[i] = &fSrcGammaTableStorage[i * 256]; | |
669 } | |
670 } | |
671 } | |
672 } | |
673 | |
674 // Build tables to transform linear to dst gamma. | |
675 switch (dstSpace->gammaNamed()) { | |
676 case SkColorSpace::kSRGB_GammaNamed: | |
677 fDstGammaTables[0] = fDstGammaTables[1] = fDstGammaTables[2] = linea
r_to_srgb; | |
678 break; | |
679 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
680 fDstGammaTables[0] = fDstGammaTables[1] = fDstGammaTables[2] = linea
r_to_2dot2; | |
681 break; | |
682 case SkColorSpace::kLinear_GammaNamed: | |
683 build_table_linear_to_gamma(fDstGammaTableStorage, kDstGammaTableSiz
e, 1.0f); | |
684 fDstGammaTables[0] = fDstGammaTables[1] = fDstGammaTables[2] = fDstG
ammaTableStorage; | |
685 break; | |
686 default: { | |
687 const SkGammas* gammas = as_CSB(dstSpace)->gammas(); | |
688 SkASSERT(gammas); | |
689 | |
690 for (int i = 0; i < 3; i++) { | |
691 const SkGammaCurve& curve = (*gammas)[i]; | |
692 | |
693 if (i > 0) { | |
694 // Check if this curve matches the first curve. In this cas
e, we can | |
695 // share the same table pointer. Logically, this should alm
ost always | |
696 // be true. I've never seen a profile where all three gamma
curves | |
697 // didn't match. But it is possible that they won't. | |
698 // TODO (msarett): | |
699 // This comparison won't catch the case where each gamma cur
ve has a | |
700 // pointer to its own look-up table (but the tables actually
match). | |
701 // Should we perform a deep compare of gamma tables here? O
r should | |
702 // we catch this when parsing the profile? Or should we not
worry | |
703 // about a bit of redundant work? | |
704 if (curve.quickEquals((*gammas)[0])) { | |
705 fDstGammaTables[i] = fDstGammaTables[0]; | |
706 continue; | |
707 } | |
708 } | |
709 | |
710 if (curve.isNamed()) { | |
711 switch (curve.fNamed) { | |
712 case SkColorSpace::kSRGB_GammaNamed: | |
713 fDstGammaTables[i] = linear_to_srgb; | |
714 break; | |
715 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
716 fDstGammaTables[i] = linear_to_2dot2; | |
717 break; | |
718 case SkColorSpace::kLinear_GammaNamed: | |
719 build_table_linear_to_gamma( | |
720 &fDstGammaTableStorage[i * kDstGammaTableSiz
e], | |
721 kDstGammaTableSize, 1.0f); | |
722 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDst
GammaTableSize]; | |
723 break; | |
724 default: | |
725 SkASSERT(false); | |
726 break; | |
727 } | |
728 } else if (curve.isValue()) { | |
729 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
730 kDstGammaTableSize, curve.fValue
); | |
731 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
732 } else if (curve.isTable()) { | |
733 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
734 kDstGammaTableSize, curve.fTable
.get(), | |
735 curve.fTableSize); | |
736 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
737 } else { | |
738 SkASSERT(curve.isParametric()); | |
739 build_table_linear_to_gamma(&fDstGammaTableStorage[i * kDstG
ammaTableSize], | |
740 kDstGammaTableSize, curve.fG, cu
rve.fA, curve.fB, | |
741 curve.fC, curve.fD, curve.fE, cu
rve.fF); | |
742 fDstGammaTables[i] = &fDstGammaTableStorage[i * kDstGammaTab
leSize]; | |
743 } | |
744 } | |
745 } | |
746 } | |
747 } | 562 } |
748 | 563 |
749 static float byte_to_float(uint8_t byte) { | 564 static float byte_to_float(uint8_t byte) { |
750 return ((float) byte) * (1.0f / 255.0f); | 565 return ((float) byte) * (1.0f / 255.0f); |
751 } | 566 } |
752 | 567 |
753 // Clamp to the 0-1 range. | 568 // Clamp to the 0-1 range. |
754 static float clamp_normalized_float(float v) { | 569 static float clamp_normalized_float(float v) { |
755 if (v > 1.0f) { | 570 if (v > 1.0f) { |
756 return 1.0f; | 571 return 1.0f; |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
907 dst++; | 722 dst++; |
908 src++; | 723 src++; |
909 } | 724 } |
910 } | 725 } |
911 | 726 |
912 void SkDefaultXform::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const
{ | 727 void SkDefaultXform::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const
{ |
913 // FIXME (msarett): | 728 // FIXME (msarett): |
914 // Planning to delete SkDefaultXform. Not going to bother to implement this
. | 729 // Planning to delete SkDefaultXform. Not going to bother to implement this
. |
915 memset(dst, 0, len * sizeof(RGBAF16)); | 730 memset(dst, 0, len * sizeof(RGBAF16)); |
916 } | 731 } |
OLD | NEW |