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