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 16static 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 24static 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 33class SkDrawGradientUnitMapper : public SkUnitMapper { 34public: 35 SkDrawGradientUnitMapper(SkAnimateMaker* maker, const char* script) : fMaker(maker), fScript(script) { 36 } 37 38 SK_DECLARE_UNFLATTENABLE_OBJECT() 39 40protected: 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 68const SkMemberInfo SkDrawGradient::fInfo[] = { 69 SK_MEMBER_INHERITED, 70 SK_MEMBER_ARRAY(offsets, Float), 71 SK_MEMBER(unitMapper, String) 72}; 73 74#endif 75 76DEFINE_GET_MEMBER(SkDrawGradient); 77 78SkDrawGradient::SkDrawGradient() : fUnitMapper(NULL) { 79} 80 81SkDrawGradient::~SkDrawGradient() { 82 for (int index = 0; index < fDrawColors.count(); index++) 83 delete fDrawColors[index]; 84 delete fUnitMapper; 85} 86 87bool 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 97int 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 106void 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 124void 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 156const SkMemberInfo SkDrawLinearGradient::fInfo[] = { 157 SK_MEMBER_INHERITED, 158 SK_MEMBER_ARRAY(points, Float), 159}; 160 161#endif 162 163DEFINE_GET_MEMBER(SkDrawLinearGradient); 164 165SkDrawLinearGradient::SkDrawLinearGradient() { 166} 167 168void 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 176void SkDrawLinearGradient::dump(SkAnimateMaker* maker) { 177 dumpBase(maker); 178 dumpRest(maker); 179 } 180#endif 181 182SkShader* 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 196const SkMemberInfo SkDrawRadialGradient::fInfo[] = { 197 SK_MEMBER_INHERITED, 198 SK_MEMBER(center, Point), 199 SK_MEMBER(radius, Float) 200}; 201 202#endif 203 204DEFINE_GET_MEMBER(SkDrawRadialGradient); 205 206SkDrawRadialGradient::SkDrawRadialGradient() : radius(0) { 207 center.set(0, 0); 208} 209 210#ifdef SK_DUMP_ENABLED 211void SkDrawRadialGradient::dump(SkAnimateMaker* maker) { 212 dumpBase(maker); 213 dumpRest(maker); 214} 215#endif 216 217SkShader* 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