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