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
SkUnitToScalar(U16CPU x)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
SkScalarToUnit(SkScalar x)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:
SkGradientUnitMapper(SkAnimateMaker * maker,const char * script)43 SkGradientUnitMapper(SkAnimateMaker* maker, const char* script) : fMaker(maker), fScript(script) {
44 }
45
46 // overrides for SkFlattenable
getFactory()47 virtual Factory getFactory() { return NULL; }
48
49 protected:
mapUnit16(uint16_t x)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
GetUnitValue(const char * token,size_t len,void * unitPtr,SkScriptValue * value)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
SkGradient()87 SkGradient::SkGradient() : fUnitMapper(NULL) {
88 }
89
~SkGradient()90 SkGradient::~SkGradient() {
91 for (int index = 0; index < fDrawColors.count(); index++)
92 delete fDrawColors[index];
93 delete fUnitMapper;
94 }
95
add(SkAnimateMaker &,SkDisplayable * child)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
addPrelude()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
dumpRest(SkAnimateMaker * maker)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
onEndElement(SkAnimateMaker & maker)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
SkLinearGradient()174 SkLinearGradient::SkLinearGradient() {
175 }
176
onEndElement(SkAnimateMaker & maker)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
dump(SkAnimateMaker * maker)185 void SkLinearGradient::dump(SkAnimateMaker* maker) {
186 dumpBase(maker);
187 dumpRest(maker);
188 }
189 #endif
190
getShader()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
SkRadialGradient()215 SkRadialGradient::SkRadialGradient() : radius(0) {
216 center.set(0, 0);
217 }
218
219 #ifdef SK_DUMP_ENABLED
dump(SkAnimateMaker * maker)220 void SkRadialGradient::dump(SkAnimateMaker* maker) {
221 dumpBase(maker);
222 dumpRest(maker);
223 }
224 #endif
225
getShader()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