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