1
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
9
10#include "SkMemberInfo.h"
11#include "SkAnimateMaker.h"
12#include "SkAnimatorScript.h"
13#include "SkBase64.h"
14#include "SkCamera.h"
15#include "SkDisplayable.h"
16#include "SkDisplayTypes.h"
17#include "SkDraw3D.h"
18#include "SkDrawColor.h"
19#include "SkParse.h"
20#include "SkScript.h"
21#include "SkTSearch.h"
22#include "SkTypedArray.h"
23
24size_t SkMemberInfo::GetSize(SkDisplayTypes type) { // size of simple types only
25    size_t byteSize;
26    switch (type) {
27        case SkType_ARGB:
28            byteSize = sizeof(SkColor);
29            break;
30        case SkType_AddMode:
31        case SkType_Align:
32        case SkType_ApplyMode:
33        case SkType_ApplyTransition:
34        case SkType_BitmapEncoding:
35        case SkType_Boolean:
36        case SkType_Cap:
37        case SkType_EventCode:
38        case SkType_EventKind:
39        case SkType_EventMode:
40        case SkType_FilterType:
41        case SkType_FontStyle:
42        case SkType_FromPathMode:
43        case SkType_Join:
44        case SkType_MaskFilterBlurStyle:
45        case SkType_PathDirection:
46        case SkType_Style:
47        case SkType_TileMode:
48        case SkType_Xfermode:
49            byteSize = sizeof(int);
50            break;
51        case SkType_Base64: // assume base64 data is always const, copied by ref
52        case SkType_Displayable:
53        case SkType_Drawable:
54        case SkType_Matrix:
55            byteSize = sizeof(void*);
56            break;
57        case SkType_MSec:
58            byteSize = sizeof(SkMSec);
59            break;
60        case SkType_Point:
61            byteSize = sizeof(SkPoint);
62            break;
63        case SkType_3D_Point:
64            byteSize = sizeof(Sk3D_Point);
65            break;
66        case SkType_Int:
67            byteSize = sizeof(int32_t);
68            break;
69        case SkType_Float:
70            byteSize = sizeof(SkScalar);
71            break;
72        case SkType_DynamicString:
73        case SkType_String:
74            byteSize = sizeof(SkString);    // assume we'll copy by reference, not value
75            break;
76        default:
77//          SkASSERT(0);
78            byteSize = 0;
79    }
80    return byteSize;
81}
82
83bool SkMemberInfo::getArrayValue(const SkDisplayable* displayable, int index, SkOperand* value) const {
84    SkASSERT(fType != SkType_String && fType != SkType_MemberProperty);
85    char* valuePtr = (char*) *(SkOperand**) memberData(displayable);
86    SkDisplayTypes type = (SkDisplayTypes) 0;
87    if (displayable->getType() == SkType_Array) {
88        SkDisplayArray* dispArray = (SkDisplayArray*) displayable;
89        if (dispArray->values.count() <= index)
90            return false;
91        type = dispArray->values.getType();
92    } else {
93        SkASSERT(0); // incomplete
94    }
95    size_t byteSize = GetSize(type);
96    memcpy(value, valuePtr + index * byteSize, byteSize);
97    return true;
98}
99
100size_t SkMemberInfo::getSize(const SkDisplayable* displayable) const {
101    size_t byteSize;
102    switch (fType) {
103        case SkType_MemberProperty:
104            byteSize = GetSize(propertyType());
105            break;
106        case SkType_Array: {
107            SkDisplayTypes type;
108            if (displayable == nullptr)
109                return sizeof(int);
110            if (displayable->getType() == SkType_Array) {
111                SkDisplayArray* dispArray = (SkDisplayArray*) displayable;
112                type = dispArray->values.getType();
113            } else
114                type = propertyType();
115            SkTDOperandArray* array = (SkTDOperandArray*) memberData(displayable);
116            byteSize = GetSize(type) * array->count();
117            } break;
118        default:
119            byteSize = GetSize((SkDisplayTypes) fType);
120    }
121    return byteSize;
122}
123
124void SkMemberInfo::getString(const SkDisplayable* displayable, SkString** string) const {
125    if (fType == SkType_MemberProperty) {
126        SkScriptValue value;
127        displayable->getProperty(propertyIndex(), &value);
128        SkASSERT(value.fType == SkType_String);
129        *string = value.fOperand.fString;
130        return;
131    }
132    SkASSERT(fCount == sizeof(SkString) / sizeof(SkScalar));
133    SkASSERT(fType == SkType_String || fType == SkType_DynamicString);
134    void* valuePtr = memberData(displayable);
135    *string = (SkString*) valuePtr;
136}
137
138void SkMemberInfo::getValue(const SkDisplayable* displayable, SkOperand value[], int count) const {
139    SkASSERT(fType != SkType_String && fType != SkType_MemberProperty);
140    SkASSERT(count == fCount);
141    void* valuePtr = memberData(displayable);
142    size_t byteSize = getSize(displayable);
143    SkASSERT(sizeof(value[0].fScalar) == sizeof(value[0])); // no support for 64 bit pointers, yet
144    memcpy(value, valuePtr, byteSize);
145}
146
147void SkMemberInfo::setString(SkDisplayable* displayable, SkString* value) const {
148    SkString* string = (SkString*) memberData(displayable);
149    string->set(*value);
150    displayable->dirty();
151}
152
153void SkMemberInfo::setValue(SkDisplayable* displayable, const SkOperand values[],
154                            int count) const {
155    SkASSERT(sizeof(values[0].fScalar) == sizeof(values[0]));   // no support for 64 bit pointers, yet
156    char* dst = (char*) memberData(displayable);
157    if (fType == SkType_Array) {
158        SkTDScalarArray* array = (SkTDScalarArray* ) dst;
159        array->setCount(count);
160        dst = (char*) array->begin();
161    }
162    memcpy(dst, values, count * sizeof(SkOperand));
163    displayable->dirty();
164}
165
166
167static inline bool is_between(int c, int min, int max)
168{
169    return (unsigned)(c - min) <= (unsigned)(max - min);
170}
171
172static inline bool is_hex(int c)
173{
174    if (is_between(c, '0', '9'))
175        return true;
176    c |= 0x20;  // make us lower-case
177    if (is_between(c, 'a', 'f'))
178        return true;
179    return false;
180}
181
182
183bool SkMemberInfo::setValue(SkAnimateMaker& maker, SkTDOperandArray* arrayStorage,
184    int storageOffset, int maxStorage, SkDisplayable* displayable, SkDisplayTypes outType,
185    const char rawValue[], size_t rawValueLen) const
186{
187    SkString valueStr(rawValue, rawValueLen);
188    SkScriptValue scriptValue;
189    scriptValue.fType = SkType_Unknown;
190    scriptValue.fOperand.fS32 = 0;
191    SkDisplayTypes type = getType();
192    SkAnimatorScript engine(maker, displayable, type);
193    if (arrayStorage)
194        displayable = nullptr;
195    bool success = true;
196    void* untypedStorage = nullptr;
197    if (displayable && fType != SkType_MemberProperty && fType != SkType_MemberFunction)
198        untypedStorage = (SkTDOperandArray*) memberData(displayable);
199
200    if (type == SkType_ARGB) {
201        // for both SpiderMonkey and SkiaScript, substitute any #xyz or #xxyyzz first
202            // it's enough to expand the colors into 0xFFxxyyzz
203        const char* poundPos;
204        while ((poundPos = strchr(valueStr.c_str(), '#')) != nullptr) {
205            size_t offset = poundPos - valueStr.c_str();
206            if (valueStr.size() - offset < 4)
207                break;
208            char r = poundPos[1];
209            char g = poundPos[2];
210            char b = poundPos[3];
211            if (is_hex(r) == false || is_hex(g) == false || is_hex(b) == false)
212                break;
213            char hex = poundPos[4];
214            if (is_hex(hex) == false) {
215                valueStr.insertUnichar(offset + 1, r);
216                valueStr.insertUnichar(offset + 3, g);
217                valueStr.insertUnichar(offset + 5, b);
218            }
219            *(char*) poundPos = '0'; // overwrite '#'
220            valueStr.insert(offset + 1, "xFF");
221        }
222    }
223    if (SkDisplayType::IsDisplayable(&maker, type) || SkDisplayType::IsEnum(&maker, type) || type == SkType_ARGB)
224        goto scriptCommon;
225    switch (type) {
226        case SkType_String:
227#if 0
228            if (displayable && displayable->isAnimate()) {
229
230                goto noScriptString;
231            }
232            if (strncmp(rawValue, "#string:", sizeof("#string:") - 1) == 0) {
233                SkASSERT(sizeof("string") == sizeof("script"));
234                char* stringHeader = valueStr.writable_str();
235                memcpy(&stringHeader[1], "script", sizeof("script") - 1);
236                rawValue = valueStr.c_str();
237                goto noScriptString;
238            } else
239#endif
240            if (strncmp(rawValue, "#script:", sizeof("#script:") - 1) != 0)
241                goto noScriptString;
242            valueStr.remove(0, 8);
243        case SkType_Unknown:
244        case SkType_Int:
245        case SkType_MSec:  // for the purposes of script, MSec is treated as a Scalar
246        case SkType_Point:
247        case SkType_3D_Point:
248        case SkType_Float:
249        case SkType_Array:
250scriptCommon: {
251                const char* script = valueStr.c_str();
252                success = engine.evaluateScript(&script, &scriptValue);
253                if (success == false) {
254                    maker.setScriptError(engine);
255                    return false;
256                }
257            }
258            SkASSERT(success);
259            if (scriptValue.fType == SkType_Displayable) {
260                if (type == SkType_String) {
261                    const char* charPtr = nullptr;
262                    maker.findKey(scriptValue.fOperand.fDisplayable, &charPtr);
263                    scriptValue.fOperand.fString = new SkString(charPtr);
264                    scriptValue.fType = SkType_String;
265                    engine.SkScriptEngine::track(scriptValue.fOperand.fString);
266                    break;
267                }
268                SkASSERT(SkDisplayType::IsDisplayable(&maker, type));
269                if (displayable)
270                    displayable->setReference(this, scriptValue.fOperand.fDisplayable);
271                else
272                    arrayStorage->begin()[0].fDisplayable = scriptValue.fOperand.fDisplayable;
273                return true;
274            }
275            if (type != scriptValue.fType) {
276                if (scriptValue.fType == SkType_Array) {
277                    engine.forget(scriptValue.getArray());
278                    goto writeStruct; // real structs have already been written by script
279                }
280                switch (type) {
281                    case SkType_String:
282                        success = engine.convertTo(SkType_String, &scriptValue);
283                        break;
284                    case SkType_MSec:
285                    case SkType_Float:
286                        success = engine.convertTo(SkType_Float, &scriptValue);
287                        break;
288                    case SkType_Int:
289                        success = engine.convertTo(SkType_Int, &scriptValue);
290                        break;
291                    case SkType_Array:
292                        success = engine.convertTo(arrayType(), &scriptValue);
293                        // !!! incomplete; create array of appropriate type and add scriptValue to it
294                        SkASSERT(0);
295                        break;
296                    case SkType_Displayable:
297                    case SkType_Drawable:
298                        return false;   // no way to convert other types to this
299                    default:    // to avoid warnings
300                        break;
301                }
302                if (success == false)
303                    return false;
304            }
305            if (type == SkType_MSec)
306                scriptValue.fOperand.fMSec = SkScalarRoundToInt(scriptValue.fOperand.fScalar * 1000);
307            scriptValue.fType = type;
308        break;
309        noScriptString:
310        case SkType_DynamicString:
311            if (fType == SkType_MemberProperty && displayable) {
312                SkString string(rawValue, rawValueLen);
313                SkScriptValue scriptValue;
314                scriptValue.fOperand.fString = &string;
315                scriptValue.fType = SkType_String;
316                displayable->setProperty(propertyIndex(), scriptValue);
317            } else if (displayable) {
318                SkString* string = (SkString*) memberData(displayable);
319                string->set(rawValue, rawValueLen);
320            } else {
321                SkASSERT(arrayStorage->count() == 1);
322                arrayStorage->begin()->fString->set(rawValue, rawValueLen);
323            }
324            goto dirty;
325        case SkType_Base64: {
326            SkBase64 base64;
327            base64.decode(rawValue, rawValueLen);
328            *(SkBase64* ) untypedStorage = base64;
329            } goto dirty;
330        default:
331            SkASSERT(0);
332            break;
333    }
334//  if (SkDisplayType::IsStruct(type) == false)
335    {
336writeStruct:
337        if (writeValue(displayable, arrayStorage, storageOffset, maxStorage,
338                untypedStorage, outType, scriptValue)) {
339                    maker.setErrorCode(SkDisplayXMLParserError::kUnexpectedType);
340            return false;
341        }
342    }
343dirty:
344    if (displayable)
345        displayable->dirty();
346    return true;
347}
348
349bool SkMemberInfo::setValue(SkAnimateMaker& maker, SkTDOperandArray* arrayStorage,
350        int storageOffset, int maxStorage, SkDisplayable* displayable, SkDisplayTypes outType,
351        SkString& raw) const {
352    return setValue(maker, arrayStorage, storageOffset, maxStorage, displayable, outType, raw.c_str(),
353        raw.size());
354}
355
356bool SkMemberInfo::writeValue(SkDisplayable* displayable, SkTDOperandArray* arrayStorage,
357    int storageOffset, int maxStorage, void* untypedStorage, SkDisplayTypes outType,
358    SkScriptValue& scriptValue) const
359{
360    SkOperand* storage = untypedStorage ? (SkOperand*) untypedStorage : arrayStorage ?
361        arrayStorage->begin() : nullptr;
362    if (storage)
363        storage += storageOffset;
364    SkDisplayTypes type = getType();
365    if (fType == SkType_MemberProperty) {
366        if(displayable)
367            displayable->setProperty(propertyIndex(), scriptValue);
368        else {
369            SkASSERT(storageOffset < arrayStorage->count());
370            switch (scriptValue.fType) {
371                case SkType_Boolean:
372                case SkType_Float:
373                case SkType_Int:
374                    memcpy(&storage->fScalar, &scriptValue.fOperand.fScalar, sizeof(SkScalar));
375                    break;
376                case SkType_Array:
377                    memcpy(&storage->fScalar, scriptValue.fOperand.fArray->begin(), scriptValue.fOperand.fArray->count() * sizeof(SkScalar));
378                    break;
379                case SkType_String:
380                    storage->fString->set(*scriptValue.fOperand.fString);
381                    break;
382                default:
383                    SkASSERT(0);    // type isn't handled yet
384            }
385        }
386    } else if (fType == SkType_MemberFunction) {
387        SkASSERT(scriptValue.fType == SkType_Array);
388        if (displayable)
389            displayable->executeFunction(displayable, this, scriptValue.fOperand.fArray, nullptr);
390        else {
391            int count = scriptValue.fOperand.fArray->count();
392    //      SkASSERT(maxStorage == 0 || count == maxStorage);
393            if (arrayStorage->count() == 2)
394                arrayStorage->setCount(2 * count);
395            else {
396                storageOffset *= count;
397                SkASSERT(count + storageOffset <= arrayStorage->count());
398            }
399            memcpy(&(*arrayStorage)[storageOffset], scriptValue.fOperand.fArray->begin(), count * sizeof(SkOperand));
400        }
401
402    } else if (fType == SkType_Array) {
403        SkTypedArray* destArray = (SkTypedArray*) (untypedStorage ? untypedStorage : arrayStorage);
404        SkASSERT(destArray);
405    //  destArray->setCount(0);
406        if (scriptValue.fType != SkType_Array) {
407            SkASSERT(type == scriptValue.fType);
408    //      SkASSERT(storageOffset + 1 <= maxStorage);
409            destArray->setCount(storageOffset + 1);
410            (*destArray)[storageOffset] = scriptValue.fOperand;
411        } else {
412            if (type == SkType_Unknown) {
413                type = scriptValue.fOperand.fArray->getType();
414                destArray->setType(type);
415            }
416            SkASSERT(type == scriptValue.fOperand.fArray->getType());
417            int count = scriptValue.fOperand.fArray->count();
418    //      SkASSERT(storageOffset + count <= maxStorage);
419            destArray->setCount(storageOffset + count);
420            memcpy(destArray->begin() + storageOffset, scriptValue.fOperand.fArray->begin(), sizeof(SkOperand) * count);
421        }
422    } else if (type == SkType_String) {
423        SkString* string = untypedStorage ? (SkString*) untypedStorage : (*arrayStorage)[storageOffset].fString;
424        string->set(*scriptValue.fOperand.fString);
425    } else if (type == SkType_ARGB && outType == SkType_Float) {
426        SkTypedArray* array = scriptValue.fOperand.fArray;
427        SkASSERT(scriptValue.fType == SkType_Int || scriptValue.fType == SkType_ARGB ||
428            scriptValue.fType == SkType_Array);
429        SkASSERT(scriptValue.fType != SkType_Array || (array != nullptr &&
430            array->getType() == SkType_Int));
431        int numberOfColors = scriptValue.fType == SkType_Array ? array->count() : 1;
432        int numberOfComponents = numberOfColors * 4;
433    //  SkASSERT(maxStorage == 0 || maxStorage == numberOfComponents);
434        if (maxStorage == 0)
435            arrayStorage->setCount(numberOfComponents);
436        for (int index = 0; index < numberOfColors; index++) {
437            SkColor color = scriptValue.fType == SkType_Array ?
438                (SkColor) array->begin()[index].fS32 : (SkColor) scriptValue.fOperand.fS32;
439            storage[0].fScalar = SkIntToScalar(SkColorGetA(color));
440            storage[1].fScalar = SkIntToScalar(SkColorGetR(color));
441            storage[2].fScalar = SkIntToScalar(SkColorGetG(color));
442            storage[3].fScalar = SkIntToScalar(SkColorGetB(color));
443            storage += 4;
444        }
445    } else if (SkDisplayType::IsStruct(nullptr /* !!! maker*/, type)) {
446        if (scriptValue.fType != SkType_Array)
447            return true;    // error
448        SkASSERT(sizeof(SkScalar) == sizeof(SkOperand)); // !!! no 64 bit pointer support yet
449        int count = scriptValue.fOperand.fArray->count();
450        if (count > 0) {
451            SkASSERT(fCount == count);
452            memcpy(storage, scriptValue.fOperand.fArray->begin(), count * sizeof(SkOperand));
453        }
454    } else if (scriptValue.fType == SkType_Array) {
455        SkASSERT(scriptValue.fOperand.fArray->getType() == type);
456        SkASSERT(scriptValue.fOperand.fArray->count() == getCount());
457        memcpy(storage, scriptValue.fOperand.fArray->begin(), getCount() * sizeof(SkOperand));
458    } else {
459        memcpy(storage, &scriptValue.fOperand, sizeof(SkOperand));
460    }
461    return false;
462}
463
464
465//void SkMemberInfo::setValue(SkDisplayable* displayable, const char value[], const char name[]) const {
466//  void* valuePtr = (void*) ((char*) displayable + fOffset);
467//  switch (fType) {
468//      case SkType_Point3D: {
469//          static const char xyz[] = "x|y|z";
470//          int index = find_one(xyz, name);
471//          SkASSERT(index >= 0);
472//          valuePtr = (void*) ((char*) valuePtr + index * sizeof(SkScalar));
473//          } break;
474//      default:
475//          SkASSERT(0);
476//  }
477//  SkParse::FindScalar(value, (SkScalar*) valuePtr);
478//  displayable->dirty();
479//}
480
481#if SK_USE_CONDENSED_INFO == 0
482
483// Find Nth memberInfo
484const SkMemberInfo* SkMemberInfo::Find(const SkMemberInfo info[], int count, int* index) {
485    SkASSERT(*index >= 0);
486    if (info->fType == SkType_BaseClassInfo) {
487        const SkMemberInfo* inherited = (SkMemberInfo*) info->fName;
488        const SkMemberInfo* result = SkMemberInfo::Find(inherited, info->fCount, index);
489        if (result != nullptr)
490            return result;
491        if (--count == 0)
492            return nullptr;
493        info++;
494    }
495    SkASSERT(info->fName);
496    SkASSERT(info->fType != SkType_BaseClassInfo);
497    if (*index >= count) {
498        *index -= count;
499        return nullptr;
500    }
501    return &info[*index];
502}
503
504// Find named memberinfo
505const SkMemberInfo* SkMemberInfo::Find(const SkMemberInfo info[], int count, const char** matchPtr) {
506    const char* match = *matchPtr;
507    if (info->fType == SkType_BaseClassInfo) {
508        const SkMemberInfo* inherited = (SkMemberInfo*) info->fName;
509        const SkMemberInfo* result = SkMemberInfo::Find(inherited, info->fCount, matchPtr);
510        if (result != nullptr)
511            return result;
512        if (--count == 0)
513            return nullptr;
514        info++;
515    }
516    SkASSERT(info->fName);
517    SkASSERT(info->fType != SkType_BaseClassInfo);
518    int index = SkStrSearch(&info->fName, count, match, sizeof(*info));
519    if (index < 0 || index >= count)
520        return nullptr;
521    return &info[index];
522}
523
524const SkMemberInfo* SkMemberInfo::getInherited() const {
525    return (SkMemberInfo*) fName;
526}
527
528#endif // SK_USE_CONDENSED_INFO == 0
529
530#if 0
531bool SkMemberInfo::SetValue(void* valuePtr, const char value[], SkDisplayTypes type,
532                            int count) {
533    switch (type) {
534        case SkType_Animate:
535        case SkType_BaseBitmap:
536        case SkType_Bitmap:
537        case SkType_Dash:
538        case SkType_Displayable:
539        case SkType_Drawable:
540        case SkType_Matrix:
541        case SkType_Path:
542        case SkType_Text:
543        case SkType_3D_Patch:
544            return false; // ref to object; caller must resolve
545        case SkType_MSec: {
546            SkParse::FindMSec(value, (SkMSec*) valuePtr);
547            } break;
548        case SkType_3D_Point:
549        case SkType_Point:
550    //  case SkType_PointArray:
551        case SkType_ScalarArray:
552            SkParse::FindScalars(value, (SkScalar*) valuePtr, count);
553            break;
554        default:
555            SkASSERT(0);
556    }
557    return true;
558}
559#endif
560