blob: c11559581b919c84e6eff35e831cb5b495d97ba9 [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"
commit-bot@chromium.org3339ac52014-05-22 02:55:59 +000014#include "SkUnitMapper.h"
15
16static SkScalar SkUnitToScalar(U16CPU x) {
17 return x / 65535.0f;
18}
19
20static U16CPU SkScalarToUnit(SkScalar x) {
21 SkScalar pin = SkScalarPin(x, 0, SK_Scalar1);
22 return (int) (pin * 65535.0f);
23}
24
25class SkDrawGradientUnitMapper : public SkUnitMapper {
26public:
27 SkDrawGradientUnitMapper(SkAnimateMaker* maker, const char* script) : fMaker(maker), fScript(script) {
28 }
29
30 SK_DECLARE_UNFLATTENABLE_OBJECT()
31
32protected:
33 virtual uint16_t mapUnit16(uint16_t x) {
34 fUnit = SkUnitToScalar(x);
35 SkScriptValue value;
36 SkAnimatorScript engine(*fMaker, NULL, SkType_Float);
37 engine.propertyCallBack(GetUnitValue, &fUnit);
38 if (engine.evaluate(fScript, &value, SkType_Float))
39 x = SkScalarToUnit(value.fOperand.fScalar);
40 return x;
41 }
42
43 static bool GetUnitValue(const char* token, size_t len, void* unitPtr, SkScriptValue* value) {
44 if (SK_LITERAL_STR_EQUAL("unit", token, len)) {
45 value->fOperand.fScalar = *(SkScalar*) unitPtr;
46 value->fType = SkType_Float;
47 return true;
48 }
49 return false;
50 }
51
52 SkAnimateMaker* fMaker;
53 const char* fScript;
54 SkScalar fUnit;
55};
56
reed@android.com8a1c16f2008-12-17 15:59:43 +000057
58#if SK_USE_CONDENSED_INFO == 0
59
rileya@google.com99547762012-07-26 21:25:09 +000060const SkMemberInfo SkDrawGradient::fInfo[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 SK_MEMBER_INHERITED,
62 SK_MEMBER_ARRAY(offsets, Float),
63 SK_MEMBER(unitMapper, String)
64};
65
66#endif
67
rileya@google.com99547762012-07-26 21:25:09 +000068DEFINE_GET_MEMBER(SkDrawGradient);
reed@android.com8a1c16f2008-12-17 15:59:43 +000069
commit-bot@chromium.org3339ac52014-05-22 02:55:59 +000070SkDrawGradient::SkDrawGradient() : fUnitMapper(NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000071}
72
rileya@google.com99547762012-07-26 21:25:09 +000073SkDrawGradient::~SkDrawGradient() {
rmistry@google.comd6176b02012-08-23 18:14:13 +000074 for (int index = 0; index < fDrawColors.count(); index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 delete fDrawColors[index];
commit-bot@chromium.org3339ac52014-05-22 02:55:59 +000076 delete fUnitMapper;
reed@android.com8a1c16f2008-12-17 15:59:43 +000077}
78
tfarina@chromium.org1d3c4112012-12-03 14:38:08 +000079bool SkDrawGradient::addChild(SkAnimateMaker& , SkDisplayable* child) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 SkASSERT(child);
81 if (child->isColor()) {
82 SkDrawColor* color = (SkDrawColor*) child;
83 *fDrawColors.append() = color;
84 return true;
85 }
86 return false;
87}
88
rileya@google.com99547762012-07-26 21:25:09 +000089int SkDrawGradient::addPrelude() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 int count = fDrawColors.count();
91 fColors.setCount(count);
rmistry@google.comd6176b02012-08-23 18:14:13 +000092 for (int index = 0; index < count; index++)
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 fColors[index] = fDrawColors[index]->color;
94 return count;
95}
96
97#ifdef SK_DUMP_ENABLED
rileya@google.com99547762012-07-26 21:25:09 +000098void SkDrawGradient::dumpRest(SkAnimateMaker* maker) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000099 dumpAttrs(maker);
100 //can a gradient have no colors?
101 bool closedYet = false;
102 SkDisplayList::fIndent += 4;
103 for (SkDrawColor** ptr = fDrawColors.begin(); ptr < fDrawColors.end(); ptr++) {
104 if (closedYet == false) {
105 SkDebugf(">\n");
106 closedYet = true;
107 }
108 SkDrawColor* color = *ptr;
109 color->dump(maker);
110 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000111 SkDisplayList::fIndent -= 4;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 dumpChildren(maker, closedYet); //dumps the matrix if it has one
113}
114#endif
115
rileya@google.com99547762012-07-26 21:25:09 +0000116void SkDrawGradient::onEndElement(SkAnimateMaker& maker) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117 if (offsets.count() != 0) {
118 if (offsets.count() != fDrawColors.count()) {
119 maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsDontMatchColors);
120 return;
121 }
122 if (offsets[0] != 0) {
123 maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustStartWithZero);
124 return;
125 }
126 if (offsets[offsets.count()-1] != SK_Scalar1) {
127 maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustEndWithOne);
128 return;
129 }
130 for (int i = 1; i < offsets.count(); i++) {
131 if (offsets[i] <= offsets[i-1]) {
132 maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustIncrease);
133 return;
134 }
135 if (offsets[i] > SK_Scalar1) {
136 maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustBeNoMoreThanOne);
137 return;
138 }
139 }
140 }
commit-bot@chromium.org3339ac52014-05-22 02:55:59 +0000141 if (unitMapper.size() > 0)
142 fUnitMapper = new SkDrawGradientUnitMapper(&maker, unitMapper.c_str());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 INHERITED::onEndElement(maker);
144}
145
146#if SK_USE_CONDENSED_INFO == 0
147
rileya@google.com99547762012-07-26 21:25:09 +0000148const SkMemberInfo SkDrawLinearGradient::fInfo[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 SK_MEMBER_INHERITED,
150 SK_MEMBER_ARRAY(points, Float),
151};
152
153#endif
154
rileya@google.com99547762012-07-26 21:25:09 +0000155DEFINE_GET_MEMBER(SkDrawLinearGradient);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156
rmistry@google.comd6176b02012-08-23 18:14:13 +0000157SkDrawLinearGradient::SkDrawLinearGradient() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158}
159
rileya@google.com99547762012-07-26 21:25:09 +0000160void SkDrawLinearGradient::onEndElement(SkAnimateMaker& maker)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161{
162 if (points.count() != 4)
163 maker.setErrorCode(SkDisplayXMLParserError::kGradientPointsLengthMustBeFour);
164 INHERITED::onEndElement(maker);
165}
166
167#ifdef SK_DUMP_ENABLED
rileya@google.com99547762012-07-26 21:25:09 +0000168void SkDrawLinearGradient::dump(SkAnimateMaker* maker) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 dumpBase(maker);
170 dumpRest(maker);
171 }
172#endif
173
rileya@google.com99547762012-07-26 21:25:09 +0000174SkShader* SkDrawLinearGradient::getShader() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 if (addPrelude() == 0 || points.count() != 4)
176 return NULL;
177 SkShader* shader = SkGradientShader::CreateLinear((SkPoint*)points.begin(),
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000178 fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode,
commit-bot@chromium.org3339ac52014-05-22 02:55:59 +0000179 fUnitMapper, 0, getMatrix());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 SkAutoTDelete<SkShader> autoDel(shader);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181 (void)autoDel.detach();
182 return shader;
183}
184
185
186#if SK_USE_CONDENSED_INFO == 0
187
rileya@google.com99547762012-07-26 21:25:09 +0000188const SkMemberInfo SkDrawRadialGradient::fInfo[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 SK_MEMBER_INHERITED,
190 SK_MEMBER(center, Point),
191 SK_MEMBER(radius, Float)
192};
193
194#endif
195
rileya@google.com99547762012-07-26 21:25:09 +0000196DEFINE_GET_MEMBER(SkDrawRadialGradient);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197
rmistry@google.comd6176b02012-08-23 18:14:13 +0000198SkDrawRadialGradient::SkDrawRadialGradient() : radius(0) {
199 center.set(0, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200}
201
202#ifdef SK_DUMP_ENABLED
rileya@google.com99547762012-07-26 21:25:09 +0000203void SkDrawRadialGradient::dump(SkAnimateMaker* maker) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 dumpBase(maker);
205 dumpRest(maker);
206}
207#endif
208
rileya@google.com99547762012-07-26 21:25:09 +0000209SkShader* SkDrawRadialGradient::getShader() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 if (addPrelude() == 0)
211 return NULL;
212 SkShader* shader = SkGradientShader::CreateRadial(center,
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000213 radius, fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode,
commit-bot@chromium.org3339ac52014-05-22 02:55:59 +0000214 fUnitMapper, 0, getMatrix());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 SkAutoTDelete<SkShader> autoDel(shader);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 (void)autoDel.detach();
217 return shader;
218}