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 24SkScalar 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 32U16CPU 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 41class SkGradientUnitMapper : public SkUnitMapper { 42public: 43 SkGradientUnitMapper(SkAnimateMaker* maker, const char* script) : fMaker(maker), fScript(script) { 44 } 45 46 // overrides for SkFlattenable 47 virtual Factory getFactory() { return NULL; } 48 49protected: 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 77const SkMemberInfo SkGradient::fInfo[] = { 78 SK_MEMBER_INHERITED, 79 SK_MEMBER_ARRAY(offsets, Float), 80 SK_MEMBER(unitMapper, String) 81}; 82 83#endif 84 85DEFINE_GET_MEMBER(SkGradient); 86 87SkGradient::SkGradient() : fUnitMapper(NULL) { 88} 89 90SkGradient::~SkGradient() { 91 for (int index = 0; index < fDrawColors.count(); index++) 92 delete fDrawColors[index]; 93 delete fUnitMapper; 94} 95 96bool 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 106int 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 115void 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 133void 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 165const SkMemberInfo SkLinearGradient::fInfo[] = { 166 SK_MEMBER_INHERITED, 167 SK_MEMBER_ARRAY(points, Float), 168}; 169 170#endif 171 172DEFINE_GET_MEMBER(SkLinearGradient); 173 174SkLinearGradient::SkLinearGradient() { 175} 176 177void 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 185void SkLinearGradient::dump(SkAnimateMaker* maker) { 186 dumpBase(maker); 187 dumpRest(maker); 188 } 189#endif 190 191SkShader* 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 205const SkMemberInfo SkRadialGradient::fInfo[] = { 206 SK_MEMBER_INHERITED, 207 SK_MEMBER(center, Point), 208 SK_MEMBER(radius, Float) 209}; 210 211#endif 212 213DEFINE_GET_MEMBER(SkRadialGradient); 214 215SkRadialGradient::SkRadialGradient() : radius(0) { 216 center.set(0, 0); 217} 218 219#ifdef SK_DUMP_ENABLED 220void SkRadialGradient::dump(SkAnimateMaker* maker) { 221 dumpBase(maker); 222 dumpRest(maker); 223} 224#endif 225 226SkShader* 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