1 2 /* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "SkDrawGradient.h" 11 #include "SkAnimateMaker.h" 12 #include "SkAnimatorScript.h" 13 #include "SkGradientShader.h" 14 #include "SkUnitMapper.h" 15 16 static SkScalar SkUnitToScalar(U16CPU x) { 17 #ifdef SK_SCALAR_IS_FLOAT 18 return x / 65535.0f; 19 #else 20 return x + (x >> 8); 21 #endif 22 } 23 24 static U16CPU SkScalarToUnit(SkScalar x) { 25 SkScalar pin = SkScalarPin(x, 0, SK_Scalar1); 26 #ifdef SK_SCALAR_IS_FLOAT 27 return (int) (pin * 65535.0f); 28 #else 29 return pin - (pin >= 32768); 30 #endif 31 } 32 33 class SkDrawGradientUnitMapper : public SkUnitMapper { 34 public: 35 SkDrawGradientUnitMapper(SkAnimateMaker* maker, const char* script) : fMaker(maker), fScript(script) { 36 } 37 38 SK_DECLARE_UNFLATTENABLE_OBJECT() 39 40 protected: 41 virtual uint16_t mapUnit16(uint16_t x) { 42 fUnit = SkUnitToScalar(x); 43 SkScriptValue value; 44 SkAnimatorScript engine(*fMaker, NULL, SkType_Float); 45 engine.propertyCallBack(GetUnitValue, &fUnit); 46 if (engine.evaluate(fScript, &value, SkType_Float)) 47 x = SkScalarToUnit(value.fOperand.fScalar); 48 return x; 49 } 50 51 static bool GetUnitValue(const char* token, size_t len, void* unitPtr, SkScriptValue* value) { 52 if (SK_LITERAL_STR_EQUAL("unit", token, len)) { 53 value->fOperand.fScalar = *(SkScalar*) unitPtr; 54 value->fType = SkType_Float; 55 return true; 56 } 57 return false; 58 } 59 60 SkAnimateMaker* fMaker; 61 const char* fScript; 62 SkScalar fUnit; 63 }; 64 65 66 #if SK_USE_CONDENSED_INFO == 0 67 68 const SkMemberInfo SkDrawGradient::fInfo[] = { 69 SK_MEMBER_INHERITED, 70 SK_MEMBER_ARRAY(offsets, Float), 71 SK_MEMBER(unitMapper, String) 72 }; 73 74 #endif 75 76 DEFINE_GET_MEMBER(SkDrawGradient); 77 78 SkDrawGradient::SkDrawGradient() : fUnitMapper(NULL) { 79 } 80 81 SkDrawGradient::~SkDrawGradient() { 82 for (int index = 0; index < fDrawColors.count(); index++) 83 delete fDrawColors[index]; 84 delete fUnitMapper; 85 } 86 87 bool SkDrawGradient::addChild(SkAnimateMaker& , SkDisplayable* child) { 88 SkASSERT(child); 89 if (child->isColor()) { 90 SkDrawColor* color = (SkDrawColor*) child; 91 *fDrawColors.append() = color; 92 return true; 93 } 94 return false; 95 } 96 97 int SkDrawGradient::addPrelude() { 98 int count = fDrawColors.count(); 99 fColors.setCount(count); 100 for (int index = 0; index < count; index++) 101 fColors[index] = fDrawColors[index]->color; 102 return count; 103 } 104 105 #ifdef SK_DUMP_ENABLED 106 void SkDrawGradient::dumpRest(SkAnimateMaker* maker) { 107 dumpAttrs(maker); 108 //can a gradient have no colors? 109 bool closedYet = false; 110 SkDisplayList::fIndent += 4; 111 for (SkDrawColor** ptr = fDrawColors.begin(); ptr < fDrawColors.end(); ptr++) { 112 if (closedYet == false) { 113 SkDebugf(">\n"); 114 closedYet = true; 115 } 116 SkDrawColor* color = *ptr; 117 color->dump(maker); 118 } 119 SkDisplayList::fIndent -= 4; 120 dumpChildren(maker, closedYet); //dumps the matrix if it has one 121 } 122 #endif 123 124 void SkDrawGradient::onEndElement(SkAnimateMaker& maker) { 125 if (offsets.count() != 0) { 126 if (offsets.count() != fDrawColors.count()) { 127 maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsDontMatchColors); 128 return; 129 } 130 if (offsets[0] != 0) { 131 maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustStartWithZero); 132 return; 133 } 134 if (offsets[offsets.count()-1] != SK_Scalar1) { 135 maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustEndWithOne); 136 return; 137 } 138 for (int i = 1; i < offsets.count(); i++) { 139 if (offsets[i] <= offsets[i-1]) { 140 maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustIncrease); 141 return; 142 } 143 if (offsets[i] > SK_Scalar1) { 144 maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustBeNoMoreThanOne); 145 return; 146 } 147 } 148 } 149 if (unitMapper.size() > 0) 150 fUnitMapper = new SkDrawGradientUnitMapper(&maker, unitMapper.c_str()); 151 INHERITED::onEndElement(maker); 152 } 153 154 #if SK_USE_CONDENSED_INFO == 0 155 156 const SkMemberInfo SkDrawLinearGradient::fInfo[] = { 157 SK_MEMBER_INHERITED, 158 SK_MEMBER_ARRAY(points, Float), 159 }; 160 161 #endif 162 163 DEFINE_GET_MEMBER(SkDrawLinearGradient); 164 165 SkDrawLinearGradient::SkDrawLinearGradient() { 166 } 167 168 void SkDrawLinearGradient::onEndElement(SkAnimateMaker& maker) 169 { 170 if (points.count() != 4) 171 maker.setErrorCode(SkDisplayXMLParserError::kGradientPointsLengthMustBeFour); 172 INHERITED::onEndElement(maker); 173 } 174 175 #ifdef SK_DUMP_ENABLED 176 void SkDrawLinearGradient::dump(SkAnimateMaker* maker) { 177 dumpBase(maker); 178 dumpRest(maker); 179 } 180 #endif 181 182 SkShader* SkDrawLinearGradient::getShader() { 183 if (addPrelude() == 0 || points.count() != 4) 184 return NULL; 185 SkShader* shader = SkGradientShader::CreateLinear((SkPoint*)points.begin(), 186 fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, fUnitMapper); 187 SkAutoTDelete<SkShader> autoDel(shader); 188 addPostlude(shader); 189 (void)autoDel.detach(); 190 return shader; 191 } 192 193 194 #if SK_USE_CONDENSED_INFO == 0 195 196 const SkMemberInfo SkDrawRadialGradient::fInfo[] = { 197 SK_MEMBER_INHERITED, 198 SK_MEMBER(center, Point), 199 SK_MEMBER(radius, Float) 200 }; 201 202 #endif 203 204 DEFINE_GET_MEMBER(SkDrawRadialGradient); 205 206 SkDrawRadialGradient::SkDrawRadialGradient() : radius(0) { 207 center.set(0, 0); 208 } 209 210 #ifdef SK_DUMP_ENABLED 211 void SkDrawRadialGradient::dump(SkAnimateMaker* maker) { 212 dumpBase(maker); 213 dumpRest(maker); 214 } 215 #endif 216 217 SkShader* SkDrawRadialGradient::getShader() { 218 if (addPrelude() == 0) 219 return NULL; 220 SkShader* shader = SkGradientShader::CreateRadial(center, 221 radius, fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, fUnitMapper); 222 SkAutoTDelete<SkShader> autoDel(shader); 223 addPostlude(shader); 224 (void)autoDel.detach(); 225 return shader; 226 } 227