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, float exponent) { | 267 static void build_table_linear_to_gamma(uint8_t* outTable, int outTableSize, flo
at exponent) { |
268 float toGammaExp = 1.0f / exponent; | 268 float toGammaExp = 1.0f / exponent; |
269 | 269 |
270 for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) { | 270 for (int i = 0; i < outTableSize; i++) { |
271 float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTable
Size - 1))); | 271 float x = ((float) i) * (1.0f / ((float) (outTableSize - 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, const float* table, int tableSize)
{ | 279 static float inverse_interp_lut(float input, 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, const float* inTable, | 302 static void build_table_linear_to_gamma(uint8_t* outTable, int outTableSize, flo
at* inTable, |
303 int inTableSize) { | 303 int inTableSize) { |
304 for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) { | 304 for (int i = 0; i < outTableSize; i++) { |
305 float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTable
Size - 1))); | 305 float x = ((float) i) * (1.0f / ((float) (outTableSize - 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, float g, float a, | 342 static void build_table_linear_to_gamma(uint8_t* outTable, int outTableSize, flo
at 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 < SkDefaultXform::kDstGammaTableSize; i++) { | 344 for (int i = 0; i < outTableSize; i++) { |
345 float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTable
Size - 1))); | 345 float x = ((float) i) * (1.0f / ((float) (outTableSize - 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 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
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 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 351 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
448 | 352 |
449 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, | 353 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, |
450 const sk_sp<SkColorSpa
ce>& dstSpace) { | 354 const sk_sp<SkColorSpa
ce>& dstSpace) { |
451 if (!srcSpace || !dstSpace) { | 355 if (!srcSpace || !dstSpace) { |
452 // Invalid input | 356 // Invalid input |
453 return nullptr; | 357 return nullptr; |
454 } | 358 } |
455 | 359 |
456 if (as_CSB(dstSpace)->colorLUT()) { | 360 if (as_CSB(dstSpace)->colorLUT()) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 srcToDstArray[9] = srcToDstMatrix.getFloat(2, 1); | 413 srcToDstArray[9] = srcToDstMatrix.getFloat(2, 1); |
510 srcToDstArray[10] = srcToDstMatrix.getFloat(2, 2); | 414 srcToDstArray[10] = srcToDstMatrix.getFloat(2, 2); |
511 srcToDstArray[11] = 0.0f; | 415 srcToDstArray[11] = 0.0f; |
512 } | 416 } |
513 | 417 |
514 template <SkColorSpace::GammaNamed Dst> | 418 template <SkColorSpace::GammaNamed Dst> |
515 SkFastXform<Dst>::SkFastXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatri
x44& srcToDst, | 419 SkFastXform<Dst>::SkFastXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatri
x44& srcToDst, |
516 const sk_sp<SkColorSpace>& dstSpace) | 420 const sk_sp<SkColorSpace>& dstSpace) |
517 { | 421 { |
518 build_src_to_dst(fSrcToDst, srcToDst); | 422 build_src_to_dst(fSrcToDst, srcToDst); |
519 build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kT
oLinear); | 423 |
520 build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, SkDefaultXform::k
DstGammaTableSize, | 424 // Build tables to transform src gamma to linear. |
521 dstSpace, kFromLinear); | 425 switch (srcSpace->gammaNamed()) { |
| 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 } |
522 } | 567 } |
523 | 568 |
524 template <> | 569 template <> |
525 void SkFastXform<SkColorSpace::kSRGB_GammaNamed> | 570 void SkFastXform<SkColorSpace::kSRGB_GammaNamed> |
526 ::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const | 571 ::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const |
527 { | 572 { |
528 SkOpts::color_xform_RGB1_to_srgb(dst, src, len, fSrcGammaTables, fSrcToDst); | 573 SkOpts::color_xform_RGB1_to_srgb(dst, src, len, fSrcGammaTables, fSrcToDst); |
529 } | 574 } |
530 | 575 |
531 template <> | 576 template <> |
(...skipping 17 matching lines...) Expand all Loading... |
549 SkOpts::color_xform_RGB1_to_linear(dst, src, len, fSrcGammaTables, fSrcToDst
); | 594 SkOpts::color_xform_RGB1_to_linear(dst, src, len, fSrcGammaTables, fSrcToDst
); |
550 } | 595 } |
551 | 596 |
552 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 597 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
553 | 598 |
554 SkDefaultXform::SkDefaultXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatr
ix44& srcToDst, | 599 SkDefaultXform::SkDefaultXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatr
ix44& srcToDst, |
555 const sk_sp<SkColorSpace>& dstSpace) | 600 const sk_sp<SkColorSpace>& dstSpace) |
556 : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) | 601 : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) |
557 , fSrcToDst(srcToDst) | 602 , fSrcToDst(srcToDst) |
558 { | 603 { |
559 build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kT
oLinear); | 604 // Build tables to transform src gamma to linear. |
560 build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, SkDefaultXform::k
DstGammaTableSize, | 605 switch (srcSpace->gammaNamed()) { |
561 dstSpace, kFromLinear); | 606 case SkColorSpace::kSRGB_GammaNamed: |
| 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 } |
562 } | 747 } |
563 | 748 |
564 static float byte_to_float(uint8_t byte) { | 749 static float byte_to_float(uint8_t byte) { |
565 return ((float) byte) * (1.0f / 255.0f); | 750 return ((float) byte) * (1.0f / 255.0f); |
566 } | 751 } |
567 | 752 |
568 // Clamp to the 0-1 range. | 753 // Clamp to the 0-1 range. |
569 static float clamp_normalized_float(float v) { | 754 static float clamp_normalized_float(float v) { |
570 if (v > 1.0f) { | 755 if (v > 1.0f) { |
571 return 1.0f; | 756 return 1.0f; |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
722 dst++; | 907 dst++; |
723 src++; | 908 src++; |
724 } | 909 } |
725 } | 910 } |
726 | 911 |
727 void SkDefaultXform::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const
{ | 912 void SkDefaultXform::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const
{ |
728 // FIXME (msarett): | 913 // FIXME (msarett): |
729 // Planning to delete SkDefaultXform. Not going to bother to implement this
. | 914 // Planning to delete SkDefaultXform. Not going to bother to implement this
. |
730 memset(dst, 0, len * sizeof(RGBAF16)); | 915 memset(dst, 0, len * sizeof(RGBAF16)); |
731 } | 916 } |
OLD | NEW |