blob: 44086e4269d9b85ab7029a706f0392bbff159da6 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkDrawGradient.h"
11#include "SkAnimateMaker.h"
12#include "SkAnimatorScript.h"
13#include "SkGradientShader.h"
14#include "SkUnitMapper.h"
15
caryclark@google.com16230cb2012-06-06 12:11:55 +000016static SkScalar SkUnitToScalar(U16CPU x) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#ifdef SK_SCALAR_IS_FLOAT
18 return x / 65535.0f;
19#else
20 return x + (x >> 8);
21#endif
22}
23
caryclark@google.com16230cb2012-06-06 12:11:55 +000024static U16CPU SkScalarToUnit(SkScalar x) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000025 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
rileya@google.com99547762012-07-26 21:25:09 +000033class SkDrawGradientUnitMapper : public SkUnitMapper {
reed@android.com8a1c16f2008-12-17 15:59:43 +000034public:
rileya@google.com99547762012-07-26 21:25:09 +000035 SkDrawGradientUnitMapper(SkAnimateMaker* maker, const char* script) : fMaker(maker), fScript(script) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000036 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000037
djsollen@google.comba28d032012-03-26 17:57:35 +000038 SK_DECLARE_UNFLATTENABLE_OBJECT()
rmistry@google.comd6176b02012-08-23 18:14:13 +000039
reed@android.com8a1c16f2008-12-17 15:59:43 +000040protected:
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);
rmistry@google.comd6176b02012-08-23 18:14:13 +000046 if (engine.evaluate(fScript, &value, SkType_Float))
reed@android.com8a1c16f2008-12-17 15:59:43 +000047 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
rileya@google.com99547762012-07-26 21:25:09 +000068const SkMemberInfo SkDrawGradient::fInfo[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +000069 SK_MEMBER_INHERITED,
70 SK_MEMBER_ARRAY(offsets, Float),
71 SK_MEMBER(unitMapper, String)
72};
73
74#endif
75
rileya@google.com99547762012-07-26 21:25:09 +000076DEFINE_GET_MEMBER(SkDrawGradient);
reed@android.com8a1c16f2008-12-17 15:59:43 +000077
rileya@google.com99547762012-07-26 21:25:09 +000078SkDrawGradient::SkDrawGradient() : fUnitMapper(NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000079}
80
rileya@google.com99547762012-07-26 21:25:09 +000081SkDrawGradient::~SkDrawGradient() {
rmistry@google.comd6176b02012-08-23 18:14:13 +000082 for (int index = 0; index < fDrawColors.count(); index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +000083 delete fDrawColors[index];
84 delete fUnitMapper;
85}
86
tfarina@chromium.org1d3c4112012-12-03 14:38:08 +000087bool SkDrawGradient::addChild(SkAnimateMaker& , SkDisplayable* child) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000088 SkASSERT(child);
89 if (child->isColor()) {
90 SkDrawColor* color = (SkDrawColor*) child;
91 *fDrawColors.append() = color;
92 return true;
93 }
94 return false;
95}
96
rileya@google.com99547762012-07-26 21:25:09 +000097int SkDrawGradient::addPrelude() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000098 int count = fDrawColors.count();
99 fColors.setCount(count);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000100 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101 fColors[index] = fDrawColors[index]->color;
102 return count;
103}
104
105#ifdef SK_DUMP_ENABLED
rileya@google.com99547762012-07-26 21:25:09 +0000106void SkDrawGradient::dumpRest(SkAnimateMaker* maker) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107 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 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000119 SkDisplayList::fIndent -= 4;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120 dumpChildren(maker, closedYet); //dumps the matrix if it has one
121}
122#endif
123
rileya@google.com99547762012-07-26 21:25:09 +0000124void SkDrawGradient::onEndElement(SkAnimateMaker& maker) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 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 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000149 if (unitMapper.size() > 0)
rileya@google.com99547762012-07-26 21:25:09 +0000150 fUnitMapper = new SkDrawGradientUnitMapper(&maker, unitMapper.c_str());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151 INHERITED::onEndElement(maker);
152}
153
154#if SK_USE_CONDENSED_INFO == 0
155
rileya@google.com99547762012-07-26 21:25:09 +0000156const SkMemberInfo SkDrawLinearGradient::fInfo[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 SK_MEMBER_INHERITED,
158 SK_MEMBER_ARRAY(points, Float),
159};
160
161#endif
162
rileya@google.com99547762012-07-26 21:25:09 +0000163DEFINE_GET_MEMBER(SkDrawLinearGradient);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164
rmistry@google.comd6176b02012-08-23 18:14:13 +0000165SkDrawLinearGradient::SkDrawLinearGradient() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166}
167
rileya@google.com99547762012-07-26 21:25:09 +0000168void SkDrawLinearGradient::onEndElement(SkAnimateMaker& maker)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169{
170 if (points.count() != 4)
171 maker.setErrorCode(SkDisplayXMLParserError::kGradientPointsLengthMustBeFour);
172 INHERITED::onEndElement(maker);
173}
174
175#ifdef SK_DUMP_ENABLED
rileya@google.com99547762012-07-26 21:25:09 +0000176void SkDrawLinearGradient::dump(SkAnimateMaker* maker) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 dumpBase(maker);
178 dumpRest(maker);
179 }
180#endif
181
rileya@google.com99547762012-07-26 21:25:09 +0000182SkShader* SkDrawLinearGradient::getShader() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183 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
rileya@google.com99547762012-07-26 21:25:09 +0000196const SkMemberInfo SkDrawRadialGradient::fInfo[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 SK_MEMBER_INHERITED,
198 SK_MEMBER(center, Point),
199 SK_MEMBER(radius, Float)
200};
201
202#endif
203
rileya@google.com99547762012-07-26 21:25:09 +0000204DEFINE_GET_MEMBER(SkDrawRadialGradient);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
rmistry@google.comd6176b02012-08-23 18:14:13 +0000206SkDrawRadialGradient::SkDrawRadialGradient() : radius(0) {
207 center.set(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208}
209
210#ifdef SK_DUMP_ENABLED
rileya@google.com99547762012-07-26 21:25:09 +0000211void SkDrawRadialGradient::dump(SkAnimateMaker* maker) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 dumpBase(maker);
213 dumpRest(maker);
214}
215#endif
216
rileya@google.com99547762012-07-26 21:25:09 +0000217SkShader* SkDrawRadialGradient::getShader() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 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}