blob: e9061b54ee1d05db8c4196e436438769f60a20f3 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* 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}