| Index: src/core/SkColorSpaceXform.cpp
 | 
| diff --git a/src/core/SkColorSpaceXform.cpp b/src/core/SkColorSpaceXform.cpp
 | 
| index e6bde616c3211e8a387b4ae4e5df5e85a5e1d59e..924f24f6fc1d7768049cf7635efd5f499988ba22 100644
 | 
| --- a/src/core/SkColorSpaceXform.cpp
 | 
| +++ b/src/core/SkColorSpaceXform.cpp
 | 
| @@ -264,11 +264,14 @@ static uint8_t clamp_normalized_float_to_byte(float v) {
 | 
|      }
 | 
|  }
 | 
|  
 | 
| +static const int kDstGammaTableSize =
 | 
| +        SkColorSpaceXform_Base<SkColorSpace::kNonStandard_GammaNamed>::kDstGammaTableSize;
 | 
| +
 | 
|  static void build_table_linear_to_gamma(uint8_t* outTable, float exponent) {
 | 
|      float toGammaExp = 1.0f / exponent;
 | 
|  
 | 
| -    for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) {
 | 
| -        float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTableSize - 1)));
 | 
| +    for (int i = 0; i < kDstGammaTableSize; i++) {
 | 
| +        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
 | 
|          outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp));
 | 
|      }
 | 
|  }
 | 
| @@ -301,8 +304,8 @@ static float inverse_interp_lut(float input, const float* table, int tableSize)
 | 
|  
 | 
|  static void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable,
 | 
|                                          int inTableSize) {
 | 
| -    for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) {
 | 
| -        float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTableSize - 1)));
 | 
| +    for (int i = 0; i < kDstGammaTableSize; i++) {
 | 
| +        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
 | 
|          float y = inverse_interp_lut(x, inTable, inTableSize);
 | 
|          outTable[i] = clamp_normalized_float_to_byte(y);
 | 
|      }
 | 
| @@ -341,8 +344,8 @@ static float inverse_parametric(float x, float g, float a, float b, float c, flo
 | 
|  
 | 
|  static void build_table_linear_to_gamma(uint8_t* outTable, float g, float a,
 | 
|                                          float b, float c, float d, float e, float f) {
 | 
| -    for (int i = 0; i < SkDefaultXform::kDstGammaTableSize; i++) {
 | 
| -        float x = ((float) i) * (1.0f / ((float) (SkDefaultXform::kDstGammaTableSize - 1)));
 | 
| +    for (int i = 0; i < kDstGammaTableSize; i++) {
 | 
| +        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
 | 
|          float y = inverse_parametric(x, g, a, b, c, d, e, f);
 | 
|          outTable[i] = clamp_normalized_float_to_byte(y);
 | 
|      }
 | 
| @@ -464,82 +467,21 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
 | 
|          return nullptr;
 | 
|      }
 | 
|  
 | 
| -    if (0.0f == srcToDst.getFloat(3, 0) &&
 | 
| -        0.0f == srcToDst.getFloat(3, 1) &&
 | 
| -        0.0f == srcToDst.getFloat(3, 2) &&
 | 
| -        !as_CSB(srcSpace)->colorLUT())
 | 
| -    {
 | 
| -        switch (dstSpace->gammaNamed()) {
 | 
| -            case SkColorSpace::kSRGB_GammaNamed:
 | 
| -                return std::unique_ptr<SkColorSpaceXform>(
 | 
| -                        new SkFastXform<SkColorSpace::kSRGB_GammaNamed>(srcSpace, srcToDst,
 | 
| -                                                                        dstSpace));
 | 
| -            case SkColorSpace::k2Dot2Curve_GammaNamed:
 | 
| -                return std::unique_ptr<SkColorSpaceXform>(
 | 
| -                        new SkFastXform<SkColorSpace::k2Dot2Curve_GammaNamed>(srcSpace, srcToDst,
 | 
| -                                                                              dstSpace));
 | 
| -            default:
 | 
| -                return std::unique_ptr<SkColorSpaceXform>(
 | 
| -                        new SkFastXform<SkColorSpace::kNonStandard_GammaNamed>(srcSpace, srcToDst,
 | 
| -                                                                               dstSpace));
 | 
| -        }
 | 
| +    switch (dstSpace->gammaNamed()) {
 | 
| +        case SkColorSpace::kSRGB_GammaNamed:
 | 
| +            return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
 | 
| +                    <SkColorSpace::kSRGB_GammaNamed>(srcSpace, srcToDst, dstSpace));
 | 
| +        case SkColorSpace::k2Dot2Curve_GammaNamed:
 | 
| +            return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
 | 
| +                    <SkColorSpace::k2Dot2Curve_GammaNamed>(srcSpace, srcToDst, dstSpace));
 | 
| +        default:
 | 
| +            return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base
 | 
| +                    <SkColorSpace::kNonStandard_GammaNamed>(srcSpace, srcToDst, dstSpace));
 | 
|      }
 | 
