|
1 |
|
2 /* |
|
3 * Copyright 2011 Google Inc. |
|
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 #include "SkAnimatorScript2.h" |
|
9 #include "SkAnimateBase.h" |
|
10 #include "SkAnimateMaker.h" |
|
11 #include "SkDisplayTypes.h" |
|
12 #include "SkExtras.h" |
|
13 #include "SkMemberInfo.h" |
|
14 #include "SkOpArray.h" |
|
15 #include "SkParse.h" |
|
16 #include "SkScript2.h" |
|
17 #include "SkScriptCallBack.h" |
|
18 |
|
19 static const SkDisplayEnumMap gEnumMaps[] = { |
|
20 { SkType_AddMode, "indirect|immediate" }, |
|
21 { SkType_Align, "left|center|right" }, |
|
22 { SkType_ApplyMode, "immediate|once" }, |
|
23 { SkType_ApplyTransition, "reverse" }, |
|
24 { SkType_BitmapEncoding, "jpeg|png" }, |
|
25 { SkType_BitmapFormat, "none|A1|A8|Index8|RGB16|RGB32" }, |
|
26 { SkType_Boolean, "false|true" }, |
|
27 { SkType_Cap, "butt|round|square" }, |
|
28 { SkType_EventCode, "none|up|down|left|right|back|end|OK|send|leftSoftKey|rightSoftKey|key0|key1|key2|key3|key4|key5|key6|key7|key8|key9|star|hash" }, |
|
29 { SkType_EventKind, "none|keyChar|keyPress|mouseDown|mouseDrag|mouseMove|mouseUp|onEnd|onLoad|user" }, |
|
30 { SkType_EventMode, "deferred|immediate" }, |
|
31 { SkType_FillType, "winding|evenOdd" }, |
|
32 { SkType_FilterType, "none|bilinear" }, |
|
33 { SkType_FromPathMode, "normal|angle|position" }, |
|
34 { SkType_Join, "miter|round|blunt" }, |
|
35 { SkType_MaskFilterBlurStyle, "normal|solid|outer|inner" }, |
|
36 { SkType_PathDirection, "cw|ccw" }, |
|
37 { SkType_Style, "fill|stroke|strokeAndFill" }, |
|
38 { SkType_TextBoxAlign, "start|center|end" }, |
|
39 { SkType_TextBoxMode, "oneLine|lineBreak" }, |
|
40 { SkType_TileMode, "clamp|repeat|mirror" }, |
|
41 { SkType_Xfermode, "clear|src|dst|srcOver|dstOver|srcIn|dstIn|srcOut|dstOut|" |
|
42 "srcATop|dstATop|xor|darken|lighten" }, |
|
43 }; |
|
44 |
|
45 static int gEnumMapCount = SK_ARRAY_COUNT(gEnumMaps); |
|
46 |
|
47 |
|
48 class SkAnimatorScript_Box : public SkScriptCallBackConvert { |
|
49 public: |
|
50 SkAnimatorScript_Box() {} |
|
51 |
|
52 ~SkAnimatorScript_Box() { |
|
53 for (SkDisplayable** dispPtr = fTrackDisplayable.begin(); dispPtr < fTrackDisplayable.end(); dispPtr++) |
|
54 delete *dispPtr; |
|
55 } |
|
56 |
|
57 virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) { |
|
58 SkDisplayable* displayable; |
|
59 switch (type) { |
|
60 case SkOperand2::kArray: { |
|
61 SkDisplayArray* boxedValue = new SkDisplayArray(*operand->fArray); |
|
62 displayable = boxedValue; |
|
63 } break; |
|
64 case SkOperand2::kS32: { |
|
65 SkDisplayInt* boxedValue = new SkDisplayInt; |
|
66 displayable = boxedValue; |
|
67 boxedValue->value = operand->fS32; |
|
68 } break; |
|
69 case SkOperand2::kScalar: { |
|
70 SkDisplayFloat* boxedValue = new SkDisplayFloat; |
|
71 displayable = boxedValue; |
|
72 boxedValue->value = operand->fScalar; |
|
73 } break; |
|
74 case SkOperand2::kString: { |
|
75 SkDisplayString* boxedValue = new SkDisplayString(*operand->fString); |
|
76 displayable = boxedValue; |
|
77 } break; |
|
78 case SkOperand2::kObject: |
|
79 return true; |
|
80 default: |
|
81 SkASSERT(0); |
|
82 return false; |
|
83 } |
|
84 track(displayable); |
|
85 operand->fObject = (void*) displayable; |
|
86 return true; |
|
87 } |
|
88 |
|
89 virtual SkOperand2::OpType getReturnType(int index) { |
|
90 return SkOperand2::kObject; |
|
91 } |
|
92 |
|
93 virtual Type getType() const { |
|
94 return kBox; |
|
95 } |
|
96 |
|
97 void track(SkDisplayable* displayable) { |
|
98 SkASSERT(fTrackDisplayable.find(displayable) < 0); |
|
99 *fTrackDisplayable.append() = displayable; |
|
100 } |
|
101 |
|
102 SkTDDisplayableArray fTrackDisplayable; |
|
103 }; |
|
104 |
|
105 |
|
106 class SkAnimatorScript_Enum : public SkScriptCallBackProperty { |
|
107 public: |
|
108 SkAnimatorScript_Enum(const char* tokens) : fTokens(tokens) {} |
|
109 |
|
110 virtual bool getConstValue(const char* name, int len, SkOperand2* value) { |
|
111 return SkAnimatorScript2::MapEnums(fTokens, name, len, &value->fS32); |
|
112 } |
|
113 |
|
114 private: |
|
115 const char* fTokens; |
|
116 }; |
|
117 |
|
118 // !!! if type is string, call invoke |
|
119 // if any other type, return original value |
|
120 // distinction is undone: could do this by returning index == 0 only if param is string |
|
121 // still, caller of getParamTypes will attempt to convert param to string (I guess) |
|
122 class SkAnimatorScript_Eval : public SkScriptCallBackFunction { |
|
123 public: |
|
124 SkAnimatorScript_Eval(SkAnimatorScript2* engine) : fEngine(engine) {} |
|
125 |
|
126 virtual bool getIndex(const char* name, int len, size_t* result) { |
|
127 if (SK_LITERAL_STR_EQUAL("eval", name, len) != 0) |
|
128 return false; |
|
129 *result = 0; |
|
130 return true; |
|
131 } |
|
132 |
|
133 virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { |
|
134 types->setCount(1); |
|
135 SkOperand2::OpType* type = types->begin(); |
|
136 type[0] = SkOperand2::kString; |
|
137 } |
|
138 |
|
139 virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) { |
|
140 SkAnimatorScript2 engine(fEngine->getMaker(), fEngine->getWorking(), |
|
141 SkAnimatorScript2::ToDisplayType(fEngine->getReturnType())); |
|
142 SkOperand2* op = params->begin(); |
|
143 const char* script = op->fString->c_str(); |
|
144 SkScriptValue2 value; |
|
145 return engine.evaluateScript(&script, &value); |
|
146 SkASSERT(value.fType == fEngine->getReturnType()); |
|
147 *answer = value.fOperand; |
|
148 // !!! incomplete ? |
|
149 return true; |
|
150 } |
|
151 |
|
152 private: |
|
153 SkAnimatorScript2* fEngine; |
|
154 }; |
|
155 |
|
156 class SkAnimatorScript_ID : public SkScriptCallBackProperty { |
|
157 public: |
|
158 SkAnimatorScript_ID(SkAnimatorScript2* engine) : fEngine(engine) {} |
|
159 |
|
160 virtual bool getIndex(const char* token, int len, size_t* result) { |
|
161 SkDisplayable* displayable; |
|
162 bool success = fEngine->getMaker().find(token, len, &displayable); |
|
163 if (success == false) { |
|
164 *result = 0; |
|
165 } else { |
|
166 *result = (size_t) displayable; |
|
167 SkDisplayable* working = fEngine->getWorking(); |
|
168 if (displayable->canContainDependents() && working && working->isAnimate()) { |
|
169 SkAnimateBase* animator = (SkAnimateBase*) working; |
|
170 if (animator->isDynamic()) { |
|
171 SkDisplayDepend* depend = (SkDisplayDepend* ) displayable; |
|
172 depend->addDependent(working); |
|
173 } |
|
174 } |
|
175 } |
|
176 return true; |
|
177 } |
|
178 |
|
179 virtual bool getResult(size_t ref, SkOperand2* answer) { |
|
180 answer->fObject = (void*) ref; |
|
181 return true; |
|
182 } |
|
183 |
|
184 virtual SkOperand2::OpType getReturnType(size_t index) { |
|
185 return index == 0 ? SkOperand2::kString : SkOperand2::kObject; |
|
186 } |
|
187 |
|
188 private: |
|
189 SkAnimatorScript2* fEngine; |
|
190 }; |
|
191 |
|
192 |
|
193 class SkAnimatorScript_Member : public SkScriptCallBackMember { |
|
194 public: |
|
195 |
|
196 SkAnimatorScript_Member(SkAnimatorScript2* engine) : fEngine(engine) {} |
|
197 |
|
198 bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) { |
|
199 SkDisplayable* displayable = (SkDisplayable*) object; |
|
200 SkString name(member, len); |
|
201 SkDisplayable* named = displayable->contains(name); |
|
202 if (named) { |
|
203 ref->fType = SkOperand2::kObject; |
|
204 ref->fOperand.fObject = named; |
|
205 return true; |
|
206 } |
|
207 const SkMemberInfo* info = displayable->getMember(name.c_str()); |
|
208 if (info == NULL) |
|
209 return false; // !!! add additional error info? |
|
210 ref->fType = SkAnimatorScript2::ToOpType(info->getType()); |
|
211 ref->fOperand.fObject = (void*) info; |
|
212 return true; |
|
213 } |
|
214 |
|
215 bool invoke(size_t ref, void* object, SkOperand2* value) { |
|
216 const SkMemberInfo* info = (const SkMemberInfo* ) ref; |
|
217 SkDisplayable* displayable = (SkDisplayable*) object; |
|
218 if (info->fType == SkType_MemberProperty) { |
|
219 if (displayable->getProperty2(info->propertyIndex(), value) == false) { |
|
220 return false; |
|
221 } |
|
222 } |
|
223 return fEngine->evalMemberCommon(info, displayable, value); |
|
224 } |
|
225 |
|
226 SkAnimatorScript2* fEngine; |
|
227 }; |
|
228 |
|
229 |
|
230 class SkAnimatorScript_MemberFunction : public SkScriptCallBackMemberFunction { |
|
231 public: |
|
232 SkAnimatorScript_MemberFunction(SkAnimatorScript2* engine) : fEngine(engine) {} |
|
233 |
|
234 bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) { |
|
235 SkDisplayable* displayable = (SkDisplayable*) object; |
|
236 SkString name(member, len); |
|
237 const SkMemberInfo* info = displayable->getMember(name.c_str()); |
|
238 if (info == NULL || info->fType != SkType_MemberFunction) |
|
239 return false; // !!! add additional error info? |
|
240 ref->fType = SkAnimatorScript2::ToOpType(info->getType()); |
|
241 ref->fOperand.fObject = (void*) info; |
|
242 return true; |
|
243 } |
|
244 |
|
245 virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { |
|
246 types->setCount(3); |
|
247 SkOperand2::OpType* type = types->begin(); |
|
248 type[0] = type[1] = type[2] = SkOperand2::kS32; |
|
249 } |
|
250 |
|
251 bool invoke(size_t ref, void* object, SkOpArray* params, SkOperand2* value) |
|
252 { |
|
253 const SkMemberInfo* info = (const SkMemberInfo* ) ref; |
|
254 SkDisplayable* displayable = (SkDisplayable*) object; |
|
255 displayable->executeFunction2(displayable, info->functionIndex(), params, info->getType(), |
|
256 value); |
|
257 return fEngine->evalMemberCommon(info, displayable, value); |
|
258 } |
|
259 |
|
260 SkAnimatorScript2* fEngine; |
|
261 }; |
|
262 |
|
263 |
|
264 class SkAnimatorScript_NamedColor : public SkScriptCallBackProperty { |
|
265 public: |
|
266 virtual bool getConstValue(const char* name, int len, SkOperand2* value) { |
|
267 return SkParse::FindNamedColor(name, len, (SkColor*) &value->fS32) != NULL; |
|
268 } |
|
269 }; |
|
270 |
|
271 |
|
272 class SkAnimatorScript_RGB : public SkScriptCallBackFunction { |
|
273 public: |
|
274 virtual bool getIndex(const char* name, int len, size_t* result) { |
|
275 if (SK_LITERAL_STR_EQUAL("rgb", name, len) != 0) |
|
276 return false; |
|
277 *result = 0; |
|
278 return true; |
|
279 } |
|
280 |
|
281 virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { |
|
282 types->setCount(3); |
|
283 SkOperand2::OpType* type = types->begin(); |
|
284 type[0] = type[1] = type[2] = SkOperand2::kS32; |
|
285 } |
|
286 |
|
287 virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) { |
|
288 SkASSERT(index == 0); |
|
289 unsigned result = 0xFF000000; |
|
290 int shift = 16; |
|
291 for (int index = 0; index < 3; index++) { |
|
292 result |= SkClampMax(params->begin()[index].fS32, 255) << shift; |
|
293 shift -= 8; |
|
294 } |
|
295 answer->fS32 = result; |
|
296 return true; |
|
297 } |
|
298 |
|
299 }; |
|
300 |
|
301 |
|
302 class SkAnimatorScript_Unbox : public SkScriptCallBackConvert { |
|
303 public: |
|
304 SkAnimatorScript_Unbox(SkAnimatorScript2* engine) : fEngine(engine) {} |
|
305 |
|
306 virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) { |
|
307 SkASSERT(type == SkOperand2::kObject); |
|
308 SkDisplayable* displayable = (SkDisplayable*) operand->fObject; |
|
309 switch (displayable->getType()) { |
|
310 case SkType_Array: { |
|
311 SkDisplayArray* boxedValue = (SkDisplayArray*) displayable; |
|
312 operand->fArray = new SkOpArray(SkAnimatorScript2::ToOpType(boxedValue->values.getType())); |
|
313 int count = boxedValue->values.count(); |
|
314 operand->fArray->setCount(count); |
|
315 memcpy(operand->fArray->begin(), boxedValue->values.begin(), count * sizeof(SkOperand2)); |
|
316 fEngine->track(operand->fArray); |
|
317 } break; |
|
318 case SkType_Boolean: { |
|
319 SkDisplayBoolean* boxedValue = (SkDisplayBoolean*) displayable; |
|
320 operand->fS32 = boxedValue->value; |
|
321 } break; |
|
322 case SkType_Int: { |
|
323 SkDisplayInt* boxedValue = (SkDisplayInt*) displayable; |
|
324 operand->fS32 = boxedValue->value; |
|
325 } break; |
|
326 case SkType_Float: { |
|
327 SkDisplayFloat* boxedValue = (SkDisplayFloat*) displayable; |
|
328 operand->fScalar = boxedValue->value; |
|
329 } break; |
|
330 case SkType_String: { |
|
331 SkDisplayString* boxedValue = (SkDisplayString*) displayable; |
|
332 operand->fString = SkNEW_ARGS(SkString, (boxedValue->value)); |
|
333 } break; |
|
334 default: { |
|
335 const char* id; |
|
336 bool success = fEngine->getMaker().findKey(displayable, &id); |
|
337 SkASSERT(success); |
|
338 operand->fString = SkNEW_ARGS(SkString, (id)); |
|
339 } |
|
340 } |
|
341 return true; |
|
342 } |
|
343 |
|
344 virtual SkOperand2::OpType getReturnType(int /*index*/, SkOperand2* operand) { |
|
345 SkDisplayable* displayable = (SkDisplayable*) operand->fObject; |
|
346 switch (displayable->getType()) { |
|
347 case SkType_Array: |
|
348 return SkOperand2::kArray; |
|
349 case SkType_Int: |
|
350 return SkOperand2::kS32; |
|
351 case SkType_Float: |
|
352 return SkOperand2::kScalar; |
|
353 case SkType_String: |
|
354 default: |
|
355 return SkOperand2::kString; |
|
356 } |
|
357 } |
|
358 |
|
359 virtual Type getType() const { |
|
360 return kUnbox; |
|
361 } |
|
362 |
|
363 SkAnimatorScript2* fEngine; |
|
364 }; |
|
365 |
|
366 SkAnimatorScript2::SkAnimatorScript2(SkAnimateMaker& maker, SkDisplayable* working, SkDisplayTypes type) : |
|
367 SkScriptEngine2(ToOpType(type)), fMaker(maker), fWorking(working) { |
|
368 *fCallBackArray.append() = new SkAnimatorScript_Member(this); |
|
369 *fCallBackArray.append() = new SkAnimatorScript_MemberFunction(this); |
|
370 *fCallBackArray.append() = new SkAnimatorScript_Box(); |
|
371 *fCallBackArray.append() = new SkAnimatorScript_Unbox(this); |
|
372 *fCallBackArray.append() = new SkAnimatorScript_ID(this); |
|
373 if (type == SkType_ARGB) { |
|
374 *fCallBackArray.append() = new SkAnimatorScript_RGB(); |
|
375 *fCallBackArray.append() = new SkAnimatorScript_NamedColor(); |
|
376 } |
|
377 if (SkDisplayType::IsEnum(&maker, type)) { |
|
378 // !!! for SpiderMonkey, iterate through the enum values, and map them to globals |
|
379 const SkDisplayEnumMap& map = GetEnumValues(type); |
|
380 *fCallBackArray.append() = new SkAnimatorScript_Enum(map.fValues); |
|
381 } |
|
382 *fCallBackArray.append() = new SkAnimatorScript_Eval(this); |
|
383 #if 0 // !!! no extra support for now |
|
384 for (SkExtras** extraPtr = maker.fExtras.begin(); extraPtr < maker.fExtras.end(); extraPtr++) { |
|
385 SkExtras* extra = *extraPtr; |
|
386 if (extra->fExtraCallBack) |
|
387 *fCallBackArray.append() = new propertyCallBack(extra->fExtraCallBack, extra->fExtraStorage); |
|
388 } |
|
389 #endif |
|
390 } |
|
391 |
|
392 SkAnimatorScript2::~SkAnimatorScript2() { |
|
393 SkScriptCallBack** end = fCallBackArray.end(); |
|
394 for (SkScriptCallBack** ptr = fCallBackArray.begin(); ptr < end; ptr++) |
|
395 delete *ptr; |
|
396 } |
|
397 |
|
398 bool SkAnimatorScript2::evalMemberCommon(const SkMemberInfo* info, |
|
399 SkDisplayable* displayable, SkOperand2* value) { |
|
400 SkDisplayTypes original; |
|
401 SkDisplayTypes type = original = (SkDisplayTypes) info->getType(); |
|
402 if (info->fType == SkType_Array) |
|
403 type = SkType_Array; |
|
404 switch (type) { |
|
405 case SkType_ARGB: |
|
406 type = SkType_Int; |
|
407 case SkType_Boolean: |
|
408 case SkType_Int: |
|
409 case SkType_MSec: |
|
410 case SkType_Float: |
|
411 SkASSERT(info->getCount() == 1); |
|
412 if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) |
|
413 value->fS32 = *(int32_t*) info->memberData(displayable); // OK for SkScalar too |
|
414 if (type == SkType_MSec) { |
|
415 value->fScalar = SkScalarDiv((SkScalar) value->fS32, 1000); // dividing two ints is the same as dividing two scalars |
|
416 type = SkType_Float; |
|
417 } |
|
418 break; |
|
419 case SkType_String: { |
|
420 SkString* displayableString; |
|
421 if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) { |
|
422 info->getString(displayable, &displayableString); |
|
423 value->fString = new SkString(*displayableString); |
|
424 } |
|
425 } break; |
|
426 case SkType_Array: { |
|
427 SkASSERT(info->fType != SkType_MemberProperty); // !!! incomplete |
|
428 SkTDOperandArray* displayableArray = (SkTDOperandArray*) info->memberData(displayable); |
|
429 if (displayable->getType() == SkType_Array) { |
|
430 SkDisplayArray* typedArray = (SkDisplayArray*) displayable; |
|
431 original = typedArray->values.getType(); |
|
432 } |
|
433 SkASSERT(original != SkType_Unknown); |
|
434 SkOpArray* array = value->fArray = new SkOpArray(ToOpType(original)); |
|
435 track(array); |
|
436 int count = displayableArray->count(); |
|
437 if (count > 0) { |
|
438 array->setCount(count); |
|
439 memcpy(array->begin(), displayableArray->begin(), count * sizeof(SkOperand2)); |
|
440 } |
|
441 } break; |
|
442 default: |
|
443 SkASSERT(0); // unimplemented |
|
444 } |
|
445 return true; |
|
446 } |
|
447 |
|
448 const SkDisplayEnumMap& SkAnimatorScript2::GetEnumValues(SkDisplayTypes type) { |
|
449 int index = SkTSearch<SkDisplayTypes>(&gEnumMaps[0].fType, gEnumMapCount, type, |
|
450 sizeof(SkDisplayEnumMap)); |
|
451 SkASSERT(index >= 0); |
|
452 return gEnumMaps[index]; |
|
453 } |
|
454 |
|
455 SkDisplayTypes SkAnimatorScript2::ToDisplayType(SkOperand2::OpType type) { |
|
456 int val = type; |
|
457 switch (val) { |
|
458 case SkOperand2::kNoType: |
|
459 return SkType_Unknown; |
|
460 case SkOperand2::kS32: |
|
461 return SkType_Int; |
|
462 case SkOperand2::kScalar: |
|
463 return SkType_Float; |
|
464 case SkOperand2::kString: |
|
465 return SkType_String; |
|
466 case SkOperand2::kArray: |
|
467 return SkType_Array; |
|
468 case SkOperand2::kObject: |
|
469 return SkType_Displayable; |
|
470 default: |
|
471 SkASSERT(0); |
|
472 return SkType_Unknown; |
|
473 } |
|
474 } |
|
475 |
|
476 SkOperand2::OpType SkAnimatorScript2::ToOpType(SkDisplayTypes type) { |
|
477 if (SkDisplayType::IsDisplayable(NULL /* fMaker */, type)) |
|
478 return SkOperand2::kObject; |
|
479 if (SkDisplayType::IsEnum(NULL /* fMaker */, type)) |
|
480 return SkOperand2::kS32; |
|
481 switch (type) { |
|
482 case SkType_ARGB: |
|
483 case SkType_MSec: |
|
484 case SkType_Int: |
|
485 return SkOperand2::kS32; |
|
486 case SkType_Float: |
|
487 case SkType_Point: |
|
488 case SkType_3D_Point: |
|
489 return SkOperand2::kScalar; |
|
490 case SkType_Base64: |
|
491 case SkType_DynamicString: |
|
492 case SkType_String: |
|
493 return SkOperand2::kString; |
|
494 case SkType_Array: |
|
495 return SkOperand2::kArray; |
|
496 case SkType_Unknown: |
|
497 return SkOperand2::kNoType; |
|
498 default: |
|
499 SkASSERT(0); |
|
500 return SkOperand2::kNoType; |
|
501 } |
|
502 } |
|
503 |
|
504 bool SkAnimatorScript2::MapEnums(const char* ptr, const char* match, size_t len, int* value) { |
|
505 int index = 0; |
|
506 bool more = true; |
|
507 do { |
|
508 const char* last = strchr(ptr, '|'); |
|
509 if (last == NULL) { |
|
510 last = &ptr[strlen(ptr)]; |
|
511 more = false; |
|
512 } |
|
513 size_t length = last - ptr; |
|
514 if (len == length && strncmp(ptr, match, length) == 0) { |
|
515 *value = index; |
|
516 return true; |
|
517 } |
|
518 index++; |
|
519 ptr = last + 1; |
|
520 } while (more); |
|
521 return false; |
|
522 } |
|
523 |
|
524 #if defined SK_DEBUG |
|
525 |
|
526 #include "SkAnimator.h" |
|
527 |
|
528 static const char scriptTestSetup[] = |
|
529 "<screenplay>" |
|
530 "<apply>" |
|
531 "<paint>" |
|
532 "<emboss id='emboss' direction='[1,1,1]' />" |
|
533 "</paint>" |
|
534 "<animateField id='animation' field='direction' target='emboss' from='[1,1,1]' to='[-1,1,1]' dur='1'/>" |
|
535 "<set lval='direction[0]' target='emboss' to='-1' />" |
|
536 "</apply>" |
|
537 "<color id='testColor' color='0 ? rgb(0,0,0) : rgb(255,255,255)' />" |
|
538 "<color id='xColor' color='rgb(12,34,56)' />" |
|
539 "<typedArray id='emptyArray' />" |
|
540 "<typedArray id='intArray' values='[1, 4, 6]' />" |
|
541 "<s32 id='idx' value='2' />" |
|
542 "<s32 id='idy' value='2' />" |
|
543 "<string id='alpha' value='abc' />" |
|
544 "<rectangle id='testRect' left='Math.cos(0)' top='2' right='12' bottom='5' />" |
|
545 "<event id='evt'>" |
|
546 "<input name='x' />" |
|
547 "<apply scope='idy'>" |
|
548 "<set field='value' to='evt.x.s32' />" |
|
549 "</apply>" |
|
550 "</event>" |
|
551 "</screenplay>"; |
|
552 |
|
553 static const SkScriptNAnswer scriptTests[] = { |
|
554 { "alpha+alpha", SkType_String, 0, 0, "abcabc" }, |
|
555 { "0 ? Math.sin(0) : 1", SkType_Int, 1 }, |
|
556 { "intArray[4]", SkType_Unknown }, |
|
557 { "emptyArray[4]", SkType_Unknown }, |
|
558 { "idx", SkType_Int, 2 }, |
|
559 { "intArray.length", SkType_Int, 3 }, |
|
560 { "intArray.values[0]", SkType_Int, 1 }, |
|
561 { "intArray[0]", SkType_Int, 1 }, |
|
562 { "idx.value", SkType_Int, 2 }, |
|
563 { "alpha.value", SkType_String, 0, 0, "abc" }, |
|
564 { "alpha", SkType_String, 0, 0, "abc" }, |
|
565 { "alpha.value+alpha.value", SkType_String, 0, 0, "abcabc" }, |
|
566 { "alpha+idx", SkType_String, 0, 0, "abc2" }, |
|
567 { "idx+alpha", SkType_String, 0, 0, "2abc" }, |
|
568 { "intArray[idx]", SkType_Int, 6 }, |
|
569 { "alpha.slice(1,2)", SkType_String, 0, 0, "b" }, |
|
570 { "alpha.value.slice(1,2)", SkType_String, 0, 0, "b" }, |
|
571 { "Math.sin(0)", SkType_Float, 0, SkIntToScalar(0) }, |
|
572 { "testRect.left+2", SkType_Float, 0, SkIntToScalar(3) }, |
|
573 { "0 ? intArray[0] : 1", SkType_Int, 1 }, |
|
574 { "0 ? intArray.values[0] : 1", SkType_Int, 1 }, |
|
575 { "0 ? idx : 1", SkType_Int, 1 }, |
|
576 { "0 ? idx.value : 1", SkType_Int, 1 }, |
|
577 { "0 ? alpha.slice(1,2) : 1", SkType_Int, 1 }, |
|
578 { "0 ? alpha.value.slice(1,2) : 1", SkType_Int, 1 }, |
|
579 { "idy", SkType_Int, 3 } |
|
580 }; |
|
581 |
|
582 #define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) |
|
583 |
|
584 void SkAnimatorScript2::UnitTest() { |
|
585 #if defined(SK_SUPPORT_UNITTEST) |
|
586 SkAnimator animator; |
|
587 SkASSERT(animator.decodeMemory(scriptTestSetup, sizeof(scriptTestSetup)-1)); |
|
588 SkEvent evt; |
|
589 evt.setString("id", "evt"); |
|
590 evt.setS32("x", 3); |
|
591 animator.doUserEvent(evt); |
|
592 // set up animator with memory script above, then run value tests |
|
593 for (int index = 0; index < SkScriptNAnswer_testCount; index++) { |
|
594 SkAnimatorScript2 engine(*animator.fMaker, NULL, scriptTests[index].fType); |
|
595 SkScriptValue2 value; |
|
596 const char* script = scriptTests[index].fScript; |
|
597 bool success = engine.evaluateScript(&script, &value); |
|
598 if (success == false) { |
|
599 SkASSERT(scriptTests[index].fType == SkType_Unknown); |
|
600 continue; |
|
601 } |
|
602 SkASSERT(value.fType == ToOpType(scriptTests[index].fType)); |
|
603 SkScalar error; |
|
604 switch (value.fType) { |
|
605 case SkOperand2::kS32: |
|
606 SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); |
|
607 break; |
|
608 case SkOperand2::kScalar: |
|
609 error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); |
|
610 SkASSERT(error < SK_Scalar1 / 10000); |
|
611 break; |
|
612 case SkOperand2::kString: |
|
613 SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer)); |
|
614 break; |
|
615 default: |
|
616 SkASSERT(0); |
|
617 } |
|
618 } |
|
619 #endif |
|
620 } |
|
621 |
|
622 #endif |