epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2011 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
reed | 9a878a0 | 2015-12-27 12:47:25 -0800 | [diff] [blame] | 7 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 8 | #ifndef SkScript2_DEFINED |
| 9 | #define SkScript2_DEFINED |
| 10 | |
reed | 9a878a0 | 2015-12-27 12:47:25 -0800 | [diff] [blame] | 11 | #include "SkDisplayType.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 12 | #include "SkOperand2.h" |
| 13 | #include "SkStream.h" |
| 14 | #include "SkTDArray.h" |
| 15 | #include "SkTDArray_Experimental.h" |
| 16 | #include "SkTDict.h" |
| 17 | #include "SkTDStack.h" |
| 18 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 19 | typedef SkLongArray(SkString*) SkTDStringArray; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 20 | |
| 21 | class SkAnimateMaker; |
| 22 | class SkScriptCallBack; |
| 23 | |
| 24 | class SkScriptEngine2 { |
| 25 | public: |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 26 | enum Error { |
| 27 | kNoError, |
| 28 | kArrayIndexOutOfBounds, |
| 29 | kCouldNotFindReferencedID, |
| 30 | kFunctionCallFailed, |
| 31 | kMemberOpFailed, |
| 32 | kPropertyOpFailed |
| 33 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 34 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 35 | enum Attrs { |
| 36 | kConstant, |
| 37 | kVariable |
| 38 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 39 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 40 | SkScriptEngine2(SkOperand2::OpType returnType); |
| 41 | ~SkScriptEngine2(); |
| 42 | bool convertTo(SkOperand2::OpType , SkScriptValue2* ); |
| 43 | bool evaluateScript(const char** script, SkScriptValue2* value); |
| 44 | void forget(SkOpArray* array); |
| 45 | Error getError() { return fError; } |
| 46 | SkOperand2::OpType getReturnType() { return fReturnType; } |
| 47 | void track(SkOpArray* array) { |
| 48 | SkASSERT(fTrackArray.find(array) < 0); |
| 49 | *fTrackArray.append() = array; } |
| 50 | void track(SkString* string) { |
| 51 | SkASSERT(fTrackString.find(string) < 0); |
| 52 | *fTrackString.append() = string; |
| 53 | } |
| 54 | static bool ConvertTo(SkScriptEngine2* , SkOperand2::OpType toType, SkScriptValue2* value); |
| 55 | static SkScalar IntToScalar(int32_t ); |
| 56 | static bool ValueToString(const SkScriptValue2& value, SkString* string); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 57 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 58 | enum Op { // used by tokenizer attribute table |
| 59 | kUnassigned, |
| 60 | kAdd, |
| 61 | kBitAnd, |
| 62 | kBitNot, |
| 63 | kBitOr, |
| 64 | kDivide, |
| 65 | kEqual, |
| 66 | kFlipOps, |
| 67 | kGreaterEqual, |
| 68 | kLogicalAnd, |
| 69 | kLogicalNot, |
| 70 | kLogicalOr, |
| 71 | kMinus, |
| 72 | kModulo, |
| 73 | kMultiply, |
| 74 | kShiftLeft, |
| 75 | kShiftRight, // signed |
| 76 | kSubtract, |
| 77 | kXor, |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 78 | // following not in attribute table |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 79 | kArrayOp, |
| 80 | kElse, |
| 81 | kIf, |
| 82 | kParen, |
| 83 | kLastLogicalOp, |
| 84 | kArtificialOp = 0x20 |
| 85 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 86 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 87 | enum TypeOp { // generated by tokenizer |
| 88 | kNop, // should never get generated |
| 89 | kAccumulatorPop, |
| 90 | kAccumulatorPush, |
| 91 | kAddInt, |
| 92 | kAddScalar, |
| 93 | kAddString, // string concat |
| 94 | kArrayIndex, |
| 95 | kArrayParam, |
| 96 | kArrayToken, |
| 97 | kBitAndInt, |
| 98 | kBitNotInt, |
| 99 | kBitOrInt, |
| 100 | kBoxToken, |
| 101 | kCallback, |
| 102 | kDivideInt, |
| 103 | kDivideScalar, |
| 104 | kDotOperator, |
| 105 | kElseOp, |
| 106 | kEnd, |
| 107 | kEqualInt, |
| 108 | kEqualScalar, |
| 109 | kEqualString, |
| 110 | kFunctionCall, |
| 111 | kFlipOpsOp, |
| 112 | kFunctionToken, |
| 113 | kGreaterEqualInt, |
| 114 | kGreaterEqualScalar, |
| 115 | kGreaterEqualString, |
| 116 | kIfOp, |
| 117 | kIntToScalar, |
| 118 | kIntToScalar2, |
| 119 | kIntToString, |
| 120 | kIntToString2, |
| 121 | kIntegerAccumulator, |
| 122 | kIntegerOperand, |
| 123 | kLogicalAndInt, |
| 124 | kLogicalNotInt, |
| 125 | kLogicalOrInt, |
| 126 | kMemberOp, |
| 127 | kMinusInt, |
| 128 | kMinusScalar, |
| 129 | kModuloInt, |
| 130 | kModuloScalar, |
| 131 | kMultiplyInt, |
| 132 | kMultiplyScalar, |
| 133 | kPropertyOp, |
| 134 | kScalarAccumulator, |
| 135 | kScalarOperand, |
| 136 | kScalarToInt, |
| 137 | kScalarToInt2, |
| 138 | kScalarToString, |
| 139 | kScalarToString2, |
| 140 | kShiftLeftInt, |
| 141 | kShiftRightInt, // signed |
| 142 | kStringAccumulator, |
| 143 | kStringOperand, |
| 144 | kStringToInt, |
| 145 | kStringToScalar, |
| 146 | kStringToScalar2, |
| 147 | kStringTrack, |
| 148 | kSubtractInt, |
| 149 | kSubtractScalar, |
| 150 | kToBool, |
| 151 | kUnboxToken, |
| 152 | kUnboxToken2, |
| 153 | kXorInt, |
| 154 | kLastTypeOp |
| 155 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 156 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 157 | enum OpBias { |
| 158 | kNoBias, |
| 159 | kTowardsNumber = 0, |
| 160 | kTowardsString |
| 161 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 162 | |
| 163 | protected: |
| 164 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 165 | enum BraceStyle { |
| 166 | // kStructBrace, |
| 167 | kArrayBrace, |
| 168 | kFunctionBrace |
| 169 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 170 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 171 | enum AddTokenRegister { |
| 172 | kAccumulator, |
| 173 | kOperand |
| 174 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 175 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 176 | enum ResultIsBoolean { |
| 177 | kResultIsNotBoolean, |
| 178 | kResultIsBoolean |
| 179 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 180 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 181 | struct OperatorAttributes { |
| 182 | unsigned int fLeftType : 3; // SkOpType union, but only lower values |
| 183 | unsigned int fRightType : 3; // SkOpType union, but only lower values |
| 184 | OpBias fBias : 1; |
| 185 | ResultIsBoolean fResultIsBoolean : 1; |
| 186 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 187 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 188 | struct Branch { |
| 189 | Branch() { |
| 190 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 191 | |
commit-bot@chromium.org | 92f9326 | 2014-05-04 01:26:19 +0000 | [diff] [blame] | 192 | Branch(Op op, int depth, size_t offset) |
| 193 | : fOffset(SkToU16(offset)), fOpStackDepth(depth), fOperator(op) |
| 194 | , fPrimed(kIsNotPrimed), fDone(kIsNotDone) { |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 195 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 196 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 197 | enum Primed { |
| 198 | kIsNotPrimed, |
| 199 | kIsPrimed |
| 200 | }; |
| 201 | |
| 202 | enum Done { |
| 203 | kIsNotDone, |
| 204 | kIsDone, |
| 205 | }; |
| 206 | |
| 207 | unsigned fOffset : 16; // offset in generated stream where branch needs to go |
| 208 | int fOpStackDepth : 7; // depth when operator was found |
| 209 | Op fOperator : 6; // operand which generated branch |
| 210 | mutable Primed fPrimed : 1; // mark when next instruction generates branch |
| 211 | Done fDone : 1; // mark when branch is complete |
| 212 | void prime() { fPrimed = kIsPrimed; } |
| 213 | void resolve(SkDynamicMemoryWStream* , size_t offset); |
| 214 | }; |
| 215 | |
| 216 | static const OperatorAttributes gOpAttributes[]; |
| 217 | static const signed char gPrecedence[]; |
| 218 | static const TypeOp gTokens[]; |
| 219 | void addToken(TypeOp ); |
| 220 | void addTokenConst(SkScriptValue2* , AddTokenRegister , SkOperand2::OpType , TypeOp ); |
| 221 | void addTokenInt(int ); |
| 222 | void addTokenScalar(SkScalar ); |
| 223 | void addTokenString(const SkString& ); |
| 224 | void addTokenValue(const SkScriptValue2& , AddTokenRegister ); |
| 225 | int arithmeticOp(char ch, char nextChar, bool lastPush); |
| 226 | bool convertParams(SkTDArray<SkScriptValue2>* , |
| 227 | const SkOperand2::OpType* paramTypes, int paramTypeCount); |
| 228 | void convertToString(SkOperand2* operand, SkOperand2::OpType type) { |
| 229 | SkScriptValue2 scriptValue; |
| 230 | scriptValue.fOperand = *operand; |
| 231 | scriptValue.fType = type; |
| 232 | convertTo(SkOperand2::kString, &scriptValue); |
| 233 | *operand = scriptValue.fOperand; |
| 234 | } |
| 235 | bool evaluateDot(const char*& script); |
| 236 | bool evaluateDotParam(const char*& script, const char* field, size_t fieldLength); |
| 237 | bool functionParams(const char** scriptPtr, SkTDArray<SkScriptValue2>* params); |
| 238 | size_t getTokenOffset(); |
| 239 | SkOperand2::OpType getUnboxType(SkOperand2 scriptValue); |
| 240 | bool handleArrayIndexer(const char** scriptPtr); |
| 241 | bool handleFunction(const char** scriptPtr); |
| 242 | bool handleMember(const char* field, size_t len, void* object); |
| 243 | bool handleMemberFunction(const char* field, size_t len, void* object, |
| 244 | SkTDArray<SkScriptValue2>* params); |
| 245 | bool handleProperty(); |
| 246 | bool handleUnbox(SkScriptValue2* scriptValue); |
| 247 | bool innerScript(const char** scriptPtr, SkScriptValue2* value); |
| 248 | int logicalOp(char ch, char nextChar); |
| 249 | void processLogicalOp(Op op); |
| 250 | bool processOp(); |
| 251 | void resolveBranch(Branch& ); |
| 252 | // void setAnimateMaker(SkAnimateMaker* maker) { fMaker = maker; } |
| 253 | SkDynamicMemoryWStream fStream; |
| 254 | SkDynamicMemoryWStream* fActiveStream; |
| 255 | SkTDStack<BraceStyle> fBraceStack; // curly, square, function paren |
| 256 | SkTDStack<Branch> fBranchStack; // logical operators, slot to store forward branch |
| 257 | SkLongArray(SkScriptCallBack*) fCallBackArray; |
| 258 | SkTDStack<Op> fOpStack; |
| 259 | SkTDStack<SkScriptValue2> fValueStack; |
| 260 | // SkAnimateMaker* fMaker; |
| 261 | SkLongArray(SkOpArray*) fTrackArray; |
| 262 | SkTDStringArray fTrackString; |
| 263 | const char* fToken; // one-deep stack |
| 264 | size_t fTokenLength; |
| 265 | SkOperand2::OpType fReturnType; |
| 266 | Error fError; |
| 267 | SkOperand2::OpType fAccumulatorType; // tracking for code generation |
| 268 | SkBool fBranchPopAllowed; |
| 269 | SkBool fConstExpression; |
| 270 | SkBool fOperandInUse; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 271 | private: |
| 272 | #ifdef SK_DEBUG |
| 273 | public: |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 274 | void decompile(const unsigned char* , size_t ); |
| 275 | static void UnitTest(); |
| 276 | static void ValidateDecompileTable(); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 277 | #endif |
| 278 | }; |
| 279 | |
| 280 | #ifdef SK_DEBUG |
| 281 | |
| 282 | struct SkScriptNAnswer2 { |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 283 | const char* fScript; |
| 284 | SkOperand2::OpType fType; |
| 285 | int32_t fIntAnswer; |
| 286 | SkScalar fScalarAnswer; |
| 287 | const char* fStringAnswer; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 288 | }; |
| 289 | |
| 290 | #endif |
| 291 | |
| 292 | |
| 293 | #endif // SkScript2_DEFINED |