| -
 | 
| -    return std::unique_ptr<SkColorSpaceXform>(new SkDefaultXform(srcSpace, srcToDst, dstSpace));
 | 
|  }
 | 
|  
 | 
|  ///////////////////////////////////////////////////////////////////////////////////////////////////
 | 
|  
 | 
| -template <SkColorSpace::GammaNamed Dst>
 | 
| -SkFastXform<Dst>::SkFastXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatrix44& srcToDst,
 | 
| -                              const sk_sp<SkColorSpace>& dstSpace)
 | 
| -{
 | 
| -    srcToDst.asRowMajorf(fSrcToDst);
 | 
| -    build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kToLinear);
 | 
| -    build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, SkDefaultXform::kDstGammaTableSize,
 | 
| -                       dstSpace, kFromLinear);
 | 
| -}
 | 
| -
 | 
| -template <>
 | 
| -void SkFastXform<SkColorSpace::kSRGB_GammaNamed>
 | 
| -::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
 | 
| -{
 | 
| -    SkOpts::color_xform_RGB1_to_srgb(dst, src, len, fSrcGammaTables, fSrcToDst);
 | 
| -}
 | 
| -
 | 
| -template <>
 | 
| -void SkFastXform<SkColorSpace::k2Dot2Curve_GammaNamed>
 | 
| -::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
 | 
| -{
 | 
| -    SkOpts::color_xform_RGB1_to_2dot2(dst, src, len, fSrcGammaTables, fSrcToDst);
 | 
| -}
 | 
| -
 | 
| -template <>
 | 
| -void SkFastXform<SkColorSpace::kNonStandard_GammaNamed>
 | 
| -::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
 | 
| -{
 | 
| -    SkOpts::color_xform_RGB1_to_table(dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
 | 
| -}
 | 
| -
 | 
| -template <SkColorSpace::GammaNamed T>
 | 
| -void SkFastXform<T>
 | 
| -::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const
 | 
| -{
 | 
| -    SkOpts::color_xform_RGB1_to_linear(dst, src, len, fSrcGammaTables, fSrcToDst);
 | 
| -}
 | 
| -
 | 
| -///////////////////////////////////////////////////////////////////////////////////////////////////
 | 
| -
 | 
| -SkDefaultXform::SkDefaultXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatrix44& srcToDst,
 | 
| -                               const sk_sp<SkColorSpace>& dstSpace)
 | 
| -    : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT()))
 | 
| -    , fSrcToDst(srcToDst)
 | 
| -{
 | 
| -    build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kToLinear);
 | 
| -    build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, SkDefaultXform::kDstGammaTableSize,
 | 
| -                       dstSpace, kFromLinear);
 | 
| -}
 | 
| -
 | 
|  static float byte_to_float(uint8_t byte) {
 | 
|      return ((float) byte) * (1.0f / 255.0f);
 | 
|  }
 | 
| @@ -647,64 +589,96 @@ static void interp_3d_clut(float dst[3], float src[3], const SkColorLookUpTable*
 | 
|      }
 | 
|  }
 | 
|  
 | 
| -void SkDefaultXform::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const {
 | 
| +static void handle_color_lut(uint32_t* dst, const uint32_t* src, int len,
 | 
| +                             SkColorLookUpTable* colorLUT) {
 | 
|      while (len-- > 0) {
 | 
|          uint8_t r = (*src >>  0) & 0xFF,
 | 
|                  g = (*src >>  8) & 0xFF,
 | 
|                  b = (*src >> 16) & 0xFF;
 | 
|  
 | 
| -        if (fColorLUT) {
 | 
| -            float in[3];
 | 
| -            float out[3];
 | 
| +        float in[3];
 | 
| +        float out[3];
 | 
| +        in[0] = byte_to_float(r);
 | 
| +        in[1] = byte_to_float(g);
 | 
| +        in[2] = byte_to_float(b);
 | 
| +        interp_3d_clut(out, in, colorLUT);
 | 
|  
 | 
| -            in[0] = byte_to_float(r);
 | 
| -            in[1] = byte_to_float(g);
 | 
| -            in[2] = byte_to_float(b);
 | 
| +        r = sk_float_round2int(255.0f * clamp_normalized_float(out[0]));
 | 
| +        g = sk_float_round2int(255.0f * clamp_normalized_float(out[1]));
 | 
| +        b = sk_float_round2int(255.0f * clamp_normalized_float(out[2]));
 | 
| +        *dst = SkPackARGB_as_RGBA(0xFF, r, g, b);
 | 
|  
 | 
| -            interp_3d_clut(out, in, fColorLUT.get());
 | 
| +        src++;
 | 
| +        dst++;
 | 
| +    }
 | 
| +}
 | 
|  
 | 
| -            r = sk_float_round2int(255.0f * clamp_normalized_float(out[0]));
 | 
| -            g = sk_float_round2int(255.0f * clamp_normalized_float(out[1]));
 | 
| -            b = sk_float_round2int(255.0f * clamp_normalized_float(out[2]));
 | 
| -        }
 | 
| +///////////////////////////////////////////////////////////////////////////////////////////////////
 | 
|  
 | 
| -        // Convert to linear.
 | 
| -        float srcFloats[3];
 | 
| -        srcFloats[0] = fSrcGammaTables[0][r];
 | 
| -        srcFloats[1] = fSrcGammaTables[1][g];
 | 
| -        srcFloats[2] = fSrcGammaTables[2][b];
 | 
| -
 | 
| -        // Convert to dst gamut.
 | 
| -        float dstFloats[3];
 | 
| -        dstFloats[0] = srcFloats[0] * fSrcToDst.getFloat(0, 0) +
 | 
| -                       srcFloats[1] * fSrcToDst.getFloat(1, 0) +
 | 
| -                       srcFloats[2] * fSrcToDst.getFloat(2, 0) + fSrcToDst.getFloat(3, 0);
 | 
| -        dstFloats[1] = srcFloats[0] * fSrcToDst.getFloat(0, 1) +
 | 
| -                       srcFloats[1] * fSrcToDst.getFloat(1, 1) +
 | 
| -                       srcFloats[2] * fSrcToDst.getFloat(2, 1) + fSrcToDst.getFloat(3, 1);
 | 
| -        dstFloats[2] = srcFloats[0] * fSrcToDst.getFloat(0, 2) +
 | 
| -                       srcFloats[1] * fSrcToDst.getFloat(1, 2) +
 | 
| -                       srcFloats[2] * fSrcToDst.getFloat(2, 2) + fSrcToDst.getFloat(3, 2);
 | 
| -
 | 
| -        // Clamp to 0-1.
 | 
| -        dstFloats[0] = clamp_normalized_float(dstFloats[0]);
 | 
| -        dstFloats[1] = clamp_normalized_float(dstFloats[1]);
 | 
| -        dstFloats[2] = clamp_normalized_float(dstFloats[2]);
 | 
| -
 | 
| -        // Convert to dst gamma.
 | 
| -        r = fDstGammaTables[0][sk_float_round2int((kDstGammaTableSize - 1) * dstFloats[0])];
 | 
| -        g = fDstGammaTables[1][sk_float_round2int((kDstGammaTableSize - 1) * dstFloats[1])];
 | 
| -        b = fDstGammaTables[2][sk_float_round2int((kDstGammaTableSize - 1) * dstFloats[2])];
 | 
| -
 | 
| -        *dst = SkPackARGB32NoCheck(0xFF, r, g, b);
 | 
| +template <SkColorSpace::GammaNamed Dst>
 | 
| +SkColorSpaceXform_Base<Dst>::SkColorSpaceXform_Base(const sk_sp<SkColorSpace>& srcSpace,
 | 
| +                                                    const SkMatrix44& srcToDst,
 | 
| +                                                    const sk_sp<SkColorSpace>& dstSpace)
 | 
| +    : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT()))
 | 
| +{
 | 
| +    srcToDst.asRowMajorf(fSrcToDst);
 | 
| +    build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kToLinear);
 | 
| +    build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, kDstGammaTableSize,
 | 
| +                       dstSpace, kFromLinear);
 | 
| +}
 | 
|  
 | 
| -        dst++;
 | 
| -        src++;
 | 
| +template <>
 | 
| +void SkColorSpaceXform_Base<SkColorSpace::kSRGB_GammaNamed>
 | 
| +::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
 | 
| +{
 | 
| +    if (fColorLUT) {
 | 
| +        handle_color_lut(dst, src, len, fColorLUT.get());
 | 
| +        src = dst;
 | 
|      }
 | 
| +
 | 
| +    SkOpts::color_xform_RGB1_to_srgb(dst, src, len, fSrcGammaTables, fSrcToDst);
 | 
|  }
 | 
|  
 | 
| -void SkDefaultXform::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const {
 | 
| -    // FIXME (msarett):
 | 
| -    // Planning to delete SkDefaultXform.  Not going to bother to implement this.
 | 
| -    memset(dst, 0, len * sizeof(RGBAF16));
 | 
| +template <>
 | 
| +void SkColorSpaceXform_Base<SkColorSpace::k2Dot2Curve_GammaNamed>
 | 
| +::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
 | 
| +{
 | 
| +    if (fColorLUT) {
 | 
| +        handle_color_lut(dst, src, len, fColorLUT.get());
 | 
| +        src = dst;
 | 
| +    }
 | 
| +
 | 
| +    SkOpts::color_xform_RGB1_to_2dot2(dst, src, len, fSrcGammaTables, fSrcToDst);
 | 
| +}
 | 
| +
 | 
| +template <>
 | 
| +void SkColorSpaceXform_Base<SkColorSpace::kNonStandard_GammaNamed>
 | 
| +::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
 | 
| +{
 | 
| +    if (fColorLUT) {
 | 
| +        handle_color_lut(dst, src, len, fColorLUT.get());
 | 
| +        src = dst;
 | 
| +    }
 | 
| +
 | 
| +    SkOpts::color_xform_RGB1_to_table(dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
 | 
| +}
 | 
| +
 | 
| +template <SkColorSpace::GammaNamed T>
 | 
| +void SkColorSpaceXform_Base<T>
 | 
| +::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const
 | 
| +{
 | 
| +    if (fColorLUT) {
 | 
| +        size_t storageBytes = len * sizeof(RGBA32);
 | 
| +#if defined(GOOGLE3)
 | 
| +        // Stack frame size is limited in GOOGLE3.
 | 
| +        SkAutoSMalloc<256 * sizeof(RGBA32)> storage(storageBytes);
 | 
| +#else
 | 
| +        SkAutoSMalloc<1024 * sizeof(RGBA32)> storage(storageBytes);
 | 
| +#endif
 | 
| +
 | 
| +        handle_color_lut((RGBA32*) storage.get(), src, len, fColorLUT.get());
 | 
| +        src = (const RGBA32*) storage.get();
 | 
| +    }
 | 
| +
 | 
| +    SkOpts::color_xform_RGB1_to_linear(dst, src, len, fSrcGammaTables, fSrcToDst);
 | 
|  }
 | 
| 
 |