blob: b211a71c123728ce1c4b440313ee399ef6787d0a [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkScriptRuntime.h"
9#include "SkScript2.h"
tomhudson@google.comc12e1b12011-09-27 18:03:23 +000010#include "SkMath.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkParse.h"
12#include "SkScriptCallBack.h"
13#include "SkString.h"
14#include "SkOpArray.h"
15
16// script tokenizer
17
18// turn text into token string
19// turn number literals into inline UTF8-style values
20// process operators to turn standard notation into stack notation
21
22// defer processing until the tokens can all be resolved
23// then, turn token strings into indices into the appropriate tables / dictionaries
24
25// consider: const evaluation?
26
27// replace script string with script tokens preceeded by special value
28
29// need second version of script plugins that return private index of found value?
rmistry@google.comd6176b02012-08-23 18:14:13 +000030 // then would need in script index of plugin, private index
reed@android.com8a1c16f2008-12-17 15:59:43 +000031
32// encode brace stack push/pop as opcodes
33
34// should token script enocde type where possible?
35
36// current flow:
rmistry@google.comd6176b02012-08-23 18:14:13 +000037 // strip whitespace
38 // if in array brace [ recurse, continue
39 // if token, handle function, or array, or property (continue)
40 // parse number, continue
41 // parse token, continue
42 // parse string literal, continue
43 // if dot operator, handle dot, continue
44 // if [ , handle array literal or accessor, continue
45 // if ), pop (if function, break)
46 // if ], pop ; if ',' break
47 // handle logical ops
48 // or, handle arithmetic ops
49 // loop
reed@android.com8a1c16f2008-12-17 15:59:43 +000050
51// !!! things to do
rmistry@google.comd6176b02012-08-23 18:14:13 +000052 // add separate processing loop to advance while suppressed
53 // or, include jump offset to skip suppressed code?
reed@android.com8a1c16f2008-12-17 15:59:43 +000054
55SkScriptRuntime::~SkScriptRuntime() {
rmistry@google.comd6176b02012-08-23 18:14:13 +000056 for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
57 delete *stringPtr;
58 for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
59 delete *arrayPtr;
reed@android.com8a1c16f2008-12-17 15:59:43 +000060}
61
62bool SkScriptRuntime::executeTokens(unsigned char* opCode) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000063 SkOperand2 operand[2]; // 1=accumulator and 2=operand
64 SkScriptEngine2::TypeOp op;
65 size_t ref;
66 int index, size;
67 int registerLoad;
68 SkScriptCallBack* callBack SK_INIT_TO_AVOID_WARNING;
69 do {
70 switch ((op = (SkScriptEngine2::TypeOp) *opCode++)) {
71 case SkScriptEngine2::kArrayToken: // create an array
72 operand[0].fArray = new SkOpArray(SkOperand2::kNoType /*fReturnType*/);
73 break;
74 case SkScriptEngine2::kArrayIndex: // array accessor
75 index = operand[1].fS32;
76 if (index >= operand[0].fArray->count()) {
77 fError = kArrayIndexOutOfBounds;
78 return false;
79 }
80 operand[0] = operand[0].fArray->begin()[index];
81 break;
82 case SkScriptEngine2::kArrayParam: // array initializer, or function param
83 *operand[0].fArray->append() = operand[1];
84 break;
85 case SkScriptEngine2::kCallback:
86 memcpy(&index, opCode, sizeof(index));
87 opCode += sizeof(index);
88 callBack = fCallBackArray[index];
89 break;
90 case SkScriptEngine2::kFunctionCall: {
91 memcpy(&ref, opCode, sizeof(ref));
92 opCode += sizeof(ref);
93 SkScriptCallBackFunction* callBackFunction = (SkScriptCallBackFunction*) callBack;
94 if (callBackFunction->invoke(ref, operand[0].fArray, /* params */
95 &operand[0] /* result */) == false) {
96 fError = kFunctionCallFailed;
97 return false;
98 }
99 } break;
100 case SkScriptEngine2::kMemberOp: {
101 memcpy(&ref, opCode, sizeof(ref));
102 opCode += sizeof(ref);
103 SkScriptCallBackMember* callBackMember = (SkScriptCallBackMember*) callBack;
104 if (callBackMember->invoke(ref, operand[0].fObject, &operand[0]) == false) {
105 fError = kMemberOpFailed;
106 return false;
107 }
108 } break;
109 case SkScriptEngine2::kPropertyOp: {
110 memcpy(&ref, opCode, sizeof(ref));
111 opCode += sizeof(ref);
112 SkScriptCallBackProperty* callBackProperty = (SkScriptCallBackProperty*) callBack;
113 if (callBackProperty->getResult(ref, &operand[0])== false) {
114 fError = kPropertyOpFailed;
115 return false;
116 }
117 } break;
118 case SkScriptEngine2::kAccumulatorPop:
119 fRunStack.pop(&operand[0]);
120 break;
121 case SkScriptEngine2::kAccumulatorPush:
122 *fRunStack.push() = operand[0];
123 break;
124 case SkScriptEngine2::kIntegerAccumulator:
125 case SkScriptEngine2::kIntegerOperand:
126 registerLoad = op - SkScriptEngine2::kIntegerAccumulator;
127 memcpy(&operand[registerLoad].fS32, opCode, sizeof(int32_t));
128 opCode += sizeof(int32_t);
129 break;
130 case SkScriptEngine2::kScalarAccumulator:
131 case SkScriptEngine2::kScalarOperand:
132 registerLoad = op - SkScriptEngine2::kScalarAccumulator;
133 memcpy(&operand[registerLoad].fScalar, opCode, sizeof(SkScalar));
134 opCode += sizeof(SkScalar);
135 break;
136 case SkScriptEngine2::kStringAccumulator:
137 case SkScriptEngine2::kStringOperand: {
138 SkString* strPtr = new SkString();
139 track(strPtr);
140 registerLoad = op - SkScriptEngine2::kStringAccumulator;
141 memcpy(&size, opCode, sizeof(size));
142 opCode += sizeof(size);
143 strPtr->set((char*) opCode, size);
144 opCode += size;
145 operand[registerLoad].fString = strPtr;
146 } break;
147 case SkScriptEngine2::kStringTrack: // call after kObjectToValue
148 track(operand[0].fString);
149 break;
150 case SkScriptEngine2::kBoxToken: {
151 SkOperand2::OpType type;
152 memcpy(&type, opCode, sizeof(type));
153 opCode += sizeof(type);
154 SkScriptCallBackConvert* callBackBox = (SkScriptCallBackConvert*) callBack;
155 if (callBackBox->convert(type, &operand[0]) == false)
156 return false;
157 } break;
158 case SkScriptEngine2::kUnboxToken:
159 case SkScriptEngine2::kUnboxToken2: {
160 SkScriptCallBackConvert* callBackUnbox = (SkScriptCallBackConvert*) callBack;
161 if (callBackUnbox->convert(SkOperand2::kObject, &operand[0]) == false)
162 return false;
163 } break;
164 case SkScriptEngine2::kIfOp:
165 case SkScriptEngine2::kLogicalAndInt:
166 memcpy(&size, opCode, sizeof(size));
167 opCode += sizeof(size);
168 if (operand[0].fS32 == 0)
169 opCode += size; // skip to else (or end of if predicate)
170 break;
171 case SkScriptEngine2::kElseOp:
172 memcpy(&size, opCode, sizeof(size));
173 opCode += sizeof(size);
174 opCode += size; // if true: after predicate, always skip to end of else
175 break;
176 case SkScriptEngine2::kLogicalOrInt:
177 memcpy(&size, opCode, sizeof(size));
178 opCode += sizeof(size);
179 if (operand[0].fS32 != 0)
180 opCode += size; // skip to kToBool opcode after || predicate
181 break;
182 // arithmetic conversion ops
183 case SkScriptEngine2::kFlipOpsOp:
184 SkTSwap(operand[0], operand[1]);
185 break;
186 case SkScriptEngine2::kIntToString:
187 case SkScriptEngine2::kIntToString2:
188 case SkScriptEngine2::kScalarToString:
189 case SkScriptEngine2::kScalarToString2:{
190 SkString* strPtr = new SkString();
191 track(strPtr);
192 if (op == SkScriptEngine2::kIntToString || op == SkScriptEngine2::kIntToString2)
193 strPtr->appendS32(operand[op - SkScriptEngine2::kIntToString].fS32);
194 else
195 strPtr->appendScalar(operand[op - SkScriptEngine2::kScalarToString].fScalar);
196 operand[0].fString = strPtr;
197 } break;
198 case SkScriptEngine2::kIntToScalar:
199 case SkScriptEngine2::kIntToScalar2:
200 operand[0].fScalar = SkScriptEngine2::IntToScalar(operand[op - SkScriptEngine2::kIntToScalar].fS32);
201 break;
202 case SkScriptEngine2::kStringToInt:
203 if (SkParse::FindS32(operand[0].fString->c_str(), &operand[0].fS32) == false)
204 return false;
205 break;
206 case SkScriptEngine2::kStringToScalar:
207 case SkScriptEngine2::kStringToScalar2:
208 if (SkParse::FindScalar(operand[0].fString->c_str(),
209 &operand[op - SkScriptEngine2::kStringToScalar].fScalar) == false)
210 return false;
211 break;
212 case SkScriptEngine2::kScalarToInt:
213 operand[0].fS32 = SkScalarFloor(operand[0].fScalar);
214 break;
215 // arithmetic ops
216 case SkScriptEngine2::kAddInt:
217 operand[0].fS32 += operand[1].fS32;
218 break;
219 case SkScriptEngine2::kAddScalar:
220 operand[0].fScalar += operand[1].fScalar;
221 break;
222 case SkScriptEngine2::kAddString:
223// if (fTrackString.find(operand[1].fString) < 0) {
224// operand[1].fString = SkNEW_ARGS(SkString, (*operand[1].fString));
225// track(operand[1].fString);
226// }
227 operand[0].fString->append(*operand[1].fString);
228 break;
229 case SkScriptEngine2::kBitAndInt:
230 operand[0].fS32 &= operand[1].fS32;
231 break;
232 case SkScriptEngine2::kBitNotInt:
233 operand[0].fS32 = ~operand[0].fS32;
234 break;
235 case SkScriptEngine2::kBitOrInt:
236 operand[0].fS32 |= operand[1].fS32;
237 break;
238 case SkScriptEngine2::kDivideInt:
239 SkASSERT(operand[1].fS32 != 0);
240 if (operand[1].fS32 == 0)
241 operand[0].fS32 = operand[0].fS32 == 0 ? SK_NaN32 :
242 operand[0].fS32 > 0 ? SK_MaxS32 : -SK_MaxS32;
243 else
244 if (operand[1].fS32 != 0) // throw error on divide by zero?
245 operand[0].fS32 /= operand[1].fS32;
246 break;
247 case SkScriptEngine2::kDivideScalar:
248 if (operand[1].fScalar == 0)
249 operand[0].fScalar = operand[0].fScalar == 0 ? SK_ScalarNaN :
250 operand[0].fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax;
251 else
252 operand[0].fScalar = SkScalarDiv(operand[0].fScalar, operand[1].fScalar);
253 break;
254 case SkScriptEngine2::kEqualInt:
255 operand[0].fS32 = operand[0].fS32 == operand[1].fS32;
256 break;
257 case SkScriptEngine2::kEqualScalar:
258 operand[0].fS32 = operand[0].fScalar == operand[1].fScalar;
259 break;
260 case SkScriptEngine2::kEqualString:
261 operand[0].fS32 = *operand[0].fString == *operand[1].fString;
262 break;
263 case SkScriptEngine2::kGreaterEqualInt:
264 operand[0].fS32 = operand[0].fS32 >= operand[1].fS32;
265 break;
266 case SkScriptEngine2::kGreaterEqualScalar:
267 operand[0].fS32 = operand[0].fScalar >= operand[1].fScalar;
268 break;
269 case SkScriptEngine2::kGreaterEqualString:
270 operand[0].fS32 = strcmp(operand[0].fString->c_str(), operand[1].fString->c_str()) >= 0;
271 break;
272 case SkScriptEngine2::kToBool:
273 operand[0].fS32 = !! operand[0].fS32;
274 break;
275 case SkScriptEngine2::kLogicalNotInt:
276 operand[0].fS32 = ! operand[0].fS32;
277 break;
278 case SkScriptEngine2::kMinusInt:
279 operand[0].fS32 = -operand[0].fS32;
280 break;
281 case SkScriptEngine2::kMinusScalar:
282 operand[0].fScalar = -operand[0].fScalar;
283 break;
284 case SkScriptEngine2::kModuloInt:
285 operand[0].fS32 %= operand[1].fS32;
286 break;
287 case SkScriptEngine2::kModuloScalar:
288 operand[0].fScalar = SkScalarMod(operand[0].fScalar, operand[1].fScalar);
289 break;
290 case SkScriptEngine2::kMultiplyInt:
291 operand[0].fS32 *= operand[1].fS32;
292 break;
293 case SkScriptEngine2::kMultiplyScalar:
294 operand[0].fScalar = SkScalarMul(operand[0].fScalar, operand[1].fScalar);
295 break;
296 case SkScriptEngine2::kShiftLeftInt:
297 operand[0].fS32 <<= operand[1].fS32;
298 break;
299 case SkScriptEngine2::kShiftRightInt:
300 operand[0].fS32 >>= operand[1].fS32;
301 break;
302 case SkScriptEngine2::kSubtractInt:
303 operand[0].fS32 -= operand[1].fS32;
304 break;
305 case SkScriptEngine2::kSubtractScalar:
306 operand[0].fScalar -= operand[1].fScalar;
307 break;
308 case SkScriptEngine2::kXorInt:
309 operand[0].fS32 ^= operand[1].fS32;
310 break;
311 case SkScriptEngine2::kEnd:
312 goto done;
313 case SkScriptEngine2::kNop:
314 SkASSERT(0);
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000315 default:
316 break;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000317 }
318 } while (true);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000319done:
rmistry@google.comd6176b02012-08-23 18:14:13 +0000320 fRunStack.push(operand[0]);
321 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322}
323
324bool SkScriptRuntime::getResult(SkOperand2* result) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000325 if (fRunStack.count() == 0)
326 return false;
327 fRunStack.pop(result);
328 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329}
330
rmistry@google.comd6176b02012-08-23 18:14:13 +0000331void SkScriptRuntime::track(SkOpArray* array) {
332 SkASSERT(fTrackArray.find(array) < 0);
333 *fTrackArray.append() = array;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334}
335
rmistry@google.comd6176b02012-08-23 18:14:13 +0000336void SkScriptRuntime::track(SkString* string) {
337 SkASSERT(fTrackString.find(string) < 0);
338 *fTrackString.append() = string;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339}
340
341void SkScriptRuntime::untrack(SkOpArray* array) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000342 int index = fTrackArray.find(array);
343 SkASSERT(index >= 0);
344 fTrackArray.begin()[index] = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345}
346
347void SkScriptRuntime::untrack(SkString* string) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000348 int index = fTrackString.find(string);
349 SkASSERT(index >= 0);
350 fTrackString.begin()[index] = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351}
352