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 "SkDisplayEvent.h"
11#include "SkAnimateMaker.h"
12#include "SkDisplayApply.h"
13#include "SkDisplayInput.h"
14#include "SkDisplayList.h"
15#ifdef SK_DEBUG
16#include "SkDump.h"
17#endif
18#include "SkEvent.h"
19#include "SkDisplayInput.h"
20#include "SkKey.h"
21#include "SkMetaData.h"
22#include "SkScript.h"
23#include "SkUtils.h"
24
25enum SkDisplayEvent_Properties {
26    SK_PROPERTY(key),
27    SK_PROPERTY(keys)
28};
29
30#if SK_USE_CONDENSED_INFO == 0
31
32const SkMemberInfo SkDisplayEvent::fInfo[] = {
33    SK_MEMBER(code, EventCode),
34    SK_MEMBER(disable, Boolean),
35    SK_MEMBER_PROPERTY(key, String), // a single key (also last key pressed)
36    SK_MEMBER_PROPERTY(keys, String), // a single key or dash-delimited range of keys
37    SK_MEMBER(kind, EventKind),
38    SK_MEMBER(target, String),
39    SK_MEMBER(x, Float),
40    SK_MEMBER(y, Float)
41};
42
43#endif
44
45DEFINE_GET_MEMBER(SkDisplayEvent);
46
47SkDisplayEvent::SkDisplayEvent() : code((SkKey) -1), disable(false),
48    kind(kUser), x(0), y(0), fLastCode((SkKey) -1), fMax((SkKey) -1), fTarget(nullptr) {
49}
50
51SkDisplayEvent::~SkDisplayEvent() {
52    deleteMembers();
53}
54
55bool SkDisplayEvent::addChild(SkAnimateMaker& , SkDisplayable* child) {
56    *fChildren.append() = child;
57    return true;
58}
59
60bool SkDisplayEvent::contains(SkDisplayable* match) {
61    for (int index = 0; index < fChildren.count(); index++) {
62        if (fChildren[index] == match || fChildren[index]->contains(match))
63            return true;
64    }
65    return false;
66}
67
68SkDisplayable* SkDisplayEvent::contains(const SkString& match) {
69    for (int index = 0; index < fChildren.count(); index++) {
70        SkDisplayable* child = fChildren[index];
71        if (child->contains(match))
72            return child;
73    }
74    return nullptr;
75}
76
77void SkDisplayEvent::deleteMembers() {
78    for (int index = 0; index < fChildren.count(); index++) {
79        SkDisplayable* evt = fChildren[index];
80        delete evt;
81    }
82}
83
84#ifdef SK_DUMP_ENABLED
85void SkDisplayEvent::dumpEvent(SkAnimateMaker* maker) {
86    dumpBase(maker);
87    SkString str;
88    SkDump::GetEnumString(SkType_EventKind, kind, &str);
89    SkDebugf("kind=\"%s\" ", str.c_str());
90    if (kind == SkDisplayEvent::kKeyPress || kind == SkDisplayEvent::kKeyPressUp) {
91        if (code >= 0)
92            SkDump::GetEnumString(SkType_EventCode, code, &str);
93        else
94            str.set("none");
95        SkDebugf("code=\"%s\" ", str.c_str());
96    }
97    if (kind == SkDisplayEvent::kKeyChar) {
98        if (fMax != (SkKey) -1 && fMax != code)
99            SkDebugf("keys=\"%c - %c\" ", code, fMax);
100        else
101            SkDebugf("key=\"%c\" ", code);
102    }
103    if (fTarget != nullptr) {
104        SkDebugf("target=\"%s\" ", fTarget->id);
105    }
106    if (kind >= SkDisplayEvent::kMouseDown && kind <= SkDisplayEvent::kMouseUp) {
107        SkDebugf("x=\"%g\" y=\"%g\" ", SkScalarToFloat(x), SkScalarToFloat(y));
108    }
109    if (disable)
110        SkDebugf("disable=\"true\" ");
111    SkDebugf("/>\n");
112}
113#endif
114
115bool SkDisplayEvent::enableEvent(SkAnimateMaker& maker)
116{
117    maker.fActiveEvent = this;
118    if (fChildren.count() == 0)
119        return false;
120    if (disable)
121        return false;
122#ifdef SK_DUMP_ENABLED
123    if (maker.fDumpEvents) {
124        SkDebugf("enable: ");
125        dumpEvent(&maker);
126    }
127#endif
128    SkDisplayList& displayList = maker.fDisplayList;
129    for (int index = 0; index < fChildren.count(); index++) {
130        SkDisplayable* displayable = fChildren[index];
131        if (displayable->isGroup()) {
132            SkTDDrawableArray* parentList = displayList.getDrawList();
133            *parentList->append() = (SkADrawable*) displayable;  // make it findable before children are enabled
134        }
135        if (displayable->enable(maker))
136            continue;
137        if (maker.hasError())
138            return true;
139        if (displayable->isDrawable() == false)
140            return true;    // error
141        SkADrawable* drawable = (SkADrawable*) displayable;
142        SkTDDrawableArray* parentList = displayList.getDrawList();
143        *parentList->append() = drawable;
144    }
145    return false;
146}
147
148bool SkDisplayEvent::getProperty(int index, SkScriptValue* value) const {
149    switch (index) {
150        case SK_PROPERTY(key):
151        case SK_PROPERTY(keys): {
152            value->fType = SkType_String;
153            char scratch[8];
154            SkKey convert = index == SK_PROPERTY(keys) ? code : fLastCode;
155            size_t size = convert > 0 ? SkUTF8_FromUnichar(convert, scratch) : 0;
156            fKeyString.set(scratch, size);
157            value->fOperand.fString = &fKeyString;
158            if (index != SK_PROPERTY(keys) || fMax == (SkKey) -1 || fMax == code)
159                break;
160            value->fOperand.fString->append("-");
161            size = SkUTF8_FromUnichar(fMax, scratch);
162            value->fOperand.fString->append(scratch, size);
163            } break;
164        default:
165            SkASSERT(0);
166            return false;
167    }
168    return true;
169}
170
171void SkDisplayEvent::onEndElement(SkAnimateMaker& maker)
172{
173    if (kind == kUser)
174        return;
175    maker.fEvents.addEvent(this);
176    if (kind == kOnEnd) {
177        SkDEBUGCODE(bool found = ) maker.find(target.c_str(), &fTarget);
178        SkASSERT(found);
179        SkASSERT(fTarget && fTarget->isAnimate());
180        SkAnimateBase* animate = (SkAnimateBase*) fTarget;
181        animate->setHasEndEvent();
182    }
183}
184
185void SkDisplayEvent::populateInput(SkAnimateMaker& maker, const SkEvent& fEvent) {
186    const SkMetaData& meta = fEvent.getMetaData();
187    SkMetaData::Iter iter(meta);
188    SkMetaData::Type    type;
189    int number;
190    const char* name;
191    while ((name = iter.next(&type, &number)) != nullptr) {
192        if (name[0] == '\0')
193            continue;
194        SkDisplayable* displayable;
195        SkInput* input;
196        for (int index = 0; index < fChildren.count(); index++) {
197            displayable = fChildren[index];
198            if (displayable->getType() != SkType_Input)
199                continue;
200            input = (SkInput*) displayable;
201            if (input->name.equals(name))
202                goto found;
203        }
204        if (!maker.find(name, &displayable) || displayable->getType() != SkType_Input)
205            continue;
206        input = (SkInput*) displayable;
207    found:
208        switch (type) {
209            case SkMetaData::kS32_Type:
210                meta.findS32(name, &input->fInt);
211                break;
212            case SkMetaData::kScalar_Type:
213                meta.findScalar(name, &input->fFloat);
214                break;
215            case SkMetaData::kPtr_Type:
216                SkASSERT(0);
217                break; // !!! not handled for now
218            case SkMetaData::kString_Type:
219                input->string.set(meta.findString(name));
220                break;
221            default:
222                SkASSERT(0);
223        }
224    }
225    // re-evaluate all animators that may have built their values from input strings
226    for (SkDisplayable** childPtr = fChildren.begin(); childPtr < fChildren.end(); childPtr++) {
227        SkDisplayable* displayable = *childPtr;
228        if (displayable->isApply() == false)
229            continue;
230        SkApply* apply = (SkApply*) displayable;
231        apply->refresh(maker);
232    }
233}
234
235bool SkDisplayEvent::setProperty(int index, SkScriptValue& value) {
236    SkASSERT(index == SK_PROPERTY(key) || index == SK_PROPERTY(keys));
237    SkASSERT(value.fType == SkType_String);
238    SkString* string = value.fOperand.fString;
239    const char* chars = string->c_str();
240    int count = SkUTF8_CountUnichars(chars);
241    SkASSERT(count >= 1);
242    code = (SkKey) SkUTF8_NextUnichar(&chars);
243    fMax = code;
244    SkASSERT(count == 1 || index == SK_PROPERTY(keys));
245    if (--count > 0) {
246        SkASSERT(*chars == '-');
247        chars++;
248        fMax = (SkKey) SkUTF8_NextUnichar(&chars);
249        SkASSERT(fMax >= code);
250    }
251    return true;
252}
253