150d3b57c8aaa0f026b981101c45ea30361382940reed/* 250d3b57c8aaa0f026b981101c45ea30361382940reed * Copyright 2011 Google Inc. 350d3b57c8aaa0f026b981101c45ea30361382940reed * 450d3b57c8aaa0f026b981101c45ea30361382940reed * Use of this source code is governed by a BSD-style license that can be 550d3b57c8aaa0f026b981101c45ea30361382940reed * found in the LICENSE file. 650d3b57c8aaa0f026b981101c45ea30361382940reed */ 750d3b57c8aaa0f026b981101c45ea30361382940reed 850d3b57c8aaa0f026b981101c45ea30361382940reed#ifndef SkMatrix44_DEFINED 950d3b57c8aaa0f026b981101c45ea30361382940reed#define SkMatrix44_DEFINED 1050d3b57c8aaa0f026b981101c45ea30361382940reed 1150d3b57c8aaa0f026b981101c45ea30361382940reed#include "SkMatrix.h" 1250d3b57c8aaa0f026b981101c45ea30361382940reed#include "SkScalar.h" 1350d3b57c8aaa0f026b981101c45ea30361382940reed 1450d3b57c8aaa0f026b981101c45ea30361382940reed#ifdef SK_MSCALAR_IS_DOUBLE 1550d3b57c8aaa0f026b981101c45ea30361382940reed#ifdef SK_MSCALAR_IS_FLOAT 1650d3b57c8aaa0f026b981101c45ea30361382940reed #error "can't define MSCALAR both as DOUBLE and FLOAT" 1750d3b57c8aaa0f026b981101c45ea30361382940reed#endif 1850d3b57c8aaa0f026b981101c45ea30361382940reed typedef double SkMScalar; 1950d3b57c8aaa0f026b981101c45ea30361382940reed 2050d3b57c8aaa0f026b981101c45ea30361382940reed static inline double SkFloatToMScalar(float x) { 2150d3b57c8aaa0f026b981101c45ea30361382940reed return static_cast<double>(x); 2250d3b57c8aaa0f026b981101c45ea30361382940reed } 2350d3b57c8aaa0f026b981101c45ea30361382940reed static inline float SkMScalarToFloat(double x) { 2450d3b57c8aaa0f026b981101c45ea30361382940reed return static_cast<float>(x); 2550d3b57c8aaa0f026b981101c45ea30361382940reed } 2650d3b57c8aaa0f026b981101c45ea30361382940reed static inline double SkDoubleToMScalar(double x) { 2750d3b57c8aaa0f026b981101c45ea30361382940reed return x; 2850d3b57c8aaa0f026b981101c45ea30361382940reed } 2950d3b57c8aaa0f026b981101c45ea30361382940reed static inline double SkMScalarToDouble(double x) { 3050d3b57c8aaa0f026b981101c45ea30361382940reed return x; 3150d3b57c8aaa0f026b981101c45ea30361382940reed } 3250d3b57c8aaa0f026b981101c45ea30361382940reed static inline double SkMScalarAbs(double x) { 3350d3b57c8aaa0f026b981101c45ea30361382940reed return fabs(x); 3450d3b57c8aaa0f026b981101c45ea30361382940reed } 3550d3b57c8aaa0f026b981101c45ea30361382940reed static const SkMScalar SK_MScalarPI = 3.141592653589793; 3650d3b57c8aaa0f026b981101c45ea30361382940reed 3750d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarFloor(x) sk_double_floor(x) 3850d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarCeil(x) sk_double_ceil(x) 3950d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarRound(x) sk_double_round(x) 4050d3b57c8aaa0f026b981101c45ea30361382940reed 4150d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarFloorToInt(x) sk_double_floor2int(x) 4250d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarCeilToInt(x) sk_double_ceil2int(x) 4350d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarRoundToInt(x) sk_double_round2int(x) 4450d3b57c8aaa0f026b981101c45ea30361382940reed 4550d3b57c8aaa0f026b981101c45ea30361382940reed 4650d3b57c8aaa0f026b981101c45ea30361382940reed#elif defined SK_MSCALAR_IS_FLOAT 4750d3b57c8aaa0f026b981101c45ea30361382940reed#ifdef SK_MSCALAR_IS_DOUBLE 4850d3b57c8aaa0f026b981101c45ea30361382940reed #error "can't define MSCALAR both as DOUBLE and FLOAT" 4950d3b57c8aaa0f026b981101c45ea30361382940reed#endif 5050d3b57c8aaa0f026b981101c45ea30361382940reed typedef float SkMScalar; 5150d3b57c8aaa0f026b981101c45ea30361382940reed 5250d3b57c8aaa0f026b981101c45ea30361382940reed static inline float SkFloatToMScalar(float x) { 5350d3b57c8aaa0f026b981101c45ea30361382940reed return x; 5450d3b57c8aaa0f026b981101c45ea30361382940reed } 5550d3b57c8aaa0f026b981101c45ea30361382940reed static inline float SkMScalarToFloat(float x) { 5650d3b57c8aaa0f026b981101c45ea30361382940reed return x; 5750d3b57c8aaa0f026b981101c45ea30361382940reed } 5850d3b57c8aaa0f026b981101c45ea30361382940reed static inline float SkDoubleToMScalar(double x) { 5950d3b57c8aaa0f026b981101c45ea30361382940reed return static_cast<float>(x); 6050d3b57c8aaa0f026b981101c45ea30361382940reed } 6150d3b57c8aaa0f026b981101c45ea30361382940reed static inline double SkMScalarToDouble(float x) { 6250d3b57c8aaa0f026b981101c45ea30361382940reed return static_cast<double>(x); 6350d3b57c8aaa0f026b981101c45ea30361382940reed } 6450d3b57c8aaa0f026b981101c45ea30361382940reed static inline float SkMScalarAbs(float x) { 6550d3b57c8aaa0f026b981101c45ea30361382940reed return sk_float_abs(x); 6650d3b57c8aaa0f026b981101c45ea30361382940reed } 6750d3b57c8aaa0f026b981101c45ea30361382940reed static const SkMScalar SK_MScalarPI = 3.14159265f; 6850d3b57c8aaa0f026b981101c45ea30361382940reed 6950d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarFloor(x) sk_float_floor(x) 7050d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarCeil(x) sk_float_ceil(x) 7150d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarRound(x) sk_float_round(x) 7250d3b57c8aaa0f026b981101c45ea30361382940reed 7350d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarFloorToInt(x) sk_float_floor2int(x) 7450d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarCeilToInt(x) sk_float_ceil2int(x) 7550d3b57c8aaa0f026b981101c45ea30361382940reed #define SkMScalarRoundToInt(x) sk_float_round2int(x) 7650d3b57c8aaa0f026b981101c45ea30361382940reed 7750d3b57c8aaa0f026b981101c45ea30361382940reed#endif 7850d3b57c8aaa0f026b981101c45ea30361382940reed 7950d3b57c8aaa0f026b981101c45ea30361382940reed#define SkIntToMScalar(n) static_cast<SkMScalar>(n) 8050d3b57c8aaa0f026b981101c45ea30361382940reed 8150d3b57c8aaa0f026b981101c45ea30361382940reed#define SkMScalarToScalar(x) SkMScalarToFloat(x) 8250d3b57c8aaa0f026b981101c45ea30361382940reed#define SkScalarToMScalar(x) SkFloatToMScalar(x) 8350d3b57c8aaa0f026b981101c45ea30361382940reed 8450d3b57c8aaa0f026b981101c45ea30361382940reedstatic const SkMScalar SK_MScalar1 = 1; 8550d3b57c8aaa0f026b981101c45ea30361382940reed 8650d3b57c8aaa0f026b981101c45ea30361382940reed/////////////////////////////////////////////////////////////////////////////// 8750d3b57c8aaa0f026b981101c45ea30361382940reed 8850d3b57c8aaa0f026b981101c45ea30361382940reedstruct SkVector4 { 8950d3b57c8aaa0f026b981101c45ea30361382940reed SkScalar fData[4]; 9050d3b57c8aaa0f026b981101c45ea30361382940reed 9150d3b57c8aaa0f026b981101c45ea30361382940reed SkVector4() { 9250d3b57c8aaa0f026b981101c45ea30361382940reed this->set(0, 0, 0, 1); 9350d3b57c8aaa0f026b981101c45ea30361382940reed } 9450d3b57c8aaa0f026b981101c45ea30361382940reed SkVector4(const SkVector4& src) { 9550d3b57c8aaa0f026b981101c45ea30361382940reed memcpy(fData, src.fData, sizeof(fData)); 9650d3b57c8aaa0f026b981101c45ea30361382940reed } 9750d3b57c8aaa0f026b981101c45ea30361382940reed SkVector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { 9850d3b57c8aaa0f026b981101c45ea30361382940reed fData[0] = x; 9950d3b57c8aaa0f026b981101c45ea30361382940reed fData[1] = y; 10050d3b57c8aaa0f026b981101c45ea30361382940reed fData[2] = z; 10150d3b57c8aaa0f026b981101c45ea30361382940reed fData[3] = w; 10250d3b57c8aaa0f026b981101c45ea30361382940reed } 10350d3b57c8aaa0f026b981101c45ea30361382940reed 10450d3b57c8aaa0f026b981101c45ea30361382940reed SkVector4& operator=(const SkVector4& src) { 10550d3b57c8aaa0f026b981101c45ea30361382940reed memcpy(fData, src.fData, sizeof(fData)); 10650d3b57c8aaa0f026b981101c45ea30361382940reed return *this; 10750d3b57c8aaa0f026b981101c45ea30361382940reed } 10850d3b57c8aaa0f026b981101c45ea30361382940reed 10950d3b57c8aaa0f026b981101c45ea30361382940reed bool operator==(const SkVector4& v) { 11050d3b57c8aaa0f026b981101c45ea30361382940reed return fData[0] == v.fData[0] && fData[1] == v.fData[1] && 11150d3b57c8aaa0f026b981101c45ea30361382940reed fData[2] == v.fData[2] && fData[3] == v.fData[3]; 11250d3b57c8aaa0f026b981101c45ea30361382940reed } 11350d3b57c8aaa0f026b981101c45ea30361382940reed bool operator!=(const SkVector4& v) { 11450d3b57c8aaa0f026b981101c45ea30361382940reed return !(*this == v); 11550d3b57c8aaa0f026b981101c45ea30361382940reed } 11650d3b57c8aaa0f026b981101c45ea30361382940reed bool equals(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { 11750d3b57c8aaa0f026b981101c45ea30361382940reed return fData[0] == x && fData[1] == y && 11850d3b57c8aaa0f026b981101c45ea30361382940reed fData[2] == z && fData[3] == w; 11950d3b57c8aaa0f026b981101c45ea30361382940reed } 12050d3b57c8aaa0f026b981101c45ea30361382940reed 12150d3b57c8aaa0f026b981101c45ea30361382940reed void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) { 12250d3b57c8aaa0f026b981101c45ea30361382940reed fData[0] = x; 12350d3b57c8aaa0f026b981101c45ea30361382940reed fData[1] = y; 12450d3b57c8aaa0f026b981101c45ea30361382940reed fData[2] = z; 12550d3b57c8aaa0f026b981101c45ea30361382940reed fData[3] = w; 12650d3b57c8aaa0f026b981101c45ea30361382940reed } 12750d3b57c8aaa0f026b981101c45ea30361382940reed}; 12850d3b57c8aaa0f026b981101c45ea30361382940reed 129afe7a5f84890b88dbb61a3ba53b3d66d679f92d7Mike Klein/** \class SkMatrix44 130afe7a5f84890b88dbb61a3ba53b3d66d679f92d7Mike Klein 131afe7a5f84890b88dbb61a3ba53b3d66d679f92d7Mike Klein The SkMatrix44 class holds a 4x4 matrix. 132afe7a5f84890b88dbb61a3ba53b3d66d679f92d7Mike Klein 133afe7a5f84890b88dbb61a3ba53b3d66d679f92d7Mike Klein SkMatrix44 is not thread safe unless you've first called SkMatrix44::getType(). 134afe7a5f84890b88dbb61a3ba53b3d66d679f92d7Mike Klein*/ 13550d3b57c8aaa0f026b981101c45ea30361382940reedclass SK_API SkMatrix44 { 13650d3b57c8aaa0f026b981101c45ea30361382940reedpublic: 13750d3b57c8aaa0f026b981101c45ea30361382940reed 13850d3b57c8aaa0f026b981101c45ea30361382940reed enum Uninitialized_Constructor { 13950d3b57c8aaa0f026b981101c45ea30361382940reed kUninitialized_Constructor 14050d3b57c8aaa0f026b981101c45ea30361382940reed }; 14150d3b57c8aaa0f026b981101c45ea30361382940reed enum Identity_Constructor { 14250d3b57c8aaa0f026b981101c45ea30361382940reed kIdentity_Constructor 14350d3b57c8aaa0f026b981101c45ea30361382940reed }; 14450d3b57c8aaa0f026b981101c45ea30361382940reed 145c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett SkMatrix44(Uninitialized_Constructor) {} 146c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett 147c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett constexpr SkMatrix44(Identity_Constructor) 148c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett : fMat{{ 1, 0, 0, 0, }, 149c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett { 0, 1, 0, 0, }, 150c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett { 0, 0, 1, 0, }, 151c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett { 0, 0, 0, 1, }} 152c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett , fTypeMask(kIdentity_Mask) 153c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett {} 15450d3b57c8aaa0f026b981101c45ea30361382940reed 15550d3b57c8aaa0f026b981101c45ea30361382940reed SK_ATTR_DEPRECATED("use the constructors that take an enum") 15650d3b57c8aaa0f026b981101c45ea30361382940reed SkMatrix44() { this->setIdentity(); } 15750d3b57c8aaa0f026b981101c45ea30361382940reed 15850d3b57c8aaa0f026b981101c45ea30361382940reed SkMatrix44(const SkMatrix44& src) { 15950d3b57c8aaa0f026b981101c45ea30361382940reed memcpy(fMat, src.fMat, sizeof(fMat)); 16050d3b57c8aaa0f026b981101c45ea30361382940reed fTypeMask = src.fTypeMask; 16150d3b57c8aaa0f026b981101c45ea30361382940reed } 16250d3b57c8aaa0f026b981101c45ea30361382940reed 16350d3b57c8aaa0f026b981101c45ea30361382940reed SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) { 16450d3b57c8aaa0f026b981101c45ea30361382940reed this->setConcat(a, b); 16550d3b57c8aaa0f026b981101c45ea30361382940reed } 16650d3b57c8aaa0f026b981101c45ea30361382940reed 16750d3b57c8aaa0f026b981101c45ea30361382940reed SkMatrix44& operator=(const SkMatrix44& src) { 16850d3b57c8aaa0f026b981101c45ea30361382940reed if (&src != this) { 16950d3b57c8aaa0f026b981101c45ea30361382940reed memcpy(fMat, src.fMat, sizeof(fMat)); 17050d3b57c8aaa0f026b981101c45ea30361382940reed fTypeMask = src.fTypeMask; 17150d3b57c8aaa0f026b981101c45ea30361382940reed } 17250d3b57c8aaa0f026b981101c45ea30361382940reed return *this; 17350d3b57c8aaa0f026b981101c45ea30361382940reed } 17450d3b57c8aaa0f026b981101c45ea30361382940reed 17550d3b57c8aaa0f026b981101c45ea30361382940reed bool operator==(const SkMatrix44& other) const; 17650d3b57c8aaa0f026b981101c45ea30361382940reed bool operator!=(const SkMatrix44& other) const { 17750d3b57c8aaa0f026b981101c45ea30361382940reed return !(other == *this); 17850d3b57c8aaa0f026b981101c45ea30361382940reed } 17950d3b57c8aaa0f026b981101c45ea30361382940reed 18050d3b57c8aaa0f026b981101c45ea30361382940reed /* When converting from SkMatrix44 to SkMatrix, the third row and 18150d3b57c8aaa0f026b981101c45ea30361382940reed * column is dropped. When converting from SkMatrix to SkMatrix44 18250d3b57c8aaa0f026b981101c45ea30361382940reed * the third row and column remain as identity: 18350d3b57c8aaa0f026b981101c45ea30361382940reed * [ a b c ] [ a b 0 c ] 18450d3b57c8aaa0f026b981101c45ea30361382940reed * [ d e f ] -> [ d e 0 f ] 18550d3b57c8aaa0f026b981101c45ea30361382940reed * [ g h i ] [ 0 0 1 0 ] 18650d3b57c8aaa0f026b981101c45ea30361382940reed * [ g h 0 i ] 18750d3b57c8aaa0f026b981101c45ea30361382940reed */ 18850d3b57c8aaa0f026b981101c45ea30361382940reed SkMatrix44(const SkMatrix&); 18950d3b57c8aaa0f026b981101c45ea30361382940reed SkMatrix44& operator=(const SkMatrix& src); 19050d3b57c8aaa0f026b981101c45ea30361382940reed operator SkMatrix() const; 19150d3b57c8aaa0f026b981101c45ea30361382940reed 19250d3b57c8aaa0f026b981101c45ea30361382940reed /** 19350d3b57c8aaa0f026b981101c45ea30361382940reed * Return a reference to a const identity matrix 19450d3b57c8aaa0f026b981101c45ea30361382940reed */ 19550d3b57c8aaa0f026b981101c45ea30361382940reed static const SkMatrix44& I(); 19650d3b57c8aaa0f026b981101c45ea30361382940reed 19750d3b57c8aaa0f026b981101c45ea30361382940reed enum TypeMask { 19850d3b57c8aaa0f026b981101c45ea30361382940reed kIdentity_Mask = 0, 19950d3b57c8aaa0f026b981101c45ea30361382940reed kTranslate_Mask = 0x01, //!< set if the matrix has translation 20050d3b57c8aaa0f026b981101c45ea30361382940reed kScale_Mask = 0x02, //!< set if the matrix has any scale != 1 20150d3b57c8aaa0f026b981101c45ea30361382940reed kAffine_Mask = 0x04, //!< set if the matrix skews or rotates 20250d3b57c8aaa0f026b981101c45ea30361382940reed kPerspective_Mask = 0x08 //!< set if the matrix is in perspective 20350d3b57c8aaa0f026b981101c45ea30361382940reed }; 20450d3b57c8aaa0f026b981101c45ea30361382940reed 20550d3b57c8aaa0f026b981101c45ea30361382940reed /** 20650d3b57c8aaa0f026b981101c45ea30361382940reed * Returns a bitfield describing the transformations the matrix may 20750d3b57c8aaa0f026b981101c45ea30361382940reed * perform. The bitfield is computed conservatively, so it may include 20850d3b57c8aaa0f026b981101c45ea30361382940reed * false positives. For example, when kPerspective_Mask is true, all 20950d3b57c8aaa0f026b981101c45ea30361382940reed * other bits may be set to true even in the case of a pure perspective 21050d3b57c8aaa0f026b981101c45ea30361382940reed * transform. 21150d3b57c8aaa0f026b981101c45ea30361382940reed */ 21250d3b57c8aaa0f026b981101c45ea30361382940reed inline TypeMask getType() const { 21350d3b57c8aaa0f026b981101c45ea30361382940reed if (fTypeMask & kUnknown_Mask) { 21450d3b57c8aaa0f026b981101c45ea30361382940reed fTypeMask = this->computeTypeMask(); 21550d3b57c8aaa0f026b981101c45ea30361382940reed } 21650d3b57c8aaa0f026b981101c45ea30361382940reed SkASSERT(!(fTypeMask & kUnknown_Mask)); 21750d3b57c8aaa0f026b981101c45ea30361382940reed return (TypeMask)fTypeMask; 21850d3b57c8aaa0f026b981101c45ea30361382940reed } 21950d3b57c8aaa0f026b981101c45ea30361382940reed 22050d3b57c8aaa0f026b981101c45ea30361382940reed /** 22150d3b57c8aaa0f026b981101c45ea30361382940reed * Return true if the matrix is identity. 22250d3b57c8aaa0f026b981101c45ea30361382940reed */ 22350d3b57c8aaa0f026b981101c45ea30361382940reed inline bool isIdentity() const { 22450d3b57c8aaa0f026b981101c45ea30361382940reed return kIdentity_Mask == this->getType(); 22550d3b57c8aaa0f026b981101c45ea30361382940reed } 22650d3b57c8aaa0f026b981101c45ea30361382940reed 22750d3b57c8aaa0f026b981101c45ea30361382940reed /** 22850d3b57c8aaa0f026b981101c45ea30361382940reed * Return true if the matrix contains translate or is identity. 22950d3b57c8aaa0f026b981101c45ea30361382940reed */ 23050d3b57c8aaa0f026b981101c45ea30361382940reed inline bool isTranslate() const { 23150d3b57c8aaa0f026b981101c45ea30361382940reed return !(this->getType() & ~kTranslate_Mask); 23250d3b57c8aaa0f026b981101c45ea30361382940reed } 23350d3b57c8aaa0f026b981101c45ea30361382940reed 23450d3b57c8aaa0f026b981101c45ea30361382940reed /** 23550d3b57c8aaa0f026b981101c45ea30361382940reed * Return true if the matrix only contains scale or translate or is identity. 23650d3b57c8aaa0f026b981101c45ea30361382940reed */ 23750d3b57c8aaa0f026b981101c45ea30361382940reed inline bool isScaleTranslate() const { 23850d3b57c8aaa0f026b981101c45ea30361382940reed return !(this->getType() & ~(kScale_Mask | kTranslate_Mask)); 23950d3b57c8aaa0f026b981101c45ea30361382940reed } 24050d3b57c8aaa0f026b981101c45ea30361382940reed 24150d3b57c8aaa0f026b981101c45ea30361382940reed /** 24250d3b57c8aaa0f026b981101c45ea30361382940reed * Returns true if the matrix only contains scale or is identity. 24350d3b57c8aaa0f026b981101c45ea30361382940reed */ 24450d3b57c8aaa0f026b981101c45ea30361382940reed inline bool isScale() const { 24550d3b57c8aaa0f026b981101c45ea30361382940reed return !(this->getType() & ~kScale_Mask); 24650d3b57c8aaa0f026b981101c45ea30361382940reed } 24750d3b57c8aaa0f026b981101c45ea30361382940reed 24850d3b57c8aaa0f026b981101c45ea30361382940reed inline bool hasPerspective() const { 24950d3b57c8aaa0f026b981101c45ea30361382940reed return SkToBool(this->getType() & kPerspective_Mask); 25050d3b57c8aaa0f026b981101c45ea30361382940reed } 25150d3b57c8aaa0f026b981101c45ea30361382940reed 25250d3b57c8aaa0f026b981101c45ea30361382940reed void setIdentity(); 25350d3b57c8aaa0f026b981101c45ea30361382940reed inline void reset() { this->setIdentity();} 25450d3b57c8aaa0f026b981101c45ea30361382940reed 25550d3b57c8aaa0f026b981101c45ea30361382940reed /** 25650d3b57c8aaa0f026b981101c45ea30361382940reed * get a value from the matrix. The row,col parameters work as follows: 25750d3b57c8aaa0f026b981101c45ea30361382940reed * (0, 0) scale-x 25850d3b57c8aaa0f026b981101c45ea30361382940reed * (0, 3) translate-x 25950d3b57c8aaa0f026b981101c45ea30361382940reed * (3, 0) perspective-x 26050d3b57c8aaa0f026b981101c45ea30361382940reed */ 26150d3b57c8aaa0f026b981101c45ea30361382940reed inline SkMScalar get(int row, int col) const { 26250d3b57c8aaa0f026b981101c45ea30361382940reed SkASSERT((unsigned)row <= 3); 26350d3b57c8aaa0f026b981101c45ea30361382940reed SkASSERT((unsigned)col <= 3); 26450d3b57c8aaa0f026b981101c45ea30361382940reed return fMat[col][row]; 26550d3b57c8aaa0f026b981101c45ea30361382940reed } 26650d3b57c8aaa0f026b981101c45ea30361382940reed 26750d3b57c8aaa0f026b981101c45ea30361382940reed /** 26850d3b57c8aaa0f026b981101c45ea30361382940reed * set a value in the matrix. The row,col parameters work as follows: 26950d3b57c8aaa0f026b981101c45ea30361382940reed * (0, 0) scale-x 27050d3b57c8aaa0f026b981101c45ea30361382940reed * (0, 3) translate-x 27150d3b57c8aaa0f026b981101c45ea30361382940reed * (3, 0) perspective-x 27250d3b57c8aaa0f026b981101c45ea30361382940reed */ 27350d3b57c8aaa0f026b981101c45ea30361382940reed inline void set(int row, int col, SkMScalar value) { 27450d3b57c8aaa0f026b981101c45ea30361382940reed SkASSERT((unsigned)row <= 3); 27550d3b57c8aaa0f026b981101c45ea30361382940reed SkASSERT((unsigned)col <= 3); 27650d3b57c8aaa0f026b981101c45ea30361382940reed fMat[col][row] = value; 27750d3b57c8aaa0f026b981101c45ea30361382940reed this->dirtyTypeMask(); 27850d3b57c8aaa0f026b981101c45ea30361382940reed } 27950d3b57c8aaa0f026b981101c45ea30361382940reed 28050d3b57c8aaa0f026b981101c45ea30361382940reed inline double getDouble(int row, int col) const { 28150d3b57c8aaa0f026b981101c45ea30361382940reed return SkMScalarToDouble(this->get(row, col)); 28250d3b57c8aaa0f026b981101c45ea30361382940reed } 28350d3b57c8aaa0f026b981101c45ea30361382940reed inline void setDouble(int row, int col, double value) { 28450d3b57c8aaa0f026b981101c45ea30361382940reed this->set(row, col, SkDoubleToMScalar(value)); 28550d3b57c8aaa0f026b981101c45ea30361382940reed } 28650d3b57c8aaa0f026b981101c45ea30361382940reed inline float getFloat(int row, int col) const { 28750d3b57c8aaa0f026b981101c45ea30361382940reed return SkMScalarToFloat(this->get(row, col)); 28850d3b57c8aaa0f026b981101c45ea30361382940reed } 28950d3b57c8aaa0f026b981101c45ea30361382940reed inline void setFloat(int row, int col, float value) { 29050d3b57c8aaa0f026b981101c45ea30361382940reed this->set(row, col, SkFloatToMScalar(value)); 29150d3b57c8aaa0f026b981101c45ea30361382940reed } 29250d3b57c8aaa0f026b981101c45ea30361382940reed 29350d3b57c8aaa0f026b981101c45ea30361382940reed /** These methods allow one to efficiently read matrix entries into an 29450d3b57c8aaa0f026b981101c45ea30361382940reed * array. The given array must have room for exactly 16 entries. Whenever 29550d3b57c8aaa0f026b981101c45ea30361382940reed * possible, they will try to use memcpy rather than an entry-by-entry 29650d3b57c8aaa0f026b981101c45ea30361382940reed * copy. 297c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett * 298c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett * Col major indicates that consecutive elements of columns will be stored 299c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett * contiguously in memory. Row major indicates that consecutive elements 300c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett * of rows will be stored contiguously in memory. 30150d3b57c8aaa0f026b981101c45ea30361382940reed */ 30250d3b57c8aaa0f026b981101c45ea30361382940reed void asColMajorf(float[]) const; 30350d3b57c8aaa0f026b981101c45ea30361382940reed void asColMajord(double[]) const; 30450d3b57c8aaa0f026b981101c45ea30361382940reed void asRowMajorf(float[]) const; 30550d3b57c8aaa0f026b981101c45ea30361382940reed void asRowMajord(double[]) const; 30650d3b57c8aaa0f026b981101c45ea30361382940reed 30750d3b57c8aaa0f026b981101c45ea30361382940reed /** These methods allow one to efficiently set all matrix entries from an 30850d3b57c8aaa0f026b981101c45ea30361382940reed * array. The given array must have room for exactly 16 entries. Whenever 30950d3b57c8aaa0f026b981101c45ea30361382940reed * possible, they will try to use memcpy rather than an entry-by-entry 31050d3b57c8aaa0f026b981101c45ea30361382940reed * copy. 311c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett * 312c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett * Col major indicates that input memory will be treated as if consecutive 313c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett * elements of columns are stored contiguously in memory. Row major 314c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett * indicates that input memory will be treated as if consecutive elements 315c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett * of rows are stored contiguously in memory. 31650d3b57c8aaa0f026b981101c45ea30361382940reed */ 31750d3b57c8aaa0f026b981101c45ea30361382940reed void setColMajorf(const float[]); 31850d3b57c8aaa0f026b981101c45ea30361382940reed void setColMajord(const double[]); 31950d3b57c8aaa0f026b981101c45ea30361382940reed void setRowMajorf(const float[]); 32050d3b57c8aaa0f026b981101c45ea30361382940reed void setRowMajord(const double[]); 32150d3b57c8aaa0f026b981101c45ea30361382940reed 32250d3b57c8aaa0f026b981101c45ea30361382940reed#ifdef SK_MSCALAR_IS_FLOAT 32350d3b57c8aaa0f026b981101c45ea30361382940reed void setColMajor(const SkMScalar data[]) { this->setColMajorf(data); } 32450d3b57c8aaa0f026b981101c45ea30361382940reed void setRowMajor(const SkMScalar data[]) { this->setRowMajorf(data); } 32550d3b57c8aaa0f026b981101c45ea30361382940reed#else 32650d3b57c8aaa0f026b981101c45ea30361382940reed void setColMajor(const SkMScalar data[]) { this->setColMajord(data); } 32750d3b57c8aaa0f026b981101c45ea30361382940reed void setRowMajor(const SkMScalar data[]) { this->setRowMajord(data); } 32850d3b57c8aaa0f026b981101c45ea30361382940reed#endif 32950d3b57c8aaa0f026b981101c45ea30361382940reed 33050d3b57c8aaa0f026b981101c45ea30361382940reed /* This sets the top-left of the matrix and clears the translation and 331c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett * perspective components (with [3][3] set to 1). mXY is interpreted 332c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett * as the matrix entry at col = X, row = Y. */ 33350d3b57c8aaa0f026b981101c45ea30361382940reed void set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02, 33450d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar m10, SkMScalar m11, SkMScalar m12, 33550d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar m20, SkMScalar m21, SkMScalar m22); 336c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett void set3x3RowMajorf(const float[]); 33750d3b57c8aaa0f026b981101c45ea30361382940reed 33850d3b57c8aaa0f026b981101c45ea30361382940reed void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); 33950d3b57c8aaa0f026b981101c45ea30361382940reed void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); 34050d3b57c8aaa0f026b981101c45ea30361382940reed void postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); 34150d3b57c8aaa0f026b981101c45ea30361382940reed 34250d3b57c8aaa0f026b981101c45ea30361382940reed void setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); 34350d3b57c8aaa0f026b981101c45ea30361382940reed void preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); 34450d3b57c8aaa0f026b981101c45ea30361382940reed void postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz); 34550d3b57c8aaa0f026b981101c45ea30361382940reed 34650d3b57c8aaa0f026b981101c45ea30361382940reed inline void setScale(SkMScalar scale) { 34750d3b57c8aaa0f026b981101c45ea30361382940reed this->setScale(scale, scale, scale); 34850d3b57c8aaa0f026b981101c45ea30361382940reed } 34950d3b57c8aaa0f026b981101c45ea30361382940reed inline void preScale(SkMScalar scale) { 35050d3b57c8aaa0f026b981101c45ea30361382940reed this->preScale(scale, scale, scale); 35150d3b57c8aaa0f026b981101c45ea30361382940reed } 35250d3b57c8aaa0f026b981101c45ea30361382940reed inline void postScale(SkMScalar scale) { 35350d3b57c8aaa0f026b981101c45ea30361382940reed this->postScale(scale, scale, scale); 35450d3b57c8aaa0f026b981101c45ea30361382940reed } 35550d3b57c8aaa0f026b981101c45ea30361382940reed 35650d3b57c8aaa0f026b981101c45ea30361382940reed void setRotateDegreesAbout(SkMScalar x, SkMScalar y, SkMScalar z, 35750d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar degrees) { 35850d3b57c8aaa0f026b981101c45ea30361382940reed this->setRotateAbout(x, y, z, degrees * SK_MScalarPI / 180); 35950d3b57c8aaa0f026b981101c45ea30361382940reed } 36050d3b57c8aaa0f026b981101c45ea30361382940reed 36150d3b57c8aaa0f026b981101c45ea30361382940reed /** Rotate about the vector [x,y,z]. If that vector is not unit-length, 36250d3b57c8aaa0f026b981101c45ea30361382940reed it will be automatically resized. 36350d3b57c8aaa0f026b981101c45ea30361382940reed */ 36450d3b57c8aaa0f026b981101c45ea30361382940reed void setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z, 36550d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar radians); 36650d3b57c8aaa0f026b981101c45ea30361382940reed /** Rotate about the vector [x,y,z]. Does not check the length of the 36750d3b57c8aaa0f026b981101c45ea30361382940reed vector, assuming it is unit-length. 36850d3b57c8aaa0f026b981101c45ea30361382940reed */ 36950d3b57c8aaa0f026b981101c45ea30361382940reed void setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z, 37050d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar radians); 37150d3b57c8aaa0f026b981101c45ea30361382940reed 37250d3b57c8aaa0f026b981101c45ea30361382940reed void setConcat(const SkMatrix44& a, const SkMatrix44& b); 37350d3b57c8aaa0f026b981101c45ea30361382940reed inline void preConcat(const SkMatrix44& m) { 37450d3b57c8aaa0f026b981101c45ea30361382940reed this->setConcat(*this, m); 37550d3b57c8aaa0f026b981101c45ea30361382940reed } 37650d3b57c8aaa0f026b981101c45ea30361382940reed inline void postConcat(const SkMatrix44& m) { 37750d3b57c8aaa0f026b981101c45ea30361382940reed this->setConcat(m, *this); 37850d3b57c8aaa0f026b981101c45ea30361382940reed } 37950d3b57c8aaa0f026b981101c45ea30361382940reed 38050d3b57c8aaa0f026b981101c45ea30361382940reed friend SkMatrix44 operator*(const SkMatrix44& a, const SkMatrix44& b) { 38150d3b57c8aaa0f026b981101c45ea30361382940reed return SkMatrix44(a, b); 38250d3b57c8aaa0f026b981101c45ea30361382940reed } 38350d3b57c8aaa0f026b981101c45ea30361382940reed 38450d3b57c8aaa0f026b981101c45ea30361382940reed /** If this is invertible, return that in inverse and return true. If it is 38550d3b57c8aaa0f026b981101c45ea30361382940reed not invertible, return false and leave the inverse parameter in an 38650d3b57c8aaa0f026b981101c45ea30361382940reed unspecified state. 38750d3b57c8aaa0f026b981101c45ea30361382940reed */ 38850d3b57c8aaa0f026b981101c45ea30361382940reed bool invert(SkMatrix44* inverse) const; 38950d3b57c8aaa0f026b981101c45ea30361382940reed 39050d3b57c8aaa0f026b981101c45ea30361382940reed /** Transpose this matrix in place. */ 39150d3b57c8aaa0f026b981101c45ea30361382940reed void transpose(); 39250d3b57c8aaa0f026b981101c45ea30361382940reed 39350d3b57c8aaa0f026b981101c45ea30361382940reed /** Apply the matrix to the src vector, returning the new vector in dst. 39450d3b57c8aaa0f026b981101c45ea30361382940reed It is legal for src and dst to point to the same memory. 39550d3b57c8aaa0f026b981101c45ea30361382940reed */ 39650d3b57c8aaa0f026b981101c45ea30361382940reed void mapScalars(const SkScalar src[4], SkScalar dst[4]) const; 39750d3b57c8aaa0f026b981101c45ea30361382940reed inline void mapScalars(SkScalar vec[4]) const { 39850d3b57c8aaa0f026b981101c45ea30361382940reed this->mapScalars(vec, vec); 39950d3b57c8aaa0f026b981101c45ea30361382940reed } 40050d3b57c8aaa0f026b981101c45ea30361382940reed 40150d3b57c8aaa0f026b981101c45ea30361382940reed SK_ATTR_DEPRECATED("use mapScalars") 40250d3b57c8aaa0f026b981101c45ea30361382940reed void map(const SkScalar src[4], SkScalar dst[4]) const { 40350d3b57c8aaa0f026b981101c45ea30361382940reed this->mapScalars(src, dst); 40450d3b57c8aaa0f026b981101c45ea30361382940reed } 40550d3b57c8aaa0f026b981101c45ea30361382940reed 40650d3b57c8aaa0f026b981101c45ea30361382940reed SK_ATTR_DEPRECATED("use mapScalars") 40750d3b57c8aaa0f026b981101c45ea30361382940reed void map(SkScalar vec[4]) const { 40850d3b57c8aaa0f026b981101c45ea30361382940reed this->mapScalars(vec, vec); 40950d3b57c8aaa0f026b981101c45ea30361382940reed } 41050d3b57c8aaa0f026b981101c45ea30361382940reed 41150d3b57c8aaa0f026b981101c45ea30361382940reed#ifdef SK_MSCALAR_IS_DOUBLE 41250d3b57c8aaa0f026b981101c45ea30361382940reed void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const; 41350d3b57c8aaa0f026b981101c45ea30361382940reed#elif defined SK_MSCALAR_IS_FLOAT 41450d3b57c8aaa0f026b981101c45ea30361382940reed inline void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const { 41550d3b57c8aaa0f026b981101c45ea30361382940reed this->mapScalars(src, dst); 41650d3b57c8aaa0f026b981101c45ea30361382940reed } 41750d3b57c8aaa0f026b981101c45ea30361382940reed#endif 41850d3b57c8aaa0f026b981101c45ea30361382940reed inline void mapMScalars(SkMScalar vec[4]) const { 41950d3b57c8aaa0f026b981101c45ea30361382940reed this->mapMScalars(vec, vec); 42050d3b57c8aaa0f026b981101c45ea30361382940reed } 42150d3b57c8aaa0f026b981101c45ea30361382940reed 42250d3b57c8aaa0f026b981101c45ea30361382940reed friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) { 42350d3b57c8aaa0f026b981101c45ea30361382940reed SkVector4 dst; 42450d3b57c8aaa0f026b981101c45ea30361382940reed m.mapScalars(src.fData, dst.fData); 42550d3b57c8aaa0f026b981101c45ea30361382940reed return dst; 42650d3b57c8aaa0f026b981101c45ea30361382940reed } 42750d3b57c8aaa0f026b981101c45ea30361382940reed 42850d3b57c8aaa0f026b981101c45ea30361382940reed /** 42950d3b57c8aaa0f026b981101c45ea30361382940reed * map an array of [x, y, 0, 1] through the matrix, returning an array 43050d3b57c8aaa0f026b981101c45ea30361382940reed * of [x', y', z', w']. 43150d3b57c8aaa0f026b981101c45ea30361382940reed * 43250d3b57c8aaa0f026b981101c45ea30361382940reed * @param src2 array of [x, y] pairs, with implied z=0 and w=1 43350d3b57c8aaa0f026b981101c45ea30361382940reed * @param count number of [x, y] pairs in src2 43450d3b57c8aaa0f026b981101c45ea30361382940reed * @param dst4 array of [x', y', z', w'] quads as the output. 43550d3b57c8aaa0f026b981101c45ea30361382940reed */ 43650d3b57c8aaa0f026b981101c45ea30361382940reed void map2(const float src2[], int count, float dst4[]) const; 43750d3b57c8aaa0f026b981101c45ea30361382940reed void map2(const double src2[], int count, double dst4[]) const; 43850d3b57c8aaa0f026b981101c45ea30361382940reed 43950d3b57c8aaa0f026b981101c45ea30361382940reed /** Returns true if transformating an axis-aligned square in 2d by this matrix 44050d3b57c8aaa0f026b981101c45ea30361382940reed will produce another 2d axis-aligned square; typically means the matrix 44150d3b57c8aaa0f026b981101c45ea30361382940reed is a scale with perhaps a 90-degree rotation. A 3d rotation through 90 44250d3b57c8aaa0f026b981101c45ea30361382940reed degrees into a perpendicular plane collapses a square to a line, but 44350d3b57c8aaa0f026b981101c45ea30361382940reed is still considered to be axis-aligned. 44450d3b57c8aaa0f026b981101c45ea30361382940reed 44550d3b57c8aaa0f026b981101c45ea30361382940reed By default, tolerates very slight error due to float imprecisions; 44650d3b57c8aaa0f026b981101c45ea30361382940reed a 90-degree rotation can still end up with 10^-17 of 44750d3b57c8aaa0f026b981101c45ea30361382940reed "non-axis-aligned" result. 44850d3b57c8aaa0f026b981101c45ea30361382940reed */ 44950d3b57c8aaa0f026b981101c45ea30361382940reed bool preserves2dAxisAlignment(SkMScalar epsilon = SK_ScalarNearlyZero) const; 45050d3b57c8aaa0f026b981101c45ea30361382940reed 45150d3b57c8aaa0f026b981101c45ea30361382940reed void dump() const; 45250d3b57c8aaa0f026b981101c45ea30361382940reed 45350d3b57c8aaa0f026b981101c45ea30361382940reed double determinant() const; 45450d3b57c8aaa0f026b981101c45ea30361382940reed 45550d3b57c8aaa0f026b981101c45ea30361382940reedprivate: 456c1a3e24918f99fc0b975111afb39dca38c50eb5cmsarett /* This is indexed by [col][row]. */ 45750d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar fMat[4][4]; 45850d3b57c8aaa0f026b981101c45ea30361382940reed mutable unsigned fTypeMask; 45950d3b57c8aaa0f026b981101c45ea30361382940reed 46050d3b57c8aaa0f026b981101c45ea30361382940reed enum { 46150d3b57c8aaa0f026b981101c45ea30361382940reed kUnknown_Mask = 0x80, 46250d3b57c8aaa0f026b981101c45ea30361382940reed 46350d3b57c8aaa0f026b981101c45ea30361382940reed kAllPublic_Masks = 0xF 46450d3b57c8aaa0f026b981101c45ea30361382940reed }; 46550d3b57c8aaa0f026b981101c45ea30361382940reed 466de68d6c4616d86621373d88100002ddfdb9c08e3brianosman void as3x4RowMajorf(float[]) const; 467de68d6c4616d86621373d88100002ddfdb9c08e3brianosman void set3x4RowMajorf(const float[]); 468111a42d9cebf0bb8844c5d24f67fac57cc619d29msarett 46950d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar transX() const { return fMat[3][0]; } 47050d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar transY() const { return fMat[3][1]; } 47150d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar transZ() const { return fMat[3][2]; } 47250d3b57c8aaa0f026b981101c45ea30361382940reed 47350d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar scaleX() const { return fMat[0][0]; } 47450d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar scaleY() const { return fMat[1][1]; } 47550d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar scaleZ() const { return fMat[2][2]; } 47650d3b57c8aaa0f026b981101c45ea30361382940reed 47750d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar perspX() const { return fMat[0][3]; } 47850d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar perspY() const { return fMat[1][3]; } 47950d3b57c8aaa0f026b981101c45ea30361382940reed SkMScalar perspZ() const { return fMat[2][3]; } 48050d3b57c8aaa0f026b981101c45ea30361382940reed 48150d3b57c8aaa0f026b981101c45ea30361382940reed int computeTypeMask() const; 48250d3b57c8aaa0f026b981101c45ea30361382940reed 48350d3b57c8aaa0f026b981101c45ea30361382940reed inline void dirtyTypeMask() { 48450d3b57c8aaa0f026b981101c45ea30361382940reed fTypeMask = kUnknown_Mask; 48550d3b57c8aaa0f026b981101c45ea30361382940reed } 48650d3b57c8aaa0f026b981101c45ea30361382940reed 48750d3b57c8aaa0f026b981101c45ea30361382940reed inline void setTypeMask(int mask) { 48850d3b57c8aaa0f026b981101c45ea30361382940reed SkASSERT(0 == (~(kAllPublic_Masks | kUnknown_Mask) & mask)); 48950d3b57c8aaa0f026b981101c45ea30361382940reed fTypeMask = mask; 49050d3b57c8aaa0f026b981101c45ea30361382940reed } 49150d3b57c8aaa0f026b981101c45ea30361382940reed 49250d3b57c8aaa0f026b981101c45ea30361382940reed /** 49350d3b57c8aaa0f026b981101c45ea30361382940reed * Does not take the time to 'compute' the typemask. Only returns true if 49450d3b57c8aaa0f026b981101c45ea30361382940reed * we already know that this matrix is identity. 49550d3b57c8aaa0f026b981101c45ea30361382940reed */ 49650d3b57c8aaa0f026b981101c45ea30361382940reed inline bool isTriviallyIdentity() const { 49750d3b57c8aaa0f026b981101c45ea30361382940reed return 0 == fTypeMask; 49850d3b57c8aaa0f026b981101c45ea30361382940reed } 499111a42d9cebf0bb8844c5d24f67fac57cc619d29msarett 500e151bdb357c21b833718b369fe8fbd7fd57ae474Matt Sarett inline const SkMScalar* values() const { return &fMat[0][0]; } 501e151bdb357c21b833718b369fe8fbd7fd57ae474Matt Sarett 502111a42d9cebf0bb8844c5d24f67fac57cc619d29msarett friend class SkColorSpace; 503e151bdb357c21b833718b369fe8fbd7fd57ae474Matt Sarett friend class SkColorSpace_XYZ; 50450d3b57c8aaa0f026b981101c45ea30361382940reed}; 50550d3b57c8aaa0f026b981101c45ea30361382940reed 50650d3b57c8aaa0f026b981101c45ea30361382940reed#endif 507