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 16SkScalar 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 24U16CPU 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 SkGradientUnitMapper : public SkUnitMapper { 34public: 35 SkGradientUnitMapper(SkAnimateMaker* maker, const char* script) : fMaker(maker), fScript(script) { 36 } 37 38 // overrides for SkFlattenable 39 virtual Factory getFactory() { return NULL; } 40 41protected: 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 69const SkMemberInfo SkGradient::fInfo[] = { 70 SK_MEMBER_INHERITED, 71 SK_MEMBER_ARRAY(offsets, Float), 72 SK_MEMBER(unitMapper, String) 73}; 74 75#endif 76 77DEFINE_GET_MEMBER(SkGradient); 78 79SkGradient::SkGradient() : fUnitMapper(NULL) { 80} 81 82SkGradient::~SkGradient() { 83 for (int index = 0; index < fDrawColors.count(); index++) 84 delete fDrawColors[index]; 85 delete fUnitMapper; 86} 87 88bool 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 98int 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 107void 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 125void 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 157const SkMemberInfo SkLinearGradient::fInfo[] = { 158 SK_MEMBER_INHERITED, 159 SK_MEMBER_ARRAY(points, Float), 160}; 161 162#endif 163 164DEFINE_GET_MEMBER(SkLinearGradient); 165 166SkLinearGradient::SkLinearGradient() { 167} 168 169void 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 177void SkLinearGradient::dump(SkAnimateMaker* maker) { 178 dumpBase(maker); 179 dumpRest(maker); 180 } 181#endif 182 183SkShader* 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 197const SkMemberInfo SkRadialGradient::fInfo[] = { 198 SK_MEMBER_INHERITED, 199 SK_MEMBER(center, Point), 200 SK_MEMBER(radius, Float) 201}; 202 203#endif 204 205DEFINE_GET_MEMBER(SkRadialGradient); 206 207SkRadialGradient::SkRadialGradient() : radius(0) { 208 center.set(0, 0); 209} 210 211#ifdef SK_DUMP_ENABLED 212void SkRadialGradient::dump(SkAnimateMaker* maker) { 213 dumpBase(maker); 214 dumpRest(maker); 215} 216#endif 217 218SkShader* 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