diff options
Diffstat (limited to 'libs/graphics/animator')
163 files changed, 27426 insertions, 0 deletions
diff --git a/libs/graphics/animator/SkAnimate.h b/libs/graphics/animator/SkAnimate.h new file mode 100644 index 0000000000..aa593bfe6c --- /dev/null +++ b/libs/graphics/animator/SkAnimate.h @@ -0,0 +1,26 @@ +#ifndef SkAnimate_DEFINED +#define SkAnimate_DEFINED + +#include "SkAnimateBase.h" +#include "SkDisplayType.h" +#include "SkIntArray.h" +#include "SkUtils.h" + +class SkAnimate : public SkAnimateBase { + DECLARE_MEMBER_INFO(Animate); + SkAnimate(); + virtual ~SkAnimate(); + virtual int components(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual void onEndElement(SkAnimateMaker& maker); +protected: + bool resolveCommon(SkAnimateMaker& ); + int fComponents; +private: + typedef SkAnimateBase INHERITED; +}; + +#endif // SkAnimateField_DEFINED + diff --git a/libs/graphics/animator/SkAnimate3DSchema.xsd b/libs/graphics/animator/SkAnimate3DSchema.xsd new file mode 100644 index 0000000000..5063b75722 --- /dev/null +++ b/libs/graphics/animator/SkAnimate3DSchema.xsd @@ -0,0 +1,39 @@ +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:Sk="http://www.skia.com/schema/SkAnimateSchema.xsd"
+ targetNamespace="urn:skia3D" xmlns:Sk3D="urn:skia3D">
+
+ <xs:simpleType name="Patch" >
+ <xs:restriction base="xs:string" >
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="Point" >
+ <xs:restriction base="xs:string" >
+ <xs:pattern value="[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)( *[ ,] *[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)){2}" />
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:element name="camera">
+ <xs:complexType >
+ <xs:attribute name="axis" type="Sk3D:Point" />
+ <xs:attribute name="hackHeight" type="Sk:Float" />
+ <xs:attribute name="hackWidth" type="Sk:Float" />
+ <xs:attribute name="location" type="Sk3D:Point" />
+ <xs:attribute name="observer" type="Sk3D:Point" />
+ <xs:attribute name="patch" type="Sk3D:Patch" />
+ <xs:attribute name="zenith" type="Sk3D:Point" />
+ <xs:attribute name="id" type="xs:ID" />
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="patch">
+ <xs:complexType >
+ <xs:attribute name="origin" type="Sk3D:Point" />
+ <xs:attribute name="rotateDegrees" type="Sk:MemberFunction" />
+ <xs:attribute name="u" type="Sk3D:Point" />
+ <xs:attribute name="v" type="Sk3D:Point" />
+ <xs:attribute name="id" type="xs:ID" />
+ </xs:complexType>
+ </xs:element>
+
+</xs:schema>
diff --git a/libs/graphics/animator/SkAnimate3DSchema.xsx b/libs/graphics/animator/SkAnimate3DSchema.xsx new file mode 100644 index 0000000000..ceb7d890c9 --- /dev/null +++ b/libs/graphics/animator/SkAnimate3DSchema.xsx @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!--This file is auto-generated by the XML Schema Designer. It holds layout information for components on the designer surface.-->
+<XSDDesignerLayout /> diff --git a/libs/graphics/animator/SkAnimateActive.cpp b/libs/graphics/animator/SkAnimateActive.cpp new file mode 100644 index 0000000000..85f676f3c1 --- /dev/null +++ b/libs/graphics/animator/SkAnimateActive.cpp @@ -0,0 +1,492 @@ +#include "SkAnimateActive.h" +#include "SkAnimateBase.h" +#include "SkAnimateMaker.h" +#include "SkAnimateSet.h" +#include "SkDrawGroup.h" +#ifdef SK_DEBUG +#include "SkTime.h" +#endif + +// SkActive holds array of interpolators + +SkActive::SkActive(SkApply& apply, SkAnimateMaker& maker) : fApply(apply), + fMaxTime(0), fMaker(maker), fDrawIndex(0), fDrawMax(0) { +} + +void SkActive::init() +{ + fAnimators = fApply.fAnimators; + int animators = fAnimators.count(); + fInterpolators.setCount(animators); + memset(fInterpolators.begin(), 0, animators * sizeof(SkOperandInterpolator*)); + fState.setCount(animators); + int index; + for (index = 0; index < animators; index++) + fInterpolators[index] = SkNEW(SkOperandInterpolator); + initState(&fApply, 0); +// for (index = 0; index < animators; index++) +// fState[index].bumpSave(); + SkASSERT(fInterpolators.count() == fAnimators.count()); +} + +SkActive::~SkActive() { + int index; + for (index = 0; index < fSaveRestore.count(); index++) + delete[] fSaveRestore[index]; + for (index = 0; index < fSaveInterpolators.count(); index++) + delete[] fSaveInterpolators[index]; + for (index = 0; index < fInterpolators.count(); index++) + delete fInterpolators[index]; +} + +void SkActive::advance() { + if (fDrawMax < fDrawIndex) + fDrawMax = fDrawIndex; + fDrawIndex += fAnimators.count(); +} + +void SkActive::append(SkApply* apply) { + int oldCount = fAnimators.count(); + SkTDAnimateArray& animates = apply->fAnimators; + int newCount = animates.count(); + int index; + int total = oldCount + newCount; + if (total == 0) + return; + fInterpolators.setCount(total); + memset(&fInterpolators.begin()[oldCount], 0, newCount * sizeof(SkOperandInterpolator*)); + for (index = oldCount; index < total; index++) + fInterpolators[index] = SkNEW(SkOperandInterpolator); + fAnimators.setCount(total); + memcpy(&fAnimators[oldCount], animates.begin(), sizeof(fAnimators[0]) * + newCount); + fState.setCount(total); + initState(apply, oldCount); + SkASSERT(fApply.scope == apply->scope); + for (index = 0; index < newCount; index++) { + SkAnimateBase* test = animates[index]; +// SkASSERT(fApply.scope == test->fTarget || fApply.scope->contains(test->fTarget)); + SkActive::SkState& testState = fState[oldCount + index]; + for (int inner = 0; inner < oldCount; inner++) { + SkAnimateBase* oldGuard = fAnimators[inner]; + SkActive::SkState& oldState = fState[inner]; + if (oldGuard->fTarget == test->fTarget && oldGuard->fFieldInfo == test->fFieldInfo && + testState.fBegin == oldState.fBegin) { + delete fInterpolators[inner]; + fInterpolators.remove(inner); + fAnimators.remove(inner); + testState.fSave = oldState.fSave; + if (oldState.fUnpostedEndEvent) { +// SkDEBUGF(("%8x %8x active append: post on end\n", this, oldGuard)); + fMaker.postOnEnd(oldGuard, oldState.fBegin + oldState.fDuration); + } + fState.remove(inner); + if (fApply.restore) { + int saveIndex = fSaveRestore.count(); + SkASSERT(fSaveInterpolators.count() == saveIndex); + saveIndex += inner; + do { + saveIndex -= oldCount; + delete[] fSaveRestore[saveIndex]; + fSaveRestore.remove(saveIndex); + delete[] fSaveInterpolators[saveIndex]; + fSaveInterpolators.remove(saveIndex); + } while (saveIndex > 0); + } + oldCount--; + break; + } + } + } +// total = oldCount + newCount; +// for (index = oldCount; index < total; index++) +// fState[index].bumpSave(); + SkASSERT(fInterpolators.count() == fAnimators.count()); +} + +void SkActive::appendSave(int oldCount) { + SkASSERT(fDrawMax == 0); // if true, we can optimize below quite a bit + int newCount = fAnimators.count(); + int saveIndex = fSaveRestore.count(); + SkASSERT(fSaveInterpolators.count() == saveIndex); + int records = saveIndex / oldCount; + int newTotal = records * newCount; + fSaveRestore.setCount(newTotal); + do { + saveIndex -= oldCount; + newTotal -= newCount; + SkASSERT(saveIndex >= 0); + SkASSERT(newTotal >= 0); + memmove(&fSaveRestore[newTotal], &fSaveRestore[saveIndex], oldCount); + memset(&fSaveRestore[newTotal + oldCount], 0, + sizeof(fSaveRestore[0]) * (newCount - oldCount)); + memmove(&fSaveInterpolators[newTotal], + &fSaveInterpolators[saveIndex], oldCount); + memset(&fSaveInterpolators[newTotal + oldCount], 0, + sizeof(fSaveRestore[0]) * (newCount - oldCount)); + } while (saveIndex > 0); + SkASSERT(newTotal == 0); +} + +void SkActive::calcDurations(int index) +{ + SkAnimateBase* animate = fAnimators[index]; + SkMSec duration = animate->dur; + SkState& state = fState[index]; + if (state.fMode == SkApply::kMode_immediate || state.fMode == SkApply::kMode_create) + duration = state.fSteps ? state.fSteps * SK_MSec1 : 1; +// else if (state.fMode == SkApply::kMode_hold) { +// int entries = animate->entries(); +// SkScriptValue value; +// value.fOperand = animate->getValues()[entries - 1]; +// value.fType = animate->getValuesType(); +// bool result = SkScriptEngine::ConvertTo(nil, SkType_Int, &value); +// SkASSERT(result); +// duration = value.fOperand.fS32 * SK_MSec1; +// } + state.fDuration = duration; + SkMSec maxTime = state.fBegin + duration; + if (fMaxTime < maxTime) + fMaxTime = maxTime; +} + +void SkActive::create(SkDrawable* drawable, SkMSec time) { + fApply.fLastTime = time; + fApply.refresh(fMaker); + for (int index = 0; index < fAnimators.count(); index++) { + SkAnimateBase* animate = fAnimators[index]; + SkOperandInterpolator& interpolator = *fInterpolators[index]; + int count = animate->components(); + if (animate->formula.size() > 0) { + SkTDOperandArray values; + values.setCount(count); + bool success = animate->fFieldInfo->setValue(fMaker, &values, 0, 0, nil, + animate->getValuesType(), animate->formula); + SkASSERT(success); + fApply.applyValues(index, values.begin(), count, animate->getValuesType(), time); + } else { + SkAutoSTMalloc<16, SkOperand> values(count); + interpolator.timeToValues(time, values.get()); + fApply.applyValues(index, values.get(), count, animate->getValuesType(), time); + } + } + drawable->enable(fMaker); + SkASSERT(fAnimators.count() == fInterpolators.count()); +} + +bool SkActive::immediate(bool enable) { + SkMSec time = 0; + bool result = false; + SkDrawable* drawable = fApply.scope; + SkMSec final = fMaxTime; + do { + bool applied = fAnimators.count() == 0; + fApply.fLastTime = time; + fApply.refresh(fMaker); + for (int index = 0; index < fAnimators.count(); index++) { + SkAnimateBase* animate = fAnimators[index]; + SkState& state = fState[index]; + if (state.fMode != SkApply::kMode_immediate) + continue; + if (state.fBegin > time) + continue; + if (time > state.fBegin + state.fDuration) + continue; + applied = true; + SkOperandInterpolator& interpolator = *fInterpolators[index]; + int count = animate->components(); + if (animate->formula.size() > 0) { + SkTDOperandArray values; + values.setCount(count); + bool success = animate->fFieldInfo->setValue(fMaker, &values, 0, 0, nil, + animate->getValuesType(), animate->formula); + SkASSERT(success); + fApply.applyValues(index, values.begin(), count, animate->getValuesType(), time); + } else { + SkAutoSTMalloc<16, SkOperand> values(count); + interpolator.timeToValues(time, values.get()); + fApply.applyValues(index, values.get(), count, animate->getValuesType(), time); + } + } + if (enable) + drawable->enable(fMaker); + else if (applied) + result |= drawable->draw(fMaker); + time += SK_MSec1; + } while (time <= final); + return result; +} + +void SkActive::fixInterpolator(SkBool save) { + int animators = fAnimators.count(); + for (int index = 0; index < animators; index++) { + SkAnimateBase* animate = fAnimators[index]; + if (save) { // saved slots increased + animate->refresh(fMaker); + SkOperand* values = animate->getValues(); + setInterpolator(index, values); + saveInterpolatorValues(index); + } else + restoreInterpolatorValues(index); + } +} + +SkMSec SkActive::getTime(SkMSec inTime, int animatorIndex) { + fState[animatorIndex].fTicks = inTime; + return inTime - fState[animatorIndex].fStartTime; +} + +bool SkActive::initializeSave() { + int animators = fAnimators.count(); + int activeTotal = fDrawIndex + animators; + int oldCount = fSaveRestore.count(); + if (oldCount < activeTotal) { + fSaveRestore.setCount(activeTotal); + memset(&fSaveRestore[oldCount], 0, sizeof(fSaveRestore[0]) * (activeTotal - oldCount)); + SkASSERT(fSaveInterpolators.count() == oldCount); + fSaveInterpolators.setCount(activeTotal); + memset(&fSaveInterpolators[oldCount], 0, + sizeof(fSaveInterpolators[0]) * (activeTotal - oldCount)); + return true; + } + return false; +} + +void SkActive::initState(SkApply* apply, int offset) { + int count = fState.count(); + for (int index = offset; index < count; index++) { + SkState& state = fState[index]; + SkAnimateBase* animate = fAnimators[index]; +#if 0 // def SK_DEBUG + if (animate->fHasEndEvent) + SkDebugf("%8x %8x active initState:\n", this, animate); +#endif + SkOperand* from = animate->getValues(); + state.fStartTime = state.fBegin = apply->begin + animate->begin; + state.fMode = apply->mode; + state.fTransition = apply->transition; +#if 0 + state.fPickup = (SkBool8) apply->pickup; +#endif + state.fRestore = (SkBool8) apply->restore; + state.fSave = apply->begin; + state.fStarted = false; + state.fSteps = apply->steps; + state.fTicks = 0; + state.fUnpostedEndEvent = (SkBool8) animate->fHasEndEvent; + calcDurations(index); + setInterpolator(index, from); + } + if (count == 0 && (apply->mode == SkApply::kMode_immediate || apply->mode == SkApply::kMode_create)) + fMaxTime = apply->begin + apply->steps * SK_MSec1; +} + +void SkActive::pickUp(SkActive* existing) { + SkTDOperandArray existingValues; + for (int index = 0; index < fAnimators.count(); index++) { + SkAnimateBase* animate = fAnimators[index]; + SkASSERT(animate->getValuesType() == SkType_Float); + int components = animate->components(); + SkOperand* from = animate->getValues(); + SkOperand* to = &from[animate->components()]; + existingValues.setCount(components); + existing->fInterpolators[index]->timeToValues( + existing->fState[index].fTicks - existing->fState[index].fStartTime, existingValues.begin()); + SkScalar originalSum = 0; + SkScalar workingSum = 0; + for (int cIndex = 0; cIndex < components; cIndex++) { + SkScalar delta = to[cIndex].fScalar - from[cIndex].fScalar; + originalSum += SkScalarMul(delta, delta); + delta = to[cIndex].fScalar - existingValues[cIndex].fScalar; + workingSum += SkScalarMul(delta, delta); + } + if (workingSum < originalSum) { + SkScalar originalDistance = SkScalarSqrt(originalSum); + SkScalar workingDistance = SkScalarSqrt(workingSum); + existing->fState[index].fDuration = (SkMSec) SkScalarMulDiv(fState[index].fDuration, + workingDistance, originalDistance); + } + fInterpolators[index]->reset(components, 2, SkType_Float); + fInterpolators[index]->setKeyFrame(0, 0, existingValues.begin(), animate->blend[0]); + fInterpolators[index]->setKeyFrame(1, fState[index].fDuration, to, animate->blend[0]); + } +} + +void SkActive::resetInterpolators() { + int animators = fAnimators.count(); + for (int index = 0; index < animators; index++) { + SkAnimateBase* animate = fAnimators[index]; + SkOperand* values = animate->getValues(); + setInterpolator(index, values); + } +} + +void SkActive::resetState() { + fDrawIndex = 0; + int count = fState.count(); + for (int index = 0; index < count; index++) { + SkState& state = fState[index]; + SkAnimateBase* animate = fAnimators[index]; +#if 0 // def SK_DEBUG + if (animate->fHasEndEvent) + SkDebugf("%8x %8x active resetState: has end event\n", this, animate); +#endif + state.fStartTime = state.fBegin = fApply.begin + animate->begin; + state.fStarted = false; + state.fTicks = 0; + } +} + +void SkActive::restoreInterpolatorValues(int index) { + SkOperandInterpolator& interpolator = *fInterpolators[index]; + index += fDrawIndex ; + int count = interpolator.getValuesCount(); + memcpy(interpolator.getValues(), fSaveInterpolators[index], count * sizeof(SkOperand)); +} + +void SkActive::saveInterpolatorValues(int index) { + SkOperandInterpolator& interpolator = *fInterpolators[index]; + index += fDrawIndex ; + int count = interpolator.getValuesCount(); + SkOperand* cache = new SkOperand[count]; // this should use sk_malloc/sk_free since SkOperand does not have a constructor/destructor + fSaveInterpolators[index] = cache; + memcpy(cache, interpolator.getValues(), count * sizeof(SkOperand)); +} + +void SkActive::setInterpolator(int index, SkOperand* from) { + if (from == nil) // legitimate for set string + return; + SkAnimateBase* animate = fAnimators[index]; + int entries = animate->entries(); + SkASSERT(entries > 0); + SkMSec duration = fState[index].fDuration; + int components = animate->components(); + SkOperandInterpolator& interpolator = *fInterpolators[index]; + interpolator.reset(components, entries == 1 ? 2 : entries, animate->getValuesType()); + interpolator.setMirror(SkToBool(animate->fMirror)); + interpolator.setReset(SkToBool(animate->fReset)); + interpolator.setRepeatCount(animate->repeat); + if (entries == 1) { + interpolator.setKeyFrame(0, 0, from, animate->blend[0]); + interpolator.setKeyFrame(1, duration, from, animate->blend[0]); + return; + } + for (int entry = 0; entry < entries; entry++) { + int blendIndex = SkMin32(animate->blend.count() - 1, entry); + interpolator.setKeyFrame(entry, entry * duration / (entries - 1), from, + animate->blend[blendIndex]); + from += components; + } +} + +void SkActive::setSteps(int steps) { + int count = fState.count(); + fMaxTime = 0; + for (int index = 0; index < count; index++) { + SkState& state = fState[index]; + state.fSteps = steps; + calcDurations(index); + } +} + +void SkActive::start() { + int count = fState.count(); + SkASSERT(count == fAnimators.count()); + SkASSERT(count == fInterpolators.count()); + for (int index = 0; index < count; index++) { + SkState& state = fState[index]; + if (state.fStarted) + continue; + state.fStarted = true; +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + SkString debugOut; + SkMSec time = fMaker.getAppTime(); + debugOut.appendS32(time - fMaker.fDebugTimeBase); + debugOut.append(" active start adjust delay id="); + debugOut.append(fApply._id); + debugOut.append("; "); + debugOut.append(fAnimators[index]->_id); + debugOut.append("="); + debugOut.appendS32(fAnimators[index]->fStart - fMaker.fDebugTimeBase); + debugOut.append(":"); + debugOut.appendS32(state.fStartTime); +#endif + if (state.fStartTime > 0) { + SkMSec future = fAnimators[index]->fStart + state.fStartTime; + if (future > fMaker.fEnableTime) + fMaker.notifyInvalTime(future); + else + fMaker.notifyInval(); +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + debugOut.append(":"); + debugOut.appendS32(future - fMaker.fDebugTimeBase); +#endif + } + if (state.fStartTime >= fMaker.fAdjustedStart) { + state.fStartTime -= fMaker.fAdjustedStart; +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + debugOut.append(" (less adjust = "); + debugOut.appendS32(fMaker.fAdjustedStart); +#endif + } + state.fStartTime += fAnimators[index]->fStart; +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + debugOut.append(") new start = "); + debugOut.appendS32(state.fStartTime - fMaker.fDebugTimeBase); + SkDebugf("%s\n", debugOut.c_str()); +// SkASSERT((int) (state.fStartTime - fMaker.fDebugTimeBase) >= 0); +#endif + } + SkASSERT(fAnimators.count() == fInterpolators.count()); +} + +#ifdef SK_DEBUG +void SkActive::validate() { + int count = fState.count(); + SkASSERT(count == fAnimators.count()); + SkASSERT(count == fInterpolators.count()); + for (int index = 0; index < count; index++) { + SkASSERT(fAnimators[index]); + SkASSERT(fInterpolators[index]); +// SkAnimateBase* test = fAnimators[index]; +// SkASSERT(fApply.scope == test->fTarget || fApply.scope->contains(test->fTarget)); + } +} +#endif + +// think about this +// there should only be one animate object, not two, to go up and down +// when the apply with reverse came into play, it needs to pick up the value +// of the existing animate object then remove it from the list +// the code below should only be bumping fSave, and there shouldn't be anything +// it needs to be synchronized with + +// however, if there are two animates both operating on the same field, then +// when one replaces the other, it may make sense to pick up the old value as a starting +// value for the new one somehow. + +//void SkActive::SkState::bumpSave() { +// if (fMode != SkApply::kMode_hold) +// return; +// if (fTransition == SkApply::kTransition_reverse) { +// if (fSave > 0) +// fSave -= SK_MSec1; +// } else if (fSave < fDuration) +// fSave += SK_MSec1; +//} + +SkMSec SkActive::SkState::getRelativeTime(SkMSec time) { + SkMSec result = time; +// if (fMode == SkApply::kMode_hold) +// result = fSave; +// else + if (fTransition == SkApply::kTransition_reverse) { + if (SkMSec_LT(fDuration, time)) + result = 0; + else + result = fDuration - time; + } + return result; +} + + diff --git a/libs/graphics/animator/SkAnimateActive.h b/libs/graphics/animator/SkAnimateActive.h new file mode 100644 index 0000000000..3bdf9330df --- /dev/null +++ b/libs/graphics/animator/SkAnimateActive.h @@ -0,0 +1,70 @@ +#ifndef SkAnimateActive_DEFINED +#define SkAnimateActive_DEFINED + +#include "SkDisplayApply.h" +#include "SkOperandInterpolator.h" +#include "SkIntArray.h" + +class SkAnimateMaker; + +class SkActive { +public: + SkActive(SkApply& , SkAnimateMaker& ); + ~SkActive(); + void advance(); + void append(SkApply* ); + void calcDurations(int index); + void create(SkDrawable* scope, SkMSec time); + bool draw() { return immediate(false); } + bool enable() { return immediate(true); } + void init( ); + SkMSec getTime(SkMSec inTime, int animatorIndex); + void pickUp(SkActive* existing); + void reset() { fDrawIndex = 0; } + void setInterpolator(int index, SkOperand* from); + void start(); +#ifdef SK_DEBUG + void validate(); +#endif +private: + void appendSave(int oldCount); + void fixInterpolator(SkBool save); + bool immediate(bool enable); + bool initializeSave(); + void initState(SkApply* , int offset); + void resetInterpolators(); + void resetState(); + void restoreInterpolatorValues(int index); + void saveInterpolatorValues(int index); + void setSteps(int steps); + struct SkState { +// void bumpSave(); + SkMSec getRelativeTime(SkMSec time); + SkApply::Mode fMode; + SkApply::Transition fTransition; + SkBool8 fPickup; + SkBool8 fRestore; + SkBool8 fStarted; + SkBool8 fUnpostedEndEvent; + S32 fSteps; + SkMSec fBegin; + SkMSec fStartTime; + SkMSec fDuration; + SkMSec fSave; + SkMSec fTicks; + }; + SkActive& operator= (const SkActive& ); + SkTDArray<SkOperandInterpolator*> fInterpolators; + SkApply& fApply; + SkTDArray<SkState> fState; // one per animator + SkTDOperandPtrArray fSaveRestore; // if apply has restore="true" + SkTDOperandPtrArray fSaveInterpolators; + SkTDAnimateArray fAnimators; + SkMSec fMaxTime; // greatest of all animation durations; only used by immediate mode + SkAnimateMaker& fMaker; + int fDrawIndex; + int fDrawMax; + friend class SkApply; +}; + +#endif // SkAnimateActive_DEFINED diff --git a/libs/graphics/animator/SkAnimateBase.cpp b/libs/graphics/animator/SkAnimateBase.cpp new file mode 100644 index 0000000000..fd3bd67a4a --- /dev/null +++ b/libs/graphics/animator/SkAnimateBase.cpp @@ -0,0 +1,230 @@ +#include "SkAnimateBase.h" +#include "SkAnimateMaker.h" +#include "SkAnimateProperties.h" +#include "SkAnimatorScript.h" +#include "SkDisplayApply.h" +#include "SkDrawable.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkAnimateBase::fInfo[] = { + SK_MEMBER(begin, MSec), + SK_MEMBER_ARRAY(blend, Float), + SK_MEMBER(dur, MSec), + SK_MEMBER_PROPERTY(dynamic, Boolean), + SK_MEMBER(field, String), // name of member info in target + SK_MEMBER(formula, DynamicString), + SK_MEMBER(from, DynamicString), + SK_MEMBER(lval, DynamicString), + SK_MEMBER_PROPERTY(mirror, Boolean), + SK_MEMBER(repeat, Float), + SK_MEMBER_PROPERTY(reset, Boolean), + SK_MEMBER_PROPERTY(step, Int), + SK_MEMBER(target, DynamicString), + SK_MEMBER(to, DynamicString), + SK_MEMBER_PROPERTY(values, DynamicString) +}; + +#endif + +DEFINE_GET_MEMBER(SkAnimateBase); + +SkAnimateBase::SkAnimateBase() : begin(0), dur(1), repeat(SK_Scalar1), + fApply(nil), fFieldInfo(nil), fFieldOffset(0), fStart((SkMSec) -1), fTarget(nil), + fChanged(0), fDelayed(0), fDynamic(0), fHasEndEvent(0), fHasValues(0), + fMirror(0), fReset(0), fResetPending(0), fTargetIsScope(0) { + blend.setCount(1); + blend[0] = SK_Scalar1; +} + +SkAnimateBase::~SkAnimateBase() { + SkDisplayTypes type = fValues.getType(); + if (type == SkType_String || type == SkType_DynamicString) { + SkASSERT(fValues.count() == 1); + delete fValues[0].fString; + } +} + +int SkAnimateBase::components() { + return 1; +} + +SkDisplayable* SkAnimateBase::deepCopy(SkAnimateMaker* maker) { + SkAnimateBase* result = (SkAnimateBase*) INHERITED::deepCopy(maker); + result->fApply = fApply; + result->fFieldInfo =fFieldInfo; + result->fHasValues = false; + return result; +} + +void SkAnimateBase::dirty() { + fChanged = true; +} + +#ifdef SK_DUMP_ENABLED +void SkAnimateBase::dump(SkAnimateMaker* maker) { + dumpBase(maker); + if (target.size() > 0) + SkDebugf("target=\"%s\" ", target.c_str()); + else if (fTarget && strcmp(fTarget->id, "")) + SkDebugf("target=\"%s\" ", fTarget->id); + if (lval.size() > 0) + SkDebugf("lval=\"%s\" ", lval.c_str()); + if (field.size() > 0) + SkDebugf("field=\"%s\" ", field.c_str()); + else if (fFieldInfo) + SkDebugf("field=\"%s\" ", fFieldInfo->fName); + if (formula.size() > 0) + SkDebugf("formula=\"%s\" ", formula.c_str()); + else { + if (from.size() > 0) + SkDebugf("from=\"%s\" ", from.c_str()); + SkDebugf("to=\"%s\" ", to.c_str()); + } + if (begin != 0) { +#ifdef SK_CAN_USE_FLOAT + SkDebugf("begin=\"%g\" ", SkScalarToFloat(SkScalarDiv(begin,1000))); +#else + SkDebugf("begin=\"%x\" ", SkScalarDiv(begin,1000)); +#endif + } +} +#endif + +SkDisplayable* SkAnimateBase::getParent() const { + return (SkDisplayable*) fApply; +} + +bool SkAnimateBase::getProperty(int index, SkScriptValue* value) const { + int boolResult; + switch (index) { + case SK_PROPERTY(dynamic): + boolResult = fDynamic; + goto returnBool; + case SK_PROPERTY(mirror): + boolResult = fMirror; + goto returnBool; + case SK_PROPERTY(reset): + boolResult = fReset; +returnBool: + value->fOperand.fS32 = SkToBool(boolResult); + value->fType = SkType_Boolean; + break; + case SK_PROPERTY(step): + if (fApply == nil) + return false; // !!! notify there's an error? + fApply->getStep(value); + break; + case SK_PROPERTY(values): + value->fOperand.fString = (SkString*) &to; + value->fType = SkType_String; + break; + default: + SkASSERT(0); + return false; + } + return true; +} + +bool SkAnimateBase::hasExecute() const +{ + return false; +} + +void SkAnimateBase::onEndElement(SkAnimateMaker& maker) { + fChanged = false; + setTarget(maker); + if (field.size()) { + SkASSERT(fTarget); + fFieldInfo = fTarget->getMember(field.c_str()); + field.reset(); + } + if (lval.size()) { + // lval must be of the form x[y] + const char* lvalStr = lval.c_str(); + const char* arrayEnd = strchr(lvalStr, '['); + if (arrayEnd == nil) + return; //should this return an error? + size_t arrayNameLen = arrayEnd - lvalStr; + SkString arrayStr(lvalStr, arrayNameLen); + SkASSERT(fTarget); //this return an error? + fFieldInfo = fTarget->getMember(arrayStr.c_str()); + SkString scriptStr(arrayEnd + 1, lval.size() - arrayNameLen - 2); + SkAnimatorScript::EvaluateInt(maker, this, scriptStr.c_str(), &fFieldOffset); + } +} + +void SkAnimateBase::packARGB(SkScalar array[], int count, SkTDOperandArray* converted) +{ + SkASSERT(count == 4); + converted->setCount(1); + SkColor color = SkColorSetARGB(SkScalarRound(array[0]), SkScalarRound(array[1]), + SkScalarRound(array[2]), SkScalarRound(array[3])); + (*converted)[0].fS32 = color; +} + + + +void SkAnimateBase::refresh(SkAnimateMaker& ) { +} + +bool SkAnimateBase::setParent(SkDisplayable* apply) { + SkASSERT(apply->isApply()); + fApply = (SkApply*) apply; + return false; +} + +bool SkAnimateBase::setProperty(int index, SkScriptValue& value) { + bool boolValue = SkToBool(value.fOperand.fS32); + switch (index) { + case SK_PROPERTY(dynamic): + fDynamic = boolValue; + goto checkForBool; + case SK_PROPERTY(values): + fHasValues = true; + SkASSERT(value.fType == SkType_String); + to = *value.fOperand.fString; + break; + case SK_PROPERTY(mirror): + fMirror = boolValue; + goto checkForBool; + case SK_PROPERTY(reset): + fReset = boolValue; +checkForBool: + SkASSERT(value.fType == SkType_Boolean); + break; + default: + return false; + } + return true; +} + +void SkAnimateBase::setTarget(SkAnimateMaker& maker) { + if (target.size()) { + SkAnimatorScript engine(maker, this, SkType_Displayable); + const char* script = target.c_str(); + SkScriptValue scriptValue; + bool success = engine.evaluateScript(&script, &scriptValue); + if (success && scriptValue.fType == SkType_Displayable) + fTarget = scriptValue.fOperand.fDrawable; + else if (maker.find(target.c_str(), (SkDisplayable**) &fTarget) == false) { + if (fApply->getMode() == SkApply::kMode_create) + return; // may not be an error + if (engine.getError() != SkScriptEngine::kNoError) + maker.setScriptError(engine); + else { + maker.setErrorNoun(target); + maker.setErrorCode(SkDisplayXMLParserError::kTargetIDNotFound); + } + return; + } + if (fApply && fApply->getMode() != SkApply::kMode_create) + target.reset(); + } +} + +bool SkAnimateBase::targetNeedsInitialization() const { + return false; +} + + diff --git a/libs/graphics/animator/SkAnimateBase.h b/libs/graphics/animator/SkAnimateBase.h new file mode 100644 index 0000000000..510b59362c --- /dev/null +++ b/libs/graphics/animator/SkAnimateBase.h @@ -0,0 +1,74 @@ +#ifndef SkAnimateBase_DEFINED +#define SkAnimateBase_DEFINED + +#include "SkDisplayable.h" +#include "SkMath.h" +#include "SkMemberInfo.h" +#include "SkTypedArray.h" + +class SkApply; +class SkDrawable; + +class SkAnimateBase : public SkDisplayable { +public: + DECLARE_MEMBER_INFO(AnimateBase); + SkAnimateBase(); + virtual ~SkAnimateBase(); + virtual int components(); + virtual SkDisplayable* deepCopy(SkAnimateMaker* ); + virtual void dirty(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + int entries() { return fValues.count() / components(); } + virtual bool hasExecute() const; + bool isDynamic() const { return SkToBool(fDynamic); } + virtual SkDisplayable* getParent() const; + virtual bool getProperty(int index, SkScriptValue* value) const; + SkMSec getStart() const { return fStart; } + SkOperand* getValues() { return fValues.begin(); } + SkDisplayTypes getValuesType() { return fValues.getType(); } + virtual void onEndElement(SkAnimateMaker& ); + void packARGB(SkScalar [], int count, SkTDOperandArray* ); + virtual void refresh(SkAnimateMaker& ); + void setChanged(bool changed) { fChanged = changed; } + void setHasEndEvent() { fHasEndEvent = true; } + virtual bool setParent(SkDisplayable* ); + virtual bool setProperty(int index, SkScriptValue& value); + void setTarget(SkAnimateMaker& ); + virtual bool targetNeedsInitialization() const; +protected: + SkMSec begin; + SkTDScalarArray blend; + SkMSec dur; + // !!! make field part of a union with fFieldInfo, or fValues, something known later? + SkString field; // temporary; once target is known, this is reset + SkString formula; + SkString from; + SkString lval; + SkScalar repeat; + SkString target; // temporary; once target is known, this is reset + SkString to; + SkApply* fApply; + const SkMemberInfo* fFieldInfo; + int fFieldOffset; + SkMSec fStart; // corrected time when this apply was enabled + SkDrawable* fTarget; + SkTypedArray fValues; + unsigned fChanged : 1; // true when value referenced by script has changed + unsigned fDelayed : 1; // enabled, but undrawn pending delay + unsigned fDynamic : 1; + unsigned fHasEndEvent : 1; + unsigned fHasValues : 1; // set if 'values' passed instead of 'to' + unsigned fMirror : 1; + unsigned fReset : 1; + unsigned fResetPending : 1; + unsigned fTargetIsScope : 1; +private: + typedef SkDisplayable INHERITED; + friend class SkActive; + friend class SkApply; + friend class SkDisplayList; +}; + +#endif // SkAnimateBase_DEFINED diff --git a/libs/graphics/animator/SkAnimateField.cpp b/libs/graphics/animator/SkAnimateField.cpp new file mode 100644 index 0000000000..b2b63555c2 --- /dev/null +++ b/libs/graphics/animator/SkAnimateField.cpp @@ -0,0 +1,113 @@ +#include "SkAnimate.h" +#include "SkAnimateMaker.h" +#include "SkDrawable.h" +#include "SkParse.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkAnimate::fInfo[] = { + SK_MEMBER_INHERITED +}; + +#endif + +DEFINE_GET_MEMBER(SkAnimate); + +SkAnimate::SkAnimate() : fComponents(0) { +} + +SkAnimate::~SkAnimate() { +} + +int SkAnimate::components() { + return fComponents; +} + +#ifdef SK_DUMP_ENABLED +void SkAnimate::dump(SkAnimateMaker* maker) { + INHERITED::dump(maker); //from animateBase + //SkSet inherits from this class + if (getType() != SkType_Set) { + if (fMirror) + SkDebugf("mirror=\"true\" "); + if (fReset) + SkDebugf("reset=\"true\" "); +#ifdef SK_CAN_USE_FLOAT + SkDebugf("dur=\"%g\" ", SkScalarToFloat(SkScalarDiv(dur,1000))); + if (repeat != SK_Scalar1) + SkDebugf("repeat=\"%g\" ", SkScalarToFloat(repeat)); +#else + SkDebugf("dur=\"%x\" ", SkScalarDiv(dur,1000)); + if (repeat != SK_Scalar1) + SkDebugf("repeat=\"%x\" ", repeat); +#endif + //if (fHasValues) + // SkDebugf("values=\"%s\" ", values); + if (blend.count() != 1 || blend[0] != SK_Scalar1) { + SkDebugf("blend=\"["); + bool firstElem = true; + for (int i = 0; i < blend.count(); i++) { + if (!firstElem) + SkDebugf(","); + firstElem = false; +#ifdef SK_CAN_USE_FLOAT + SkDebugf("%g", SkScalarToFloat(blend[i])); +#else + SkDebugf("%x", blend[i]); +#endif + } + SkDebugf("]\" "); + } + SkDebugf("/>\n");//i assume that if it IS, we will do it separately + } +} +#endif + +bool SkAnimate::resolveCommon(SkAnimateMaker& maker) { + if (fTarget == nil) // if nil, recall onEndElement after apply closes and sets target to scope + return false; + INHERITED::onEndElement(maker); + return maker.hasError() == false; +} + +void SkAnimate::onEndElement(SkAnimateMaker& maker) { + bool resolved = resolveCommon(maker); + if (resolved && fFieldInfo == nil) { + maker.setErrorNoun(field); + maker.setErrorCode(SkDisplayXMLParserError::kFieldNotInTarget); + } + if (resolved == false || fFieldInfo == nil) + return; + SkDisplayTypes outType = fFieldInfo->getType(); + if (fHasValues) { + SkASSERT(to.size() > 0); + fFieldInfo->setValue(maker, &fValues, 0, 0, nil, outType, to); + SkASSERT(0); + // !!! this needs to set fComponents + return; + } + fComponents = fFieldInfo->getCount(); + if (fFieldInfo->fType == SkType_Array) { + SkTypedArray* array = (SkTypedArray*) fFieldInfo->memberData(fTarget); + int count = array->count(); + if (count > 0) + fComponents = count; + } + if (outType == SkType_ARGB) { + fComponents <<= 2; // four color components + outType = SkType_Float; + } + fValues.setType(outType); + if (formula.size() > 0){ + fComponents = 1; + from.set("0"); + to.set("dur"); + outType = SkType_MSec; + } + int max = fComponents * 2; + fValues.setCount(max); + memset(fValues.begin(), 0, max * sizeof(fValues.begin()[0])); + fFieldInfo->setValue(maker, &fValues, fFieldOffset, max, this, outType, from); + fFieldInfo->setValue(maker, &fValues, fComponents + fFieldOffset, max, this, outType, to); +} + diff --git a/libs/graphics/animator/SkAnimateMaker.cpp b/libs/graphics/animator/SkAnimateMaker.cpp new file mode 100644 index 0000000000..e66f7df470 --- /dev/null +++ b/libs/graphics/animator/SkAnimateMaker.cpp @@ -0,0 +1,356 @@ +#include "SkAnimateMaker.h" +#include "SkAnimator.h" +#include "SkAnimatorScript.h" +#include "SkDisplayable.h" +#include "SkDisplayApply.h" +#include "SkDisplayList.h" +#include "SkDisplayMovie.h" +#include "SkDisplayType.h" +#include "SkExtras.h" +#include "SkMemberInfo.h" +#include "SkStream.h" +#include "SkSystemEventTypes.h" +#include "SkTime.h" + +class DefaultTimeline : public SkAnimator::Timeline { + virtual SkMSec getMSecs() const { + return SkTime::GetMSecs(); + } +} gDefaultTimeline; + +SkAnimateMaker::SkAnimateMaker(SkAnimator* animator, SkCanvas* canvas, SkPaint* paint) + : fActiveEvent(NULL), fAdjustedStart(0), fCanvas(canvas), fEnableTime(0), + fHostEventSinkID(0), fMinimumInterval((SkMSec) -1), fPaint(paint), fParentMaker(NULL), + fTimeline(&gDefaultTimeline), fInInclude(false), fInMovie(false), + fFirstScriptError(false), fLoaded(false), fIDs(256), fAnimator(animator) +{ + fScreenplay.time = 0; +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + fDebugTimeBase = (SkMSec) -1; +#endif +#ifdef SK_DUMP_ENABLED + fDumpEvents = fDumpGConditions = fDumpPosts = false; +#endif +} + +SkAnimateMaker::~SkAnimateMaker() { + deleteMembers(); +} + +#if 0 +SkMSec SkAnimateMaker::adjustDelay(SkMSec expectedBase, SkMSec delay) { + SkMSec appTime = (*fTimeCallBack)(); + if (appTime) + delay -= appTime - expectedBase; + if (delay < 0) + delay = 0; + return delay; +} +#endif + +void SkAnimateMaker::appendActive(SkActive* active) { + fDisplayList.append(active); +} + +void SkAnimateMaker::clearExtraPropertyCallBack(SkDisplayTypes type) { + SkExtras** end = fExtras.end(); + for (SkExtras** extraPtr = fExtras.begin(); extraPtr < end; extraPtr++) { + SkExtras* extra = *extraPtr; + if (extra->definesType(type)) { + extra->fExtraCallBack = NULL; + extra->fExtraStorage = NULL; + break; + } + } +} + +bool SkAnimateMaker::computeID(SkDisplayable* displayable, SkDisplayable* parent, SkString* newID) { + const char* script; + if (findKey(displayable, &script) == false) + return true; + return SkAnimatorScript::EvaluateString(*this, displayable, parent, script, newID); +} + +SkDisplayable* SkAnimateMaker::createInstance(const char name[], size_t len) { + SkDisplayTypes type = SkDisplayType::GetType(this, name, len ); + if ((int)type >= 0) + return SkDisplayType::CreateInstance(this, type); + return NULL; +} + +// differs from SkAnimator::decodeStream in that it does not reset error state +bool SkAnimateMaker::decodeStream(SkStream* stream) +{ + SkDisplayXMLParser parser(*this); + return parser.parse(*stream); +} + +// differs from SkAnimator::decodeURI in that it does not set URI base +bool SkAnimateMaker::decodeURI(const char uri[]) { +// SkDebugf("animator decode %s\n", uri); + SkStream* stream = SkStream::GetURIStream(fPrefix.c_str(), uri); + SkAutoTDelete<SkStream> autoDel(stream); + bool success = decodeStream(stream); + if (hasError() && fError.hasNoun() == false) + fError.setNoun(uri); + return success; +} + +#if defined SK_DEBUG && 0 +//used for the if'd out section of deleteMembers +#include "SkTSearch.h" + +extern "C" { + int compare_disp(const void* a, const void* b) { + return *(const SkDisplayable**)a - *(const SkDisplayable**)b; + } +} +#endif + +void SkAnimateMaker::delayEnable(SkApply* apply, SkMSec time) { + int index = fDelayed.find(apply); + if (index < 0) + *fDelayed.append() = apply; + (new SkEvent(SK_EventType_Delay))->postTime(fAnimator->getSinkID(), time); +} + +void SkAnimateMaker::deleteMembers() { + int index; +#if defined SK_DEBUG && 0 + //this code checks to see if helpers are among the children, but it is not complete - + //it should check the children of the children + int result; + SkTDArray<SkDisplayable*> children(fChildren.begin(), fChildren.count()); + SkQSort(children.begin(), children.count(), sizeof(SkDisplayable*),compare_disp); + for (index = 0; index < fHelpers.count(); index++) { + SkDisplayable* helper = fHelpers[index]; + result = SkTSearch(children.begin(), children.count(), helper, sizeof(SkDisplayable*)); + SkASSERT(result < 0); + } +#endif + for (index = 0; index < fChildren.count(); index++) { + SkDisplayable* child = fChildren[index]; + delete child; + } + for (index = 0; index < fHelpers.count(); index++) { + SkDisplayable* helper = fHelpers[index]; + delete helper; + } + for (index = 0; index < fExtras.count(); index++) { + SkExtras* extras = fExtras[index]; + delete extras; + } +} + +void SkAnimateMaker::doDelayedEvent() { + fEnableTime = getAppTime(); + for (int index = 0; index < fDelayed.count(); ) { + SkDisplayable* child = fDelayed[index]; + SkASSERT(child->isApply()); + SkApply* apply = (SkApply*) child; + apply->interpolate(*this, fEnableTime); + if (apply->hasDelayedAnimator()) + index++; + else + fDelayed.remove(index); + } +} + +bool SkAnimateMaker::doEvent(const SkEvent& event) { + return (!fInMovie || fLoaded) && fAnimator->doEvent(event); +} + +#ifdef SK_DUMP_ENABLED +void SkAnimateMaker::dump(const char* match) { + SkTDict<SkDisplayable*>::Iter iter(fIDs); + const char* name; + SkDisplayable* result; + while ((name = iter.next(&result)) != NULL) { + if (strcmp(match,name) == 0) + result->dump(this); + } +} +#endif + +int SkAnimateMaker::dynamicProperty(SkString& nameStr, SkDisplayable** displayablePtr ) { + const char* name = nameStr.c_str(); + const char* dot = strchr(name, '.'); + SkASSERT(dot); + SkDisplayable* displayable; + if (find(name, dot - name, &displayable) == false) { + SkASSERT(0); + return 0; + } + const char* fieldName = dot + 1; + const SkMemberInfo* memberInfo = displayable->getMember(fieldName); + *displayablePtr = displayable; + return (int) memberInfo->fOffset; +} + +SkMSec SkAnimateMaker::getAppTime() const { + return fTimeline->getMSecs(); +} + +#ifdef SK_DEBUG +SkAnimator* SkAnimateMaker::getRoot() +{ + SkAnimateMaker* maker = this; + while (maker->fParentMaker) + maker = maker->fParentMaker; + return maker == this ? NULL : maker->fAnimator; +} +#endif + +void SkAnimateMaker::helperAdd(SkDisplayable* trackMe) { + SkASSERT(fHelpers.find(trackMe) < 0); + *fHelpers.append() = trackMe; +} + +void SkAnimateMaker::helperRemove(SkDisplayable* alreadyTracked) { + int helperIndex = fHelpers.find(alreadyTracked); + if (helperIndex >= 0) + fHelpers.remove(helperIndex); +} + +#if 0 +void SkAnimateMaker::loadMovies() { + for (SkDisplayable** dispPtr = fMovies.begin(); dispPtr < fMovies.end(); dispPtr++) { + SkDisplayable* displayable = *dispPtr; + SkASSERT(displayable->getType() == SkType_Movie); + SkDisplayMovie* movie = (SkDisplayMovie*) displayable; + SkAnimateMaker* movieMaker = movie->fMovie.fMaker; + movieMaker->fEvents.doEvent(*movieMaker, SkDisplayEvent::kOnload, NULL); + movieMaker->fEvents.removeEvent(SkDisplayEvent::kOnload, NULL); + movieMaker->loadMovies(); + } +} +#endif + +void SkAnimateMaker::notifyInval() { + if (fHostEventSinkID) + fAnimator->onEventPost(new SkEvent(SK_EventType_Inval), fHostEventSinkID); +} + +void SkAnimateMaker::notifyInvalTime(SkMSec time) { + if (fHostEventSinkID) + fAnimator->onEventPostTime(new SkEvent(SK_EventType_Inval), fHostEventSinkID, time); +} + +void SkAnimateMaker::postOnEnd(SkAnimateBase* animate, SkMSec end) { + SkEvent evt; + evt.setS32("time", animate->getStart() + end); + evt.setPtr("anim", animate); + evt.setType(SK_EventType_OnEnd); + SkEventSinkID sinkID = fAnimator->getSinkID(); + fAnimator->onEventPost(new SkEvent(evt), sinkID); +} + +void SkAnimateMaker::reset() { + deleteMembers(); + fChildren.reset(); + fHelpers.reset(); + fIDs.reset(); + fEvents.reset(); + fDisplayList.hardReset(); +} + +void SkAnimateMaker::removeActive(SkActive* active) { + if (active == NULL) + return; + fDisplayList.remove(active); +} + +bool SkAnimateMaker::resolveID(SkDisplayable* displayable, SkDisplayable* original) { + SkString newID; + bool success = computeID(original, NULL, &newID); + if (success) + setID(displayable, newID); + return success; +} + +void SkAnimateMaker::setErrorString() { + fErrorString.reset(); + if (fError.hasError()) { + SkString err; + if (fFileName.size() > 0) + fErrorString.set(fFileName.c_str()); + else + fErrorString.set("screenplay error"); + int line = fError.getLineNumber(); + if (line >= 0) { + fErrorString.append(", "); + fErrorString.append("line "); + fErrorString.appendS32(line); + } + fErrorString.append(": "); + fError.getErrorString(&err); + fErrorString.append(err); +#if defined SK_DEBUG + SkDebugf("%s\n", fErrorString.c_str()); +#endif + } +} + +void SkAnimateMaker::setEnableTime(SkMSec appTime, SkMSec expectedTime) { +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + SkString debugOut; + SkMSec time = getAppTime(); + debugOut.appendS32(time - fDebugTimeBase); + debugOut.append(" set enable old enable="); + debugOut.appendS32(fEnableTime - fDebugTimeBase); + debugOut.append(" old adjust="); + debugOut.appendS32(fAdjustedStart); + debugOut.append(" new enable="); + debugOut.appendS32(expectedTime - fDebugTimeBase); + debugOut.append(" new adjust="); + debugOut.appendS32(appTime - expectedTime); + SkDebugf("%s\n", debugOut.c_str()); +#endif + fAdjustedStart = appTime - expectedTime; + fEnableTime = expectedTime; + SkDisplayable** firstMovie = fMovies.begin(); + SkDisplayable** endMovie = fMovies.end(); + for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) { + SkDisplayMovie* movie = (SkDisplayMovie*) *ptr; + movie->fMovie.fMaker->setEnableTime(appTime, expectedTime); + } +} + +void SkAnimateMaker::setExtraPropertyCallBack(SkDisplayTypes type, + SkScriptEngine::_propertyCallBack callBack, void* userStorage) { + SkExtras** end = fExtras.end(); + for (SkExtras** extraPtr = fExtras.begin(); extraPtr < end; extraPtr++) { + SkExtras* extra = *extraPtr; + if (extra->definesType(type)) { + extra->fExtraCallBack = callBack; + extra->fExtraStorage = userStorage; + break; + } + } +} + +void SkAnimateMaker::setID(SkDisplayable* displayable, const SkString& newID) { + fIDs.set(newID.c_str(), displayable); +#ifdef SK_DEBUG + displayable->_id.set(newID); + displayable->id = displayable->_id.c_str(); +#endif +} + +void SkAnimateMaker::setScriptError(const SkScriptEngine& engine) { + SkString errorString; +#ifdef SK_DEBUG + engine.getErrorString(&errorString); +#endif + setErrorNoun(errorString); + setErrorCode(SkDisplayXMLParserError::kErrorInScript); +} + +bool SkAnimateMaker::GetStep(const char* token, size_t len, void* stepPtr, SkScriptValue* value) { + if (SK_LITERAL_STR_EQUAL("step", token, len)) { + value->fOperand.fS32 = *(S32*) stepPtr; + value->fType = SkType_Int; + return true; + } + return false; +} diff --git a/libs/graphics/animator/SkAnimateMaker.h b/libs/graphics/animator/SkAnimateMaker.h new file mode 100644 index 0000000000..acc2c54b9e --- /dev/null +++ b/libs/graphics/animator/SkAnimateMaker.h @@ -0,0 +1,153 @@ +#ifndef SkAnimateMaker_DEFINED +#define SkAnimateMaker_DEFINED + +// #define SK_DEBUG_ANIMATION_TIMING + +#include "SkAnimator.h" +#include "SkBitmap.h" +#include "SkIntArray.h" +#include "SkDisplayEvents.h" +#include "SkDisplayList.h" +#include "SkDisplayScreenplay.h" +#include "SkDisplayXMLParser.h" +#include "SkScript.h" +#include "SkString.h" +#include "SkTDict.h" + +// not sure where this little helper macro should go + + +class SkActive; +class SkAnimate; +class SkCanvas; +class SkDisplayable; +class SkDrawable; +class SkDump; +class SkEvent; +class SkEventSink; +class SkExtras; +class SkGroup; +class SkPaint; +class SkStream; + +class SkAnimateMaker { +public: + SkAnimateMaker(SkAnimator* animator, SkCanvas* canvas, SkPaint* paint); + ~SkAnimateMaker(); + void appendActive(SkActive* ); + void childrenAdd(SkDisplayable* child) { *fChildren.append() = child; } + void clearExtraPropertyCallBack(SkDisplayTypes type); + bool computeID(SkDisplayable* displayable, SkDisplayable* parent, SkString* newID); + SkDisplayable* createInstance(const char name[], size_t len); + bool decodeStream(SkStream* stream); + bool decodeURI(const char uri[]); + void delayEnable(SkApply* apply, SkMSec time); + void doDelayedEvent(); + bool doEvent(const SkEvent& event); +#ifdef SK_DUMP_ENABLED + void dump(const char* match); +#endif + int dynamicProperty(SkString& nameStr, SkDisplayable** ); + bool find(const char* str, SkDisplayable** displayablePtr) const { + return fIDs.find(str, displayablePtr); + } + bool find(const char* str, size_t len, SkDisplayable** displayablePtr) const { + return fIDs.find(str, len, displayablePtr); + } + bool findKey(SkDisplayable* displayable, const char** string) const { + return fIDs.findKey(displayable, string); + } +// bool find(SkString& string, SkDisplayable** displayablePtr) { +// return fIDs.find(string.c_str(), displayablePtr); +// } + SkAnimator* getAnimator() { return fAnimator; } + SkMSec getAppTime() const; // call caller to get current time +#ifdef SK_DEBUG + SkAnimator* getRoot(); +#endif + SkXMLParserError::ErrorCode getErrorCode() const { return fError.getErrorCode(); } + SkMSec getInTime() { return fDisplayList.getTime(); } + int getNativeCode() const { return fError.getNativeCode(); } + bool hasError() { return fError.hasError(); } + void helperAdd(SkDisplayable* trackMe); + void helperRemove(SkDisplayable* alreadyTracked); + void idsSet(const char* attrValue, size_t len, SkDisplayable* displayable) { + fIDs.set(attrValue, len, displayable); } +// void loadMovies(); + void notifyInval(); + void notifyInvalTime(SkMSec time); + void postOnEnd(SkAnimateBase* animate, SkMSec end); + void removeActive(SkActive* ); + void reset(); + bool resolveID(SkDisplayable* displayable, SkDisplayable* original); + void setEnableTime(SkMSec appTime, SkMSec expectedTime); + void setErrorCode(SkXMLParserError::ErrorCode err) { if (fError.hasError() == false) fError.INHERITED::setCode(err); } + void setErrorCode(SkDisplayXMLParserError::ErrorCode err) { if (fError.hasError() == false) fError.setCode(err); } + void setErrorNoun(const SkString& str) { if (fError.hasError() == false) fError.setNoun(str); } + void setErrorString(); + void setExtraPropertyCallBack(SkDisplayTypes type, SkScriptEngine::_propertyCallBack , void* userStorage); + void setID(SkDisplayable* displayable, const SkString& newID); + void setInnerError(SkAnimateMaker* maker, const SkString& str) { fError.setInnerError(maker, str); } + void setScriptError(const SkScriptEngine& ); +#ifdef SK_DEBUG + void validate() { fDisplayList.validate(); } +#else + void validate() {} +#endif + SkDisplayEvent* fActiveEvent; + SkMSec fAdjustedStart; + SkBitmap fBitmap; + SkCanvas* fCanvas; + SkMSec fEnableTime; + int fEndDepth; // passed parameter to onEndElement + SkEvents fEvents; + SkDisplayList fDisplayList; + SkEventSinkID fHostEventSinkID; + SkMSec fMinimumInterval; + SkPaint* fPaint; + SkAnimateMaker* fParentMaker; + SkString fPrefix; + SkDisplayScreenplay fScreenplay; + const SkAnimator::Timeline* fTimeline; + SkBool8 fInInclude; + SkBool8 fInMovie; + SkBool8 fFirstScriptError; +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + SkMSec fDebugTimeBase; +#endif +#ifdef SK_DUMP_ENABLED + SkString fDumpAnimated; + SkBool8 fDumpEvents; + SkBool8 fDumpGConditions; + SkBool8 fDumpPosts; +#endif +private: + void deleteMembers(); + static bool GetStep(const char* token, size_t len, void* stepPtr, SkScriptValue* ); + SkAnimateMaker& operator=(SkAnimateMaker& ); + SkTDDisplayableArray fChildren; + SkTDDisplayableArray fDelayed; // SkApply that contain delayed enable events + SkDisplayXMLParserError fError; + SkString fErrorString; + SkTDArray<SkExtras*> fExtras; + SkString fFileName; + SkTDDisplayableArray fHelpers; // helper displayables + SkBool8 fLoaded; + SkTDDisplayableArray fMovies; + SkTDict<SkDisplayable*> fIDs; + SkAnimator* fAnimator; + friend class SkAdd; + friend class SkAnimateBase; + friend class SkDisplayXMLParser; + friend class SkAnimator; + friend class SkAnimatorScript; + friend class SkApply; + friend class SkDisplayMovie; + friend class SkDisplayType; + friend class SkEvents; + friend class SkGroup; + friend struct SkMemberInfo; +}; + +#endif // SkAnimateMaker_DEFINED + diff --git a/libs/graphics/animator/SkAnimateProperties.h b/libs/graphics/animator/SkAnimateProperties.h new file mode 100644 index 0000000000..17bc7771bf --- /dev/null +++ b/libs/graphics/animator/SkAnimateProperties.h @@ -0,0 +1,12 @@ +#ifndef SkAnimateProperties_DEFINED +#define SkAnimateProperties_DEFINED + +enum SkAnimateBase_Properties { + SK_PROPERTY(dynamic), + SK_PROPERTY(mirror), + SK_PROPERTY(reset), + SK_PROPERTY(step), + SK_PROPERTY(values) +}; + +#endif // SkAnimateProperties_DEFINED diff --git a/libs/graphics/animator/SkAnimateSchema.xsd b/libs/graphics/animator/SkAnimateSchema.xsd new file mode 100644 index 0000000000..2c75eb4a89 --- /dev/null +++ b/libs/graphics/animator/SkAnimateSchema.xsd @@ -0,0 +1,2787 @@ +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" +xmlns:Sk="urn:screenplay" targetNamespace="urn:screenplay"> + + <!-- /** Animate + An ID of an element of type <animate> or <set> + */ --> + <xs:simpleType name="Animate"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** 3D_Point + An array of three floats in ECMAScript notation: [x, y, z]. + */ --> + <xs:simpleType name="3D_Point"> + <xs:restriction base="xs:string"> + <xs:pattern value="[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)( *, *[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)){2}" /> + </xs:restriction> + </xs:simpleType> + + <!-- /** ARGB + The red, green, blue, and optional alpha color components. + */ --> + <xs:simpleType name="ARGB"> + <xs:restriction base="xs:string"> + <!-- @pattern #[0-9a-fA-F]{3} #rgb contains three hexadecimal digits. #rgb is equivalent to 0xFFrrggbb. --> + <xs:pattern value="#[0-9a-fA-F]{3}"/> + <!-- @pattern #[0-9a-fA-F]{4} #argb contains four hexadecimal digits. #argb is equivalent to 0xaarrggbb. --> + <xs:pattern value="#[0-9a-fA-F]{4}"/> + <!-- @pattern #[0-9a-fA-F]{6} #rrggbb contains six hexadecimal digits. #rrggbb is equivalent to 0xFFrrggbb. --> + <xs:pattern value="#[0-9a-fA-F]{6}"/> + <!-- @pattern #[0-9a-fA-F]{8} #aarrggbb contains eight hexadecimal digits. #aarrggbb is equivalent to 0xaarrggbb. --> + <xs:pattern value="#[0-9a-fA-F]{8}"/> + <!-- @pattern 0[xX][0-9a-fA-F]{8} 0xaarrggbb describes the color as a packed hexadecimal; each pair of digits + corresponds to alpha, red, green, and blue respectively. --> + <xs:pattern value="0[xX][0-9a-fA-F]{8}"/> + <!-- @pattern rgb\(\d+{1,3},\d+{1,3},\d+{1,3}\) rgb(r, g, b) describes color with three integers ranging from 0 to 255, + corresponding to red, green, and blue respectively. --> + <xs:pattern value="rgb\(\d+{1,3},\d+{1,3},\d+{1,3}\)"/> + <!-- @patternList Color can be described by the following standard CSS color names. --> + <xs:pattern value="aliceblue"/> + <xs:pattern value="antiquewhite"/> + <xs:pattern value="aqua"/> + <xs:pattern value="aquamarine"/> + <xs:pattern value="azure"/> + <xs:pattern value="beige"/> + <xs:pattern value="bisque"/> + <xs:pattern value="black"/> + <xs:pattern value="blanchedalmond"/> + <xs:pattern value="blue"/> + <xs:pattern value="blueviolet"/> + <xs:pattern value="brown"/> + <xs:pattern value="burlywood"/> + <xs:pattern value="cadetblue"/> + <xs:pattern value="chartreuse"/> + <xs:pattern value="chocolate"/> + <xs:pattern value="coral"/> + <xs:pattern value="cornflowerblue"/> + <xs:pattern value="cornsilk"/> + <xs:pattern value="crimson"/> + <xs:pattern value="cyan"/> + <xs:pattern value="darkblue"/> + <xs:pattern value="darkcyan"/> + <xs:pattern value="darkgoldenrod"/> + <xs:pattern value="darkgray"/> + <xs:pattern value="darkgreen"/> + <xs:pattern value="darkkhaki"/> + <xs:pattern value="darkmagenta"/> + <xs:pattern value="darkolivegreen"/> + <xs:pattern value="darkorange"/> + <xs:pattern value="darkorchid"/> + <xs:pattern value="darkred"/> + <xs:pattern value="darksalmon"/> + <xs:pattern value="darkseagreen"/> + <xs:pattern value="darkslateblue"/> + <xs:pattern value="darkslategray"/> + <xs:pattern value="darkturquoise"/> + <xs:pattern value="darkviolet"/> + <xs:pattern value="deeppink"/> + <xs:pattern value="deepskyblue"/> + <xs:pattern value="dimgray"/> + <xs:pattern value="dodgerblue"/> + <xs:pattern value="firebrick"/> + <xs:pattern value="floralwhite"/> + <xs:pattern value="forestgreen"/> + <xs:pattern value="fuchsia"/> + <xs:pattern value="gainsboro"/> + <xs:pattern value="ghostwhite"/> + <xs:pattern value="gold"/> + <xs:pattern value="goldenrod"/> + <xs:pattern value="gray"/> + <xs:pattern value="green"/> + <xs:pattern value="greenyellow"/> + <xs:pattern value="honeydew"/> + <xs:pattern value="hotpink"/> + <xs:pattern value="indianred"/> + <xs:pattern value="indigo"/> + <xs:pattern value="ivory"/> + <xs:pattern value="khaki"/> + <xs:pattern value="lavender"/> + <xs:pattern value="lavenderblush"/> + <xs:pattern value="lawngreen"/> + <xs:pattern value="lemonchiffon"/> + <xs:pattern value="lightblue"/> + <xs:pattern value="lightcoral"/> + <xs:pattern value="lightcyan"/> + <xs:pattern value="lightgoldenrodyellow"/> + <xs:pattern value="lightgreen"/> + <xs:pattern value="lightgrey"/> + <xs:pattern value="lightpink"/> + <xs:pattern value="lightsalmon"/> + <xs:pattern value="lightseagreen"/> + <xs:pattern value="lightskyblue"/> + <xs:pattern value="lightslategray"/> + <xs:pattern value="lightsteelblue"/> + <xs:pattern value="lightyellow"/> + <xs:pattern value="lime"/> + <xs:pattern value="limegreen"/> + <xs:pattern value="linen"/> + <xs:pattern value="magenta"/> + <xs:pattern value="maroon"/> + <xs:pattern value="mediumaquamarine"/> + <xs:pattern value="mediumblue"/> + <xs:pattern value="mediumorchid"/> + <xs:pattern value="mediumpurple"/> + <xs:pattern value="mediumseagreen"/> + <xs:pattern value="mediumslateblue"/> + <xs:pattern value="mediumspringgreen"/> + <xs:pattern value="mediumturquoise"/> + <xs:pattern value="mediumvioletred"/> + <xs:pattern value="midnightblue"/> + <xs:pattern value="mintcream"/> + <xs:pattern value="mistyrose"/> + <xs:pattern value="moccasin"/> + <xs:pattern value="navajowhite"/> + <xs:pattern value="navy"/> + <xs:pattern value="oldlace"/> + <xs:pattern value="olive"/> + <xs:pattern value="olivedrab"/> + <xs:pattern value="orange"/> + <xs:pattern value="orangered"/> + <xs:pattern value="orchid"/> + <xs:pattern value="palegoldenrod"/> + <xs:pattern value="palegreen"/> + <xs:pattern value="paleturquoise"/> + <xs:pattern value="palevioletred"/> + <xs:pattern value="papayawhip"/> + <xs:pattern value="peachpuff"/> + <xs:pattern value="peru"/> + <xs:pattern value="pink"/> + <xs:pattern value="plum"/> + <xs:pattern value="powderblue"/> + <xs:pattern value="purple"/> + <xs:pattern value="red"/> + <xs:pattern value="rosybrown"/> + <xs:pattern value="royalblue"/> + <xs:pattern value="saddlebrown"/> + <xs:pattern value="salmon"/> + <xs:pattern value="sandybrown"/> + <xs:pattern value="seagreen"/> + <xs:pattern value="seashell"/> + <xs:pattern value="sienna"/> + <xs:pattern value="silver"/> + <xs:pattern value="skyblue"/> + <xs:pattern value="slateblue"/> + <xs:pattern value="slategray"/> + <xs:pattern value="snow"/> + <xs:pattern value="springgreen"/> + <xs:pattern value="steelblue"/> + <xs:pattern value="tan"/> + <xs:pattern value="teal"/> + <xs:pattern value="thistle"/> + <xs:pattern value="tomato"/> + <xs:pattern value="turquoise"/> + <xs:pattern value="violet"/> + <xs:pattern value="wheat"/> + <xs:pattern value="white"/> + <xs:pattern value="whitesmoke"/> + <xs:pattern value="yellow"/> + <!--@patternListLast --> + <xs:pattern value="yellowgreen"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** AddMode + AddMode controls how the add element adds its referenced element to the + display list. By default, the referenced element remains in the add element + so that the add element's use attribute may be animated to change the + element it refers to. Setting the mode attribute to "immediate" causes the + add element to put the referenced element in the display list directly. + The move and replace elements are not affected by the mode attribute; + they always move or replace the referenced element directly. + */ --> + <xs:simpleType name="AddMode"> + <xs:restriction base="xs:string"> + <!-- @pattern immediate Puts the referenced element in the display list. --> + <xs:pattern value="immediate"/> + <!-- @pattern indirect Puts the containing element in the display list. --> + <xs:pattern value="indirect"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Align + Align places text to the left, center, or right of the text position. + */ --> + <xs:simpleType name="Align"> + <xs:restriction base="xs:string"> + <!-- @pattern left The first character in the text string is drawn at the text position. --> + <xs:pattern value="left"/> + <!-- @pattern center The text string is measured and centered on the text position. --> + <xs:pattern value="center"/> + <!-- @pattern right The last character in the text string is drawn to the left of the text position. --> + <xs:pattern value="right"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** ApplyMode + ApplyMode affects how the apply element animates values. + */ --> + <xs:simpleType name="ApplyMode"> + <xs:restriction base="xs:string"> + <!-- @pattern immediate Iterates through all animation values immediately. --> + <xs:pattern value="immediate"/> + <!-- @pattern once Performs the animation at once without adding the scope to + the display list. --> + <xs:pattern value="once"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** ApplyTransition + ApplyTransition affects how the apply element sets the time of the animators. + */ --> + <xs:simpleType name="ApplyTransition"> + <xs:restriction base="xs:string"> + <!-- @pattern reverse Performs the animation in reverse. --> + <xs:pattern value="reverse"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Base64 + Base64 describes 8 bit binary using 64 character values. + See http://rfc.net/rfc2045.html for the base64 format. + */ --> + <xs:simpleType name="Base64"> + <xs:restriction base="xs:string"> + <xs:pattern value="[A-Za-z0-9+/ ]+"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** BaseBitmap + A reference to an image like a JPEG, GIF, or PNG; or a reference to a bitmap element + that has been drawn into with a drawTo element. + */ --> + <xs:simpleType name="BaseBitmap"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** BitmapEncoding + Used to specify the compression format for writing an image file with the snapshot element. + */ --> + <xs:simpleType name="BitmapEncoding"> + <xs:restriction base="xs:string"> + <!-- @pattern jpeg See http://www.jpeg.org/jpeg/ for more information about JPEG. --> + <xs:pattern value="jpeg"/> + <!-- @pattern png See http://www.libpng.org/pub/png/ for more information about PNG. --> + <xs:pattern value="png"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** BitmapFormat + Determines the number of bits per pixel in a bitmap. + */ --> + <xs:simpleType name="BitmapFormat"> + <xs:restriction base="xs:string"> + <xs:pattern value="none"/> + <!-- @pattern A1 1-bit per pixel, (0 is transparent, 1 is opaque). --> + <xs:pattern value="A1"/> + <!-- @pattern A8 8-bits per pixel, with only alpha specified (0 is transparent, 0xFF is opaque). --> + <xs:pattern value="A8"/> + <!-- @pattern Index8 8-bits per pixel, using a ColorTable element to specify the colors. --> + <xs:pattern value="Index8"/> + <!-- @pattern RGB16 16-bits per pixel, compile-time configured to be either 555 or 565. --> + <xs:pattern value="RGB16"/> + <!-- @pattern RGB32 32-bits per pixel, plus alpha. --> + <xs:pattern value="RGB32"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Boolean + Either "true" (non-zero) or "false" (zero). + */ --> + <xs:simpleType name="Boolean"> + <xs:restriction base="xs:string"> + <xs:pattern value="false"/> + <xs:pattern value="true"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Cap + The values for the strokeCap attribute. + */ --> + <xs:simpleType name="Cap"> + <xs:restriction base="xs:string"> + <!-- @pattern butt begin and end a contour with no extension --> + <xs:pattern value="butt"/> + <!-- @pattern round begin and end a contour with a semi-circle extension --> + <xs:pattern value="round"/> + <!-- @pattern square begin and end a contour with a half square extension --> + <xs:pattern value="square"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Color + A reference to a color element. + */ --> + <xs:simpleType name="Color"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** Displayable + A reference to any element: @list(Displayable) + */ --> + <xs:simpleType name="Displayable"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** DisplayableArray + An array of one or more element IDs. + */ --> + <xs:simpleType name="DisplayableArray"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** Drawable + A reference to an element that can be drawn: @list(Drawable) + */ --> + <xs:simpleType name="Drawable"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** DynamicString + Dynamic strings contain scripts that are re-evaluated each time the script is enabled. + */ --> + <xs:simpleType name="DynamicString"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** EventCode + Key codes that can trigger events, usually corresponding to physical buttons on the device. + */ --> + <xs:simpleType name="EventCode"> + <xs:restriction base="xs:string"> + <xs:pattern value="none"/> + <!-- @pattern up The up arrow. --> + <xs:pattern value="up"/> + <!-- @pattern down The down arrow. --> + <xs:pattern value="down"/> + <!-- @pattern left The left arrow. --> + <xs:pattern value="left"/> + <!-- @pattern right The right arrow. --> + <xs:pattern value="right"/> + <!-- @pattern back The back button (may not be present; the Backspace key on a PC). --> + <xs:pattern value="back"/> + <!-- @pattern end The end button (may not be present; the Esc key on a PC). --> + <xs:pattern value="end"/> + <!-- @pattern OK The OK button (the Enter key on a PC). --> + <xs:pattern value="OK"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** EventKind + Specifies how an event is triggered; by a key, when an animation ends, when the + document is loaded, or when this event is triggered by the user's C++ or XML. + */ --> + <xs:simpleType name="EventKind"> + <xs:restriction base="xs:string"> + <xs:pattern value="none"/> + <!-- @pattern keyChar A key corresponding to a Unichar value. --> + <xs:pattern value="keyChar"/> + <!-- @pattern keyPress A key with a particular function, such as an arrow key or the OK button. --> + <xs:pattern value="keyPress"/> + <!-- @pattern mouseDown Triggered when the primary mouse button is pressed. --> + <xs:pattern value="mouseDown"/> + <!-- @pattern mouseDrag Triggered when the primary mouse is moved while the button is pressed. --> + <xs:pattern value="mouseDrag"/> + <!-- @pattern mouseMove Triggered when the primary mouse is moved. --> + <xs:pattern value="mouseMove"/> + <!-- @pattern mouseUp Triggered when the primary mouse button is released. --> + <xs:pattern value="mouseUp"/> + <!-- @pattern onEnd Triggered when an event ends. --> + <xs:pattern value="onEnd"/> + <!-- @pattern onLoad Triggered when the document loads. --> + <xs:pattern value="onLoad"/> + <!-- @pattern user Triggered when a post element or C++ event is activated. --> + <xs:pattern value="user"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** EventMode + Specifies whether the event is delivered immediately to matching event element or deferred to + the application-wide event handler. + */ --> + <xs:simpleType name="EventMode"> + <xs:restriction base="xs:string"> + <!-- @pattern deferred Process the event using the host's event queue. --> + <xs:pattern value="deferred"/> + <!-- @pattern immediate Activate the event element immediately. --> + <xs:pattern value="immediate"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** FillType + Filled paths that self-intersect use the winding or evenOdd rule to determine whether the + overlaps are filled or are holes. + */ --> + <xs:simpleType name="FillType"> + <xs:restriction base="xs:string"> + <!-- @pattern winding Fill if the sum of edge directions is non-zero. --> + <xs:pattern value="winding"/> + <!-- @pattern evenOdd Fill if the sum of edges is an odd number. --> + <xs:pattern value="evenOdd"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** FilterType + Scaled bitmaps without a filter type set point-sample the source bitmap to determine the + destination pixels' colors. Bilinear and bicubic compute the values of intermediate pixels + by sampling the pixels around them. + */ --> + <xs:simpleType name="FilterType"> + <xs:restriction base="xs:string"> + <xs:pattern value="none"/> + <!-- @pattern bilinear Compute the pixel value as the linear interpolation of adjacent pixels. --> + <xs:pattern value="bilinear"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Float + A signed fractional value. + */ --> + <xs:simpleType name="Float"> + <xs:restriction base="xs:float"> + <xs:pattern value="[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** FloatArray + An array of one or more signed fractional values. + */ --> + <xs:simpleType name="FloatArray"> + <xs:restriction base="xs:float"> + <xs:pattern value="\[[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)( *, *[+-]?([0-9]*\.[0-9]+|[0-9]+\.?))*\]"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** FromPathMode + A matrix computed from an offset along a path may include the point's position, the angle + tangent, or both. + . + */ --> + <xs:simpleType name="FromPathMode"> + <xs:restriction base="xs:string"> + <!-- @pattern normal Compute the matrix using the path's angle and position. --> + <xs:pattern value="normal"/> + <!-- @pattern angle Compute the matrix using only the path's angle. --> + <xs:pattern value="angle"/> + <!-- @pattern position Compute the matrix using only the path's position. --> + <xs:pattern value="position"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Int + A signed integer. + */ --> + <xs:simpleType name="Int"> + <xs:restriction base="xs:integer"/> + </xs:simpleType> + + <!-- /** IntArray + An array of one or more signed integer values. + */ --> + <xs:simpleType name="IntArray"> + <xs:restriction base="xs:integer"> + <xs:pattern value="\[[+-]?[0-9]+( *, *[+-]?[0-9]+)*\]"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Join + The edges of thick lines in a path are joined by extending the outer edges to form a miter, + or by adding a round circle at the intersection point, or by connecting the outer edges with a line + to form a blunt joint. + */ --> + <xs:simpleType name="Join"> + <xs:restriction base="xs:string"> + <!-- @pattern miter Extend the outer edges to form a miter. --> + <xs:pattern value="miter"/> + <!-- @pattern round Join the outer edges with a circular arc. --> + <xs:pattern value="round"/> + <!-- @pattern blunt Connect the outer edges with a line. --> + <xs:pattern value="blunt"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** MaskFilterBlurStyle + A blur can affect the inside or outside part of the shape, or it can affect both. The shape + itself can be drawn solid, or can be invisible. + */ --> + <xs:simpleType name="MaskFilterBlurStyle"> + <xs:restriction base="xs:string"> + <!-- @pattern normal Blur inside and outside. --> + <xs:pattern value="normal"/> + <!-- @pattern solid Solid inside, blur outside. --> + <xs:pattern value="solid"/> + <!-- @pattern outer Invisible inside, blur outside. --> + <xs:pattern value="outer"/> + <!-- @pattern inner Blur inside only.. --> + <xs:pattern value="inner"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** MaskFilter + The ID of a blur or emboss element. + */ --> + <xs:simpleType name="MaskFilter"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** Matrix + The ID of a matrix element. + */ --> + <xs:simpleType name="Matrix"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** MSec + A fractional second with millisecond resolution. + */ --> + <xs:simpleType name="MSec"> + <xs:restriction base="xs:float"/> + </xs:simpleType> + + <!-- /** Paint + The ID of a paint element. + */ --> + <xs:simpleType name="Paint"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** Path + The ID of a path element. + */ --> + <xs:simpleType name="Path"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** PathDirection + PathDirection determines if the path is traveled clockwise or counterclockwise. + */ --> + <xs:simpleType name="PathDirection"> + <xs:restriction base="xs:string"> + <!-- @pattern cw The path is traveled clockwise. --> + <xs:pattern value="cw"/> + <!-- @pattern ccw The path is traveled counterclockwise. --> + <xs:pattern value="ccw"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** PathEffect + The ID of a dash or discrete element. + */ --> + <xs:simpleType name="PathEffect"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** Point + A pair of signed values representing the x and y coordinates of a point. + */ --> + <xs:simpleType name="Point"> + <xs:restriction base="xs:string"> + <xs:pattern value="\[ *[+-]?([0-9]*\.[0-9]+|[0-9]+\.?) *[ ,] *[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)\]"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Rect + The ID of a rectangle element. + */ --> + <xs:simpleType name="Rect"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** Shader + The ID of a linear or radial gradient. + */ --> + <xs:simpleType name="Shader"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** String + A sequence of characters. + */ --> + <xs:simpleType name="String"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** Style + Geometry can be filled, stroked or both. + */ --> + <xs:simpleType name="Style"> + <xs:restriction base="xs:string"> + <!-- @pattern fill The interior of the geometry is filled with the paint's color. --> + <xs:pattern value="fill"/> + <!-- @pattern stroke The outline of the geometry is stroked with the paint's color. --> + <xs:pattern value="stroke"/> + <!-- @pattern strokeAndFill The interior is filled and outline is stroked with the paint's color. --> + <xs:pattern value="strokeAndFill"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Text + The ID of a text element. + */ --> + <xs:simpleType name="Text"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** TextBoxAlign + Multiple lines of text may be aligned to the start of the box, the center, or the end. + */ --> + <xs:simpleType name="TextBoxAlign"> + <xs:restriction base="xs:string"> + <!-- @pattern start The text begins within the upper left of the box. --> + <xs:pattern value="start"/> + <!-- @pattern center The text is positioned in the center of the box. --> + <xs:pattern value="center"/> + <!-- @pattern end The text ends within the lower right of the box. --> + <xs:pattern value="end"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** TextBoxMode + Fitting the text may optionally introduce line breaks. + */ --> + <xs:simpleType name="TextBoxMode"> + <xs:restriction base="xs:string"> + <!-- @pattern oneLine No additional linebreaks are added. --> + <xs:pattern value="oneLine"/> + <!-- @pattern lineBreak Line breaks may be added to fit the text to the box. --> + <xs:pattern value="lineBreak"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** TileMode + A shader describes how to draw within a rectangle. + Outside of the rectangle, the shader may be ignored, clamped on the edges, or repeated. + The repetitions may be mirrored from the original shader. + */ --> + <xs:simpleType name="TileMode"> + <xs:restriction base="xs:string"> + <!-- @pattern clamp The edge shader color is extended. --> + <xs:pattern value="clamp"/> + <!-- @pattern repeat The shader is repeated horizontally and vertically. --> + <xs:pattern value="repeat"/> + <!-- @pattern mirror The shader is mirrored horizontally and vertically. --> + <xs:pattern value="mirror"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Typeface + The ID of a typeface element. + */ --> + <xs:simpleType name="Typeface"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** UnknownArray + An array of values of any type. + */ --> + <xs:simpleType name="UnknownArray"> + <xs:restriction base="xs:string"/> + </xs:simpleType> + + <!-- /** Xfermode + The operation applied when drawing a color to the destination background. + */ --> + <xs:simpleType name="Xfermode"> + <xs:restriction base="xs:string"> + <!-- @pattern clear Set the destination alpha to zero and the destination color to black. --> + <xs:pattern value="clear"/> + <!-- @pattern src Set the destination to the source alpha and color. --> + <xs:pattern value="src"/> + <!-- @pattern dst Set the destination to the destination alpha and color. --> + <xs:pattern value="dst"/> + <!-- @pattern srcOver The default. Set the destination to the source color blended + with the destination by the source alpha. --> + <xs:pattern value="srcOver"/> + <!-- @pattern dstOver Set the destination to the destination color blended + with the source by the destination alpha. --> + <xs:pattern value="dstOver"/> + <!-- @pattern srcIn Set the destination to the source color scaled by the destination + alpha. --> + <xs:pattern value="srcIn"/> + <!-- @pattern dstIn Set the destination to the destination color scaled by the source + alpha. --> + <xs:pattern value="dstIn"/> + <!-- @pattern srcOut Set the destination to the source color scaled by the + inverse of the destination alpha. --> + <xs:pattern value="srcOut"/> + <!-- @pattern dstOut Set the destination to the destination color scaled by the + inverse of the source alpha. --> + <xs:pattern value="dstOut"/> + <!-- @pattern srcATop Set the destination to the source color times the destination alpha, + blended with the destination times the inverse of the source alpha. --> + <xs:pattern value="srcATop"/> + <!-- @pattern dstATop Set the destination to the destination color times the source alpha, + blended with the source times the inverse of the destination alpha. --> + <xs:pattern value="dstATop"/> + <!-- @pattern xor Set the destination to the destination color times the + inverse of the source alpha, + blended with the source times the inverse of the destination alpha. --> + <xs:pattern value="xor"/> + </xs:restriction> + </xs:simpleType> + + <!-- /** Math + Math provides functions and properties in the ECMAScript library to screenplay script expressions. + The Math element is always implicitly added at the top of every screenplay description, so + its functions and properties are always available. + */ --> + <xs:element name="Math"> + <xs:complexType> + <!-- @attribute E The value 2.718281828. --> + <xs:attribute name="E" type="Sk:Float"/> + <!-- @attribute LN10 The value 2.302585093. --> + <xs:attribute name="LN10" type="Sk:Float"/> + <!-- @attribute LN2 The value 0.693147181. --> + <xs:attribute name="LN2" type="Sk:Float"/> + <!-- @attribute LOG10E The value 0.434294482. --> + <xs:attribute name="LOG10E" type="Sk:Float"/> + <!-- @attribute LOG2E The value 1.442695041. --> + <xs:attribute name="LOG2E" type="Sk:Float"/> + <!-- @attribute PI The value 3.141592654. --> + <xs:attribute name="PI" type="Sk:Float"/> + <!-- @attribute SQRT1_2 The value 0.707106781. --> + <xs:attribute name="SQRT1_2" type="Sk:Float"/> + <!-- @attribute SQRT2 The value 1.414213562. --> + <xs:attribute name="SQRT2" type="Sk:Float"/> + <!-- @attribute abs A function that returns the absolute value of its argument. --> + <xs:attribute name="abs" type="Sk:Float"/> + <!-- @attribute acos A function that returns the arc cosine of its argument. --> + <xs:attribute name="acos" type="Sk:Float"/> + <!-- @attribute asin A function that returns the arc sine of its argument. --> + <xs:attribute name="asin" type="Sk:Float"/> + <!-- @attribute atan A function that returns the arc tan of its argument. --> + <xs:attribute name="atan" type="Sk:Float"/> + <!-- @attribute atan2 A function that returns the arc tan of the ratio of its two arguments. --> + <xs:attribute name="atan2" type="Sk:Float"/> + <!-- @attribute ceil A function that returns the rounded up value of its argument. --> + <xs:attribute name="ceil" type="Sk:Float"/> + <!-- @attribute cos A function that returns the cosine of its argument. --> + <xs:attribute name="cos" type="Sk:Float"/> + <!-- @attribute exp A function that returns E raised to a power (the argument). --> + <xs:attribute name="exp" type="Sk:Float"/> + <!-- @attribute floor A function that returns the rounded down value of its argument. --> + <xs:attribute name="floor" type="Sk:Float"/> + <!-- @attribute log A function that returns the natural logarithm its argument. --> + <xs:attribute name="log" type="Sk:Float"/> + <!-- @attribute max A function that returns the largest of any number of arguments. --> + <xs:attribute name="max" type="Sk:Float"/> + <!-- @attribute min A function that returns the smallest of any number of arguments. --> + <xs:attribute name="min" type="Sk:Float"/> + <!-- @attribute pow A function that returns the first argument raised to the power of the second argument. --> + <xs:attribute name="pow" type="Sk:Float"/> + <!-- @attribute random A function that returns a random value from zero to one. + (See also the <random> element.) --> + <xs:attribute name="random" type="Sk:Float"/> + <!-- @attribute round A function that returns the rounded value of its argument. --> + <xs:attribute name="round" type="Sk:Float"/> + <!-- @attribute sin A function that returns the sine of its argument. --> + <xs:attribute name="sin" type="Sk:Float"/> + <!-- @attribute sqrt A function that returns the square root of its argument. --> + <xs:attribute name="sqrt" type="Sk:Float"/> + <!-- @attribute tan A function that returns the tangent of its argument. --> + <xs:attribute name="tan" type="Sk:Float"/> + </xs:complexType> + </xs:element> + + <!-- /** Number + Number provides properties in the ECMAScript library to screenplay script expressions. + The Number element is always implicitly added at the top of every screenplay description, so + its properties are always available. + */ --> + <xs:element name="Number"> + <xs:complexType> + <!-- @attribute MAX_VALUE The maximum number value; approximately 32767.999985 fixed point, + 3.4028235e+38 floating point. --> + <xs:attribute name="MAX_VALUE" type="Sk:Float"/> + <!-- @attribute MIN_VALUE The minimum number value; approximately 0.000015 fixed point, + 1.1754944e-38 floating point. --> + <xs:attribute name="MIN_VALUE" type="Sk:Float"/> + <!-- @attribute NEGATIVE_INFINITY The most negative number value. Fixed point does not + have a value for negative infinity, and approximates it with -32767.999985. --> + <xs:attribute name="NEGATIVE_INFINITY" type="Sk:Float"/> + <!-- @attribute NaN A bit pattern representing "Not a Number". Fixed point does not + have a value for NaN, and approximates it with -32768. --> + <xs:attribute name="NaN" type="Sk:Float"/> + <!-- @attribute POSITIVE_INFINITY The greatest positive number value. Fixed point does not + have a value for positive infinity, and approximates it with 32767.999985. --> + <xs:attribute name="POSITIVE_INFINITY" type="Sk:Float"/> + </xs:complexType> + </xs:element> + + <!-- /** add + Add references a drawable element, and adds it to the display list. + If where and offset are omitted, the element is appended to the end of the display list. + If where is specified, the element is inserted at the first occurance of where in the display list. + If offset and where are specified, the element is inserted at where plus offset. + A positive offset without where inserts the element at the start of the list plus offset. + A negative offset without where inserts the element at the end of the list minus offset. + */ --> + <xs:element name="add"> + <xs:complexType> + <!-- @attribute mode If indirect (the default), keep the add element in the display list, + and draw the add's use element. If immediate, put the add's use element in the display list. --> + <xs:attribute name="mode" type="Sk:AddMode"/> + <!-- @attribute offset The offset added to the insert index. --> + <xs:attribute name="offset" type="Sk:Int"/> + <!-- @attribute use The drawable element to add to the display list. --> + <xs:attribute name="use" type="Sk:Drawable"/> + <!-- @attribute where The drawable element marking where to insert. --> + <xs:attribute name="where" type="Sk:Drawable"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** addCircle + AddCircle adds a closed circle to the parent path element. + */ --> + <xs:element name="addCircle"> + <xs:complexType> + <!-- @attribute direction One of @pattern. @patternDescription --> + <xs:attribute name="direction" type="Sk:PathDirection"/> + <!-- @attribute radius The distance from the center to the edge of the circle. --> + <xs:attribute name="radius" type="Sk:Float"/> + <!-- @attribute x The x coordinate of the circle's center. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The y coordinate of the circle's center.--> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** addOval + AddOval adds a closed oval described by its bounding box to the parent path element. + */ --> + <xs:element name="addOval"> + <xs:complexType> + <!-- @attribute direction One of @pattern. @patternDescription --> + <xs:attribute name="direction" type="Sk:PathDirection"/> + <!-- @attribute bottom The bottom edge of the oval's bounding box. --> + <xs:attribute name="bottom" type="Sk:Float"/> + <!-- @attribute left The left edge of the oval's bounding box. --> + <xs:attribute name="left" type="Sk:Float"/> + <!-- @attribute right The right edge of the oval's bounding box. --> + <xs:attribute name="right" type="Sk:Float"/> + <!-- @attribute top The top edge of the oval's bounding box. --> + <xs:attribute name="top" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** addPath + AddPath adds a path to the parent path element. + An optional matrix may transform the path as it is added. + */ --> + <xs:element name="addPath"> + <xs:complexType> + <!-- @attribute matrix The matrix applied to the path as it is added. --> + <xs:attribute name="matrix" type="Sk:Matrix"/> + <!-- @attribute path The path to add. --> + <xs:attribute name="path" type="Sk:Path"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** addRect + AddRect adds a closed rectangle to the parent path element. + */ --> + <xs:element name="addRect"> + <xs:complexType> + <!-- @attribute direction One of @pattern. @patternDescription --> + <xs:attribute name="direction" type="Sk:PathDirection"/> + <!-- @attribute bottom The bottom edge of the rectangle. --> + <xs:attribute name="bottom" type="Sk:Float"/> + <!-- @attribute left The left edge of the rectangle. --> + <xs:attribute name="left" type="Sk:Float"/> + <!-- @attribute right The right edge of the rectangle. --> + <xs:attribute name="right" type="Sk:Float"/> + <!-- @attribute top" The top" edge of the rectangle. --> + <xs:attribute name="top" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** addRoundRect + AddRoundRect adds a closed rounded rectangle to the parent path element. + */ --> + <xs:element name="addRoundRect"> + <xs:complexType> + <!-- @attribute direction One of @pattern. @patternDescription --> + <xs:attribute name="direction" type="Sk:PathDirection"/> + <!-- @attribute bottom The bottom edge of the rounded rectangle's bounding box. --> + <xs:attribute name="bottom" type="Sk:Float"/> + <!-- @attribute left The left edge of the rounded rectangle's bounding box. --> + <xs:attribute name="left" type="Sk:Float"/> + <!-- @attribute right The right edge of the rounded rectangle's bounding box. --> + <xs:attribute name="right" type="Sk:Float"/> + <!-- @attribute top The top edge of the rounded rectangle's bounding box. --> + <xs:attribute name="top" type="Sk:Float"/> + <!-- @attribute rx The X-radius of the oval used to round the corners. --> + <xs:attribute name="rx" type="Sk:Float"/> + <!-- @attribute ry The Y-radius of the oval used to round the corners. --> + <xs:attribute name="ry" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** animate + Animate varies the value of an element's attribute over time. + The animation may vary starting at the 'from' attribute, and ending at the 'to' attribute, + or may compute the value using the 'formula' attribute. + */ --> + <xs:element name="animate"> + <xs:complexType> + <!-- @attribute begin An optional offset that must elapse before the animation begins. The apply + begin attribute is added to any animator's begin attribute. --> + <xs:attribute name="begin" type="Sk:MSec"/> + <!-- @attribute blend Specifies how the from and to values are blended. A value from 0.0 to + 1.0 specifies a cubic lag/log/lag blend (slow to change at the beginning and end); the closer + blend is to 1.0, the more linear the blend. If omitted, the blend is linear. --> + <xs:attribute name="blend" type="Sk:FloatArray"/> + <!-- @attribute dur The duration of the animation in milliseconds. --> + <xs:attribute name="dur" type="Sk:MSec"/> + <!-- @attribute dynamic If true, restart the animation if any of the simple values the 'from', 'formula', + 'lval', or 'to' attributes reference are changed. Simple values are contained by the array, boolean, float, int, + and string elements. --> + <xs:attribute name="dynamic" type="Sk:Boolean" /> + <!-- @attribute field The attribute to animate. --> + <xs:attribute name="field" type="Sk:String"/> + <!-- @attribute formula A script to execute over time to compute the field's value. Typically, + the fomula is a script expression which includes a reference to the time attribute of the + containing apply element. Requires a dur. For animations that do not stop, set dur="Number.POSITIVE_INFINITY" --> + <xs:attribute name="formula" type="Sk:DynamicString"/> + <!-- @attribute from The starting value (requires a 'to' attribute) --> + <xs:attribute name="from" type="Sk:DynamicString"/> + <!-- @attribute lval An expression evaluating to the attribute to animate. + If present, lval overrides 'field'. The expression is typically an array element, + e.g. lval="x[y]" . --> + <xs:attribute name="lval" type="Sk:DynamicString"/> + <!-- @attribute mirror If true, reverses the interpolated value during even repeat cycles. --> + <xs:attribute name="mirror" type="Sk:Boolean"/> + <!-- @attribute repeat Specifies the number of times to repeat the animation. + (May be fractional.) --> + <xs:attribute name="repeat" type="Sk:Float"/> + <!-- @attribute reset If true, the computed value is the initial value after the + animation is complete. If false, or by default, the computed value is the final value + after the animation is complete. --> + <xs:attribute name="reset" type="Sk:Boolean"/> + <!-- @attribute step When the apply's attribute mode="immediate" or "create", the step attribute can be read by + script to determine the current animation iteration. --> + <xs:attribute name="step" type="Sk:Int" /> + <!-- @attribute target The element to animate. By default, the element contained by the apply + or referenced by the apply's scope attribute is the animate target. --> + <xs:attribute name="target" type="Sk:DynamicString"/> + <!-- @attribute to The ending value (requires a 'from' attribute) --> + <xs:attribute name="to" type="Sk:DynamicString"/> + <!-- @attribute values [Depreciated] --> + <xs:attribute name="values" type="Sk:DynamicString"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** apply + Apply changes one or more attributes of an element. + Apply either contains one displayable element or references the element scoping the change + with the 'scope' attribute. Apply either contains one animator element or references it with + the 'animator' attribute. + In the display list, apply draws the element it scopes after evaluating the animation. + */ --> + <xs:element name="apply"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="1"> + <xs:element ref="Sk:animate"/> + <xs:element ref="Sk:set" /> + <!-- not quite right; want to say 'one of the above, one of the below' + </xs:choice> + <xs:choice minOccurs="0" maxOccurs="1"> + --> + <xs:element ref="Sk:add"/> + <xs:element ref="Sk:array"/> + <xs:element ref="Sk:apply"/> + <xs:element ref="Sk:bitmap"/> + <xs:element ref="Sk:boolean"/> + <xs:element ref="Sk:bounds"/> + <!-- <xs:element ref="Sk3D:camera"/> --> + <xs:element ref="Sk:clear"/> + <xs:element ref="Sk:clip"/> + <xs:element ref="Sk:color"/> + <xs:element ref="Sk:drawTo"/> + <xs:element ref="Sk:float"/> + <xs:element ref="Sk:full"/> + <xs:element ref="Sk:group"/> + <xs:element ref="Sk:image"/> + <xs:element ref="Sk:int"/> + <xs:element ref="Sk:line"/> + <xs:element ref="Sk:matrix"/> + <xs:element ref="Sk:move"/> + <xs:element ref="Sk:oval"/> + <xs:element ref="Sk:paint"/> + <!-- <xs:element ref="Sk:patch"/> --> + <xs:element ref="Sk:path"/> + <xs:element ref="Sk:point"/> + <xs:element ref="Sk:polygon"/> + <xs:element ref="Sk:polyline"/> + <xs:element ref="Sk:post"/> + <xs:element ref="Sk:random"/> + <xs:element ref="Sk:rect"/> + <xs:element ref="Sk:remove"/> + <xs:element ref="Sk:replace"/> + <xs:element ref="Sk:roundRect"/> + <xs:element ref="Sk:save"/> + <xs:element ref="Sk:snapshot"/> + <xs:element ref="Sk:string"/> + <xs:element ref="Sk:text"/> + <xs:element ref="Sk:textBox"/> + <xs:element ref="Sk:textOnPath"/> + <xs:element ref="Sk:textToPath"/> + </xs:choice> + <!-- @attribute animator The description of how the element is changed over time. --> + <xs:attribute name="animator" type="Sk:Animate"/> + <!-- @attribute begin An optional offset that must elapse before the animation begins. The apply + begin attribute is added to any animator's begin attribute. --> + <xs:attribute name="begin" type="Sk:MSec" /> + <!-- @attribute dontDraw Edits an element's attribute without drawing it; for instance, + to edit a clip's rectangle without drawing the rectangle, set dontDraw="true". --> + <xs:attribute name="dontDraw" type="Sk:Boolean"/> + <!-- @attribute dynamicScope The location in the display list where animations are stored. Use + dynamicScope instead of scope if a script expression with potentially different values is desired to + describe the scope. --> + <xs:attribute name="dynamicScope" type="Sk:String"/> + <!-- @attribute interval The optional time interval from one animation frame to the next. --> + <xs:attribute name="interval" type="Sk:MSec" /> + <!-- @attribute mode One of @pattern. @patternDescription --> + <xs:attribute name="mode" type="Sk:ApplyMode"/> + <!-- @attribute pickup Starts the animation at the current target's attribute value. Enabling + 'pickup' permits omitting the 'from' attribute of the animator. --> + <xs:attribute name="pickup" type="Sk:Boolean"/> + <!-- @attribute restore If true, multiple references to the same apply statement save and + restore the interpolated target values. --> + <xs:attribute name="restore" type="Sk:Boolean"/> + <!-- @attribute scope The location in the display list where animations are stored. --> + <xs:attribute name="scope" type="Sk:Drawable"/> + <!-- @attribute step When mode="immediate" or "create", the step attribute can be read by + script to determine the current animation iteration. --> + <xs:attribute name="step" type="Sk:Int" /> + <!-- @attribute steps When mode="immediate", the number of times the animation + is stepped. The animation iterates 'steps' times plus one. --> + <xs:attribute name="steps" type="Sk:Int" /> + <!-- @attribute time When read from script, returns the animation time. Typically used by + an animate element's formula attribute. --> + <xs:attribute name="time" type="Sk:MSec" /> + <!-- @attribute transition One of @pattern. @patternDescription --> + <xs:attribute name="transition" type="Sk:ApplyTransition"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** array + Array contains an array of values of the same type. The values may be + numbers or strings. + */ --> + <xs:element name="array"> + <xs:complexType> + <!-- @attribute length The number of elements in the array (read only). --> + <xs:attribute name="length" type="Sk:Int"/> + <!-- @attribute values The elements in the array. --> + <xs:attribute name="values" type="Sk:UnknownArray"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** bitmap + Bitmap describes a rectangle of pixels. + Use the <drawTo> element to draw to a bitmap. + Add the bitmap to the display list to draw from a bitmap. + */ --> + <xs:element name="bitmap"> + <xs:complexType> + <!-- @attribute erase The color, including the alpha, the bitmap is intially set to. --> + <xs:attribute name="erase" type="Sk:ARGB"/> + <!-- @attribute format One of @pattern. @patternDescription --> + <xs:attribute name="format" type="Sk:BitmapFormat"/> + <!-- @attribute height The height of the bitmap in pixels. --> + <xs:attribute name="height" type="Sk:Int"/> + <!-- @attribute rowBytes The number of byte describing each row of pixels (optional). --> + <xs:attribute name="rowBytes" type="Sk:Int"/> + <!-- @attribute width The height of the width in pixels. --> + <xs:attribute name="width" type="Sk:Int"/> + <!-- @attribute x The left edge of the bitmap in unit space. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The top edge of teh bitmap in unit space. --> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** bitmapShader + BitmapShader sets the paint shader to draw the bitmap as a texture. + */ --> + <xs:element name="bitmapShader"> + <xs:complexType> + <xs:choice > + <xs:element ref="Sk:image" minOccurs="0" /> + <xs:element ref="Sk:matrix" minOccurs="0" /> + </xs:choice> + <!-- @attribute matrix Matrix applies a 3x3 transform to the gradient. --> + <xs:attribute name="matrix" type="Sk:Matrix"/> + <!-- @attribute tileMode One of @pattern. @patternDescription --> + <xs:attribute name="tileMode" type="Sk:TileMode"/> + <!-- @attribute filterType The bitmap filter to employ, one of @pattern. --> + <xs:attribute name="filterType" type="Sk:FilterType"/> + <!-- @attribute image The bitmap to draw. --> + <xs:attribute name="image" type="Sk:BaseBitmap"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + + <!-- /** blur + Blur describes an image filter in the paint that blurs the drawn geometry. + */ --> + <xs:element name="blur"> + <xs:complexType> + <!-- @attribute blurStyle One of @pattern. @patternDescription --> + <xs:attribute name="blurStyle" type="Sk:MaskFilterBlurStyle"/> + <!-- @attribute radius The extent of the filter effect in unit space. If the radius is less + than zero, the blur has no effect. --> + <xs:attribute name="radius" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** boolean + Boolean contains an boolean. The boolean element cannot be added to a display list, but can + by set by animations and read by any attribute definition. An boolean element may be referenced, + for instance, by a group's condition attribute to make an animation conditionally execute. + */ --> + <xs:element name="boolean"> + <xs:complexType> + <!-- @attribute value The contained boolean. --> + <xs:attribute name="value" type="Sk:Boolean"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** bounds + Bounds describes a bounding box that is not drawn. Bounds is used to specify a rectangle to + invalidate or record whether the specified area was drawn. + The width and height attribute compute the rectangle's right and bottom edges when the rectangle + description is first seen. Animating the rectangle's left or top will not recompute the right or bottom + if the width or height have been specified. + */ --> + <xs:element name="bounds"> + <xs:complexType> + <!-- @attribute bottom The bottom edge of the rectangle. --> + <xs:attribute name="bottom" type="Sk:Float"/> + <!-- @attribute height The height of the rectangle. Setting height computes the + bottom attribute from the top attribute. --> + <xs:attribute name="height" type="Sk:Float"/> + <!-- @attribute inval If set to true, union the drawn bounds to compute an inval area. --> + <xs:attribute name="inval" type="Sk:Boolean"/> + <!-- @attribute left The left edge of the rectangle. --> + <xs:attribute name="left" type="Sk:Float"/> + <!-- @attribute needsRedraw Set to true if last draw was visible. --> + <xs:attribute name="needsRedraw" type="Sk:Boolean"/> + <!-- @attribute right The right edge of the rectangle. --> + <xs:attribute name="right" type="Sk:Float"/> + <!-- @attribute top The top edge of the rectangle. --> + <xs:attribute name="top" type="Sk:Float"/> + <!-- @attribute width The width of the rectangle. --> + <xs:attribute name="width" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** clear + Clear removes all entries in the display list. + */ --> + <xs:element name="clear"> + <xs:complexType> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** clip + Clip sets the canvas to clip drawing to an element's geometry. + A clip element may contain an element or reference an element with the path or + rectangle attributes. To make the clip unrestricted, enclose a 'full' element. + */ --> + <xs:element name="clip"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="1"> + <xs:element ref="Sk:full"/> + <xs:element ref="Sk:rect"/> + <xs:element ref="Sk:path"/> + <xs:element ref="Sk:polygon"/> + <xs:element ref="Sk:polyline"/> + </xs:choice> + <!-- @attribute path A path-derived element to clip to: either an oval, + a path, a polygon, a polyline, or a roundRect. --> + <xs:attribute name="path" type="Sk:Path"/> + <!-- @attribute rect A rectangle element to clip to. --> + <xs:attribute name="rect" type="Sk:Rect"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** close + Close connects the last point in the path's contour to the first if the contour is not already closed. + */ --> + <xs:element name="close"> + <xs:complexType> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** color + Color describes a color in RGB space or HSV space, and its alpha (transparency). + */ --> + <xs:element name="color"> + <xs:complexType> + <!-- @attribute alpha The alpha component, which describes transparency. + Alpha ranges from 0.0 (transparent) to 1.0 (completely opaque). --> + <xs:attribute name="alpha" type="Sk:Float"/> + <!-- @attribute blue The blue component of an RGB color. Blue ranges from 0 to 255. --> + <xs:attribute name="blue" type="Sk:Float"/> + <!-- @attribute color The complete color. The color can be specified by name, + by hexadecimal value, or with the rgb function. --> + <xs:attribute name="color" type="Sk:ARGB"/> + <!-- @attribute green The green component of an RGB color. Green ranges from 0 to 255. --> + <xs:attribute name="green" type="Sk:Float"/> + <!-- @attribute hue The hue component of an HSV color. Hue ranges from 0 to 360. --> + <xs:attribute name="hue" type="Sk:Float"/> + <!-- @attribute red The red component of an RGB color. Red ranges from 0 to 255. --> + <xs:attribute name="red" type="Sk:Float"/> + <!-- @attribute saturation The saturation component of an HSV color. Saturation ranges from 0 to 1. --> + <xs:attribute name="saturation" type="Sk:Float"/> + <!-- @attribute value The value component of an HSV color. Value ranges from 0 to 1. --> + <xs:attribute name="value" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** cubicTo + CubicTo adds a cubic to the path, using the last point in the path as the first point of the cubic. + */ --> + <xs:element name="cubicTo"> + <xs:complexType> + <!-- @attribute x1 The x position of the first off-curve point. --> + <xs:attribute name="x1" type="Sk:Float"/> + <!-- @attribute x2 The x position of the second off-curve point. --> + <xs:attribute name="x2" type="Sk:Float"/> + <!-- @attribute x3 The x position of the final on-curve point. --> + <xs:attribute name="x3" type="Sk:Float"/> + <!-- @attribute y1 The y position of the first off-curve point. --> + <xs:attribute name="y1" type="Sk:Float"/> + <!-- @attribute y2 The y position of the second off-curve point. --> + <xs:attribute name="y2" type="Sk:Float"/> + <!-- @attribute y3 The y position of the final on-curve point. --> + <xs:attribute name="y3" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** dash + Dash describes an array of dashes and gaps that describe how the paint strokes lines, + rectangles, and paths. The intervals, phase, and dashed path are all measured in the same + unit space. The phase and distance between dashes is unaffected by the paint's stroke width. + */ --> + <xs:element name="dash"> + <xs:complexType> + <!-- @attribute intervals An array of floats that alternately describe the lengths of + dashes and gaps. Intervals must contain an even number of entries. --> + <xs:attribute name="intervals" type="Sk:FloatArray"/> + <!-- @attribute phase Phase advances the placement of the first dash. A positive phase + preceeds the first dash with a gap. A negative phase shortens the length of the first dash. --> + <xs:attribute name="phase" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** data + Data provides metadata to an event. The metadata may be an integer, a float, + or a string. + */ --> + <xs:element name="data"> + <xs:complexType> + <!-- @attribute float The float value associated with the metadata. --> + <xs:attribute name="float" type="Sk:Float"/> + <!-- @attribute initialized A read-only value set to false (unused by data). --> + <xs:attribute name="initialized" type="Sk:Boolean"/> + <!-- @attribute int The integer value associated with the metadata. --> + <xs:attribute name="int" type="Sk:Int"/> + <!-- @attribute name The name of the metadata. This is the name of the data. --> + <xs:attribute name="name" type="Sk:String"/> + <!-- @attribute string The string value associated with the metadata. --> + <xs:attribute name="string" type="Sk:String"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** discrete + Discrete alters the edge of the stroke randomly. Discrete is a path effect, and only has an + effect when referenced from a paint.. A <pathEffect/> + element with no attributes will dissable discrete. + */ --> + <xs:element name="discrete"> + <xs:complexType> + <!-- @attribute deviation The amount of wobble in the stroke. --> + <xs:attribute name="deviation" type="Sk:Float"/> + <!-- @attribute segLength The length of wobble in the stroke. --> + <xs:attribute name="segLength" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** drawTo + DrawTo images to a bitmap. The bitmap can be added to the display list + to draw the composite image. + DrawTo can be used as an offscreen to speed complicated animations, and + for bitmap effects such as pixelated zooming. + DrawTo can only reference a single drawable element. Use <add>, + <group>, or <save> to draw multiple elements with <drawTo>. + */ --> + <xs:element name="drawTo"> + <xs:complexType> + <xs:choice maxOccurs="unbounded" > + <xs:element ref="Sk:add"/> + <xs:element ref="Sk:apply"/> + <xs:element ref="Sk:bitmap"/> + <xs:element ref="Sk:bounds"/> + <!-- <xs:element ref="Sk3D:camera"/> --> + <xs:element ref="Sk:clear"/> + <xs:element ref="Sk:clip"/> + <xs:element ref="Sk:color"/> + <xs:element ref="Sk:full"/> + <xs:element ref="Sk:group"/> + <xs:element ref="Sk:image"/> + <xs:element ref="Sk:line"/> + <xs:element ref="Sk:matrix"/> + <xs:element ref="Sk:move"/> + <xs:element ref="Sk:oval"/> + <xs:element ref="Sk:paint"/> + <!-- <xs:element ref="Sk:patch"/> --> + <xs:element ref="Sk:path"/> + <xs:element ref="Sk:point"/> + <xs:element ref="Sk:polygon"/> + <xs:element ref="Sk:polyline"/> + <xs:element ref="Sk:rect"/> + <xs:element ref="Sk:remove"/> + <xs:element ref="Sk:replace"/> + <xs:element ref="Sk:roundRect"/> + <xs:element ref="Sk:save"/> + <xs:element ref="Sk:text"/> + <xs:element ref="Sk:textBox"/> + <xs:element ref="Sk:textOnPath"/> + <xs:element ref="Sk:textToPath"/> + </xs:choice> + <!-- @attribute drawOnce If set, the drawTo will only draw a single time. --> + <xs:attribute name="drawOnce" type="Sk:Boolean"/> + <!-- @attribute use The bitmap to draw into. --> + <xs:attribute name="use" type="Sk:bitmap"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** dump + Dump prints a list of the items in the display list and all items' + children to the debug console. Dump is only available in Debug + builds. */ --> + <xs:element name="dump"> + <xs:complexType> + <!-- @attribute displayList Dumps the current display list if true. The display list is also + dumped if dump has no attributes. --> + <xs:attribute name="displayList" type="Sk:Boolean"/> + <!-- @attribute eventList Dumps the list of events, both enabled and disabled. --> + <xs:attribute name="eventList" type="Sk:Boolean"/> + <!-- @attribute events Outputs each event element as it is enabled. --> + <xs:attribute name="events" type="Sk:Boolean"/> + <!-- @attribute groups Outputs each group element as its condition is evaluated. --> + <xs:attribute name="groups" type="Sk:Boolean"/> + <!-- @attribute name Outputs the values associated with a single named element. --> + <xs:attribute name="name" type="Sk:String"/> + <!-- @attribute posts Outputs each post element as it is enabled. --> + <xs:attribute name="posts" type="Sk:Boolean"/> + <!-- @attribute script Evaluates the provided script --> + <xs:attribute name="script" type=Sk:String"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** emboss + PRELIMINARY [to be replaced with SkEmbossMaskFilter.h doxyfomation + at some point] + Emboss applies a mask filter to the paint that makes bias the object's color + towards white or black depending on the normals of the path contour, giving + the shape a 3D raised or depressed effect. + Embossing is replaced by subsequent mask filter elements, or + disabled a negative radius, or by an empty <mask filter> element. + */ --> + <xs:element name="emboss"> + <xs:complexType> + <!-- @attribute ambient The amount of ambient light, from 0 to 1. --> + <xs:attribute name="ambient" type="Sk:Float"/> + <!-- @attribute direction The direction of the light source, as descibed by a 3D vector. + (The vector is normalized to a unit length of 1.0.) --> + <xs:attribute name="direction" type="Sk:FloatArray"/> + <!-- @attribute radius The extent of the filter effect in unit space. If the radius is less + than zero, the emboss has no effect. --> + <xs:attribute name="radius" type="Sk:Float"/> + <!-- @attribute specular The expotential intensity of the light, from 0 to 1. + Each increase of 0.0625 doubles the intensity. --> + <xs:attribute name="specular" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** event + Event contains a series of actions performed each time the event's criteria are satisfied. + These actions may modify the display list, may enable animations which in turn modify + elements' attributes, and may post other events. + */ --> + <xs:element name="event"> + <xs:complexType> + <xs:choice maxOccurs="unbounded" > + <xs:element ref="Sk:add"/> + <xs:element ref="Sk:apply"/> + <xs:element ref="Sk:array"/> + <xs:element ref="Sk:bitmap"/> + <xs:element ref="Sk:boolean"/> + <xs:element ref="Sk:bounds"/> + <!-- <xs:element ref="Sk3D:camera"/> --> + <xs:element ref="Sk:clear"/> + <xs:element ref="Sk:clip"/> + <xs:element ref="Sk:color"/> + <xs:element ref="Sk:drawTo"/> + <xs:element ref="Sk:dump"/> + <xs:element ref="Sk:float"/> + <xs:element ref="Sk:full"/> + <xs:element ref="Sk:group"/> + <xs:element ref="Sk:hitClear"/> + <xs:element ref="Sk:hitTest"/> + <xs:element ref="Sk:image"/> + <xs:element ref="Sk:input"/> + <xs:element ref="Sk:int"/> + <xs:element ref="Sk:line"/> + <xs:element ref="Sk:matrix"/> + <xs:element ref="Sk:move"/> + <xs:element ref="Sk:movie"/> + <xs:element ref="Sk:oval"/> + <xs:element ref="Sk:paint"/> + <!-- <xs:element ref="Sk:patch"/> --> + <xs:element ref="Sk:path"/> + <xs:element ref="Sk:point"/> + <xs:element ref="Sk:polygon"/> + <xs:element ref="Sk:polyline"/> + <xs:element ref="Sk:post"/> + <xs:element ref="Sk:random"/> + <xs:element ref="Sk:rect"/> + <xs:element ref="Sk:remove"/> + <xs:element ref="Sk:replace"/> + <xs:element ref="Sk:roundRect"/> + <xs:element ref="Sk:save"/> + <xs:element ref="Sk:snapshot"/> + <xs:element ref="Sk:string"/> + <xs:element ref="Sk:text"/> + <xs:element ref="Sk:textBox"/> + <xs:element ref="Sk:textOnPath"/> + <xs:element ref="Sk:textToPath"/> + </xs:choice> + <!-- @attribute code The key code to match to a key press event, one of @pattern. + If the code is set to @pattern[0], the event is never activated. --> + <xs:attribute name="code" type="Sk:EventCode"/> + <!-- @attribute disable If true, the event cannot be activated. By default false.. --> + <xs:attribute name="disable" type="Sk:Boolean"/> + <!-- @attribute key The character code to match to a key down event. + When read, the key that activated this event. --> + <xs:attribute name="key" type="Sk:String"/> + <!-- @attribute keys A dash-separated continuous range of character codes to match + to a key down event. Read the key attribute to determine the key that activated this event. --> + <xs:attribute name="keys" type="Sk:String"/> <!-- single or range of keys --> + <!-- @attribute kind The event kind that activates this event, one of @pattern. + If kind equals keyChar, either attribute key or keys is expected. + If kind equals keyPress, attribute code is expected. + If kind equals onEnd, attribute target is expected. + If kind equals onLoad, the event is activated when the document containing the event + is loaded. The onLoad attribute cannot be activated through a post event. + If kind equals user, the event is activated when the posted event targets this event's ID. --> + <xs:attribute name="kind" type="Sk:EventKind"/> + <!-- @attribute target The element to listen to which activates this event. --> + <xs:attribute name="target" type="Sk:String" /> + <!-- @attribute x For click events, the x-coordinate of the click. --> + <xs:attribute name="x" type="Sk:Float" /> + <!-- @attribute y For click events, the y-coordinate of the click. --> + <xs:attribute name="y" type="Sk:Float" /> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** float + Float contains a signed fractional value. The float element cannot be added to a display list, + but can be set by animations and read by any attribute definition. + */ --> + <xs:element name="float"> + <xs:complexType> + <!-- @attribute value The contained float. --> + <xs:attribute name="value" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** fromPath + FromPath concatenates the parent matrix with a new matrix + that maps a unit vector to a point on the given path. + A fromPath element may contain a path element, or may refer to a previously + defined path element with the path attribute. + */ --> + <xs:element name="fromPath"> + <xs:complexType> + <xs:choice > + <!-- @element path The path to evaluate. --> + <xs:element ref="Sk:path" minOccurs="0" /> + </xs:choice> + <!-- @attribute mode One of @pattern. + If mode is set to normal, the matrix maps the unit vector's angle and position. + If mode is set to angle, the matrix maps only the unit vector's angle. + If mode is set to position, the matrix maps only the unit vector's position. --> + <xs:attribute name="mode" type="Sk:FromPathMode"/> + <!-- @attribute offset The distance along the path to evaluate. --> + <xs:attribute name="offset" type="Sk:Float"/> + <!-- @attribute path The path to evaluate. --> + <xs:attribute name="path" type="Sk:Path"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** full + Full paints the entire canvas to the limit of the canvas' clip. + */ --> + <xs:element name="full"> + <xs:complexType> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** group + The group element collects a series of elements into a group. The group can be referenced + or defined within elements, like apply, which operate on any kind of element. Groups + may contain groups. An element in a group draws identically to an element outside a group. + */ --> + <xs:element name="group"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <xs:element ref="Sk:add"/> + <xs:element ref="Sk:apply"/> + <xs:element ref="Sk:array"/> + <xs:element ref="Sk:bitmap"/> + <xs:element ref="Sk:boolean"/> + <xs:element ref="Sk:bounds"/> + <!-- <xs:element ref="Sk3D:camera"/> --> + <xs:element ref="Sk:clear"/> + <xs:element ref="Sk:clip"/> + <xs:element ref="Sk:drawTo"/> + <xs:element ref="Sk:float"/> + <xs:element ref="Sk:full"/> + <xs:element ref="Sk:group"/> + <xs:element ref="Sk:hitClear"/> + <xs:element ref="Sk:hitTest"/> + <xs:element ref="Sk:image"/> + <xs:element ref="Sk:int"/> + <xs:element ref="Sk:line"/> + <xs:element ref="Sk:matrix"/> + <xs:element ref="Sk:move"/> + <xs:element ref="Sk:oval"/> + <xs:element ref="Sk:paint"/> + <!-- <xs:element ref="Sk:patch"/> --> + <xs:element ref="Sk:path"/> + <xs:element ref="Sk:point"/> + <xs:element ref="Sk:polygon"/> + <xs:element ref="Sk:polyline"/> + <xs:element ref="Sk:post"/> + <xs:element ref="Sk:random"/> + <xs:element ref="Sk:rect"/> + <xs:element ref="Sk:remove"/> + <xs:element ref="Sk:replace"/> + <xs:element ref="Sk:roundRect"/> + <xs:element ref="Sk:save"/> + <xs:element ref="Sk:snapshot"/> + <xs:element ref="Sk:string"/> + <xs:element ref="Sk:text"/> + <xs:element ref="Sk:textBox"/> + <xs:element ref="Sk:textOnPath"/> + <xs:element ref="Sk:textToPath"/> + </xs:choice> + <!-- @attribute condition If present and zero, the contained elements are ignored + when drawn. --> + <xs:attribute name="condition" type="Sk:DynamicString"/> + <!-- @attribute enableCondition If present and zero, the contained elements are ignored + when enabled. --> + <xs:attribute name="enableCondition" type="Sk:DynamicString"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <xs:element name="hitClear" > + <xs:complexType> + <xs:choice maxOccurs="1"> + <xs:element ref="Sk:array"/> + </xs:choice> + <!-- @attribute targets An array of element IDs to clear their hit-tested state. --> + <xs:attribute name="targets" type="Sk:DisplayableArray"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <xs:element name="hitTest" > + <xs:complexType> + <xs:choice maxOccurs="2"> + <xs:element ref="Sk:array"/> + </xs:choice> + <!-- @attribute bullets An array of element IDs to test for intersection with targets. --> + <xs:attribute name="bullets" type="Sk:DisplayableArray"/> + <!-- @attribute hits The targets the bullets hit. A read-only array of indices, one index + per bullet. The value of the array element is the index of the target hit, or -1 if no + target was hit. --> + <xs:attribute name="hits" type="Sk:IntArray"/> + <!-- @attribute targets An array of element IDs to test for intersection with bullets. --> + <xs:attribute name="targets" type="Sk:DisplayableArray"/> + <!-- @attribute value Read only; set to true if some bullet hit some target. --> + <xs:attribute name="value" type="Sk:Boolean"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** image + Image creates a reference to a JPEG, PNG or GIF. The image may be referenced + through the local file system, the internet, or embedded in the document in Base64 + format. The specific image type is determined by examining the byte stream. + */ --> + <xs:element name="image"> + <xs:complexType> + <!-- @attribute base64 The image in Base64 notation. See http://rfc.net/rfc2045.html + for the base64 format. --> + <xs:attribute name="base64" type="Sk:Base64"/> + <!-- @attribute height The height of the image (read-only). --> + <xs:attribute name="height" type="Sk:Int"/> + <!-- @attribute src The URI reference, local to the contaiing document. --> + <xs:attribute name="src" type="Sk:String"/> + <!-- @attribute width The width of the image (read-only). --> + <xs:attribute name="width" type="Sk:Int"/> + <!-- @attribute x The position of the left edge of the image in local coordinates. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The position of the top edge of the image in local coordinates. --> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** include + Include adds the referenced XML to the containing document. Unlike movie, the XML + directives can reference the document's IDs and can define new IDs that are referenced + by the remainder of the document or subsequent includes. + */ --> + <xs:element name="include"> + <xs:complexType> + <!-- @attribute src The URI reference, local to the containing document, + containing the include's XML. --> + <xs:attribute name="src" type="Sk:String"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** input + Input captures the metadata passed from an event. When the metadata's name or id + matches the metadata's name, the metadata's payload is copied to the corresponding + input attribute. + */ --> + <xs:element name="input"> + <xs:complexType> + <!-- @attribute float The floating point payload carried by the metadata. --> + <xs:attribute name="float" type="Sk:Float"/> + <!-- @attribute initialized A read-only value set to true if the input received a value + from the event. --> + <xs:attribute name="initialized" type="Sk:Boolean"/> + <!-- @attribute int The signed integer payload carried by the metadata. --> + <xs:attribute name="int" type="Sk:Int"/> + <!-- @attribute name The name of the metadata containing the payload. Note that + the name or id may match the payload, but that XML requires the id to be + uniquely defined in the document, while multiple input elements may reuse + the name. --> + <xs:attribute name="name" type="Sk:String"/> + <!-- @attribute string The text payload carried by the metadata. --> + <xs:attribute name="string" type="Sk:String"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** int + Int contains an integer. The int element cannot be added to a display list, but can + by set by animations and read by any attribute definition. An int element may be used, + for instance, to index through an array element. + */ --> + <xs:element name="int"> + <xs:complexType> + <!-- @attribute value The contained integer. --> + <xs:attribute name="value" type="Sk:Int"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** line + Line describes a line between two points. As noted below, the paint's stroke and + strokeAndFill attributes are ignored. + */ --> + <xs:element name="line"> + <xs:complexType> + <!-- @attribute x1 The start point's x value. --> + <xs:attribute name="x1" type="Sk:Float"/> + <!-- @attribute x2 The stop point's x value. --> + <xs:attribute name="x2" type="Sk:Float"/> + <!-- @attribute y1 The start point's y value. --> + <xs:attribute name="y1" type="Sk:Float"/> + <!-- @attribute y2 The stop point's y value. --> + <xs:attribute name="y2" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** lineTo + LineTo adds a line from the last point in a path to the specified point. + */ --> + <xs:element name="lineTo"> + <xs:complexType> + <!-- @attribute x The final path x coordinate. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The final path y coordinate. --> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** linearGradient + LinearGradient sets the paint shader to ramp between two or more colors. + */ --> + <xs:element name="linearGradient"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <xs:element ref="Sk:color"/> + <xs:element ref="Sk:matrix"/> + </xs:choice> + <!-- @attribute matrix Matrix applies a 3x3 transform to the gradient. --> + <xs:attribute name="matrix" type="Sk:Matrix"/> + <!-- @attribute tileMode One of @pattern. @patternDescription --> + <xs:attribute name="tileMode" type="Sk:TileMode"/> + <!-- @attribute offsets An optional array of values used to bias the colors. The first entry + in the array must be 0.0, the last must be 1.0, and intermediate values must ascend. --> + <xs:attribute name="offsets" type="Sk:FloatArray"/> + <!-- @attribute points Two points describing the start and end of the gradient. --> + <xs:attribute name="points" type="Sk:Point"/> <!-- not right; should be array of 2 points --> + <!-- @attribute unitMapper A script that returns the mapping for [0,1] for the gradient. + The script can use the predefined variable 'unit' to compute the mapping. For instance, + "unit*unit" squares the value (while still keeping it in the range of [0,1].) The computed number + is pinned to from 0 to 1 after the script is executed. --> + <xs:attribute name="unitMapper" type="Sk:String"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** maskFilter + MaskFilter disables any mask filter referenced by the paint. + */ --> + <xs:element name="maskFilter"> + <xs:complexType> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** matrix + Matrix transforms all points drawn to the canvas. The matrix may translate, scale, skew, rotate, + or apply perspective, or apply any combination. + */ --> + <xs:element name="matrix"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <!-- @element fromPath FromPath maps a unit vector to a position and direction on a path. --> + <xs:element ref="Sk:fromPath"/> + <!-- @element polyToPoly PolyToPoly maps a points between two polygons. --> + <xs:element ref="Sk:polyToPoly"/> + <!-- @element rectToRect RectToRect maps a points between two rectangles. --> + <xs:element ref="Sk:rectToRect"/> + <!-- @element rotate Rotate computes the matrix rotation in degrees. --> + <xs:element ref="Sk:rotate"/> + <!-- @element scale Scale stretches or shrinks horizontally, vertically, or both. --> + <xs:element ref="Sk:scale"/> + <!-- @element skew Skew slants horizontally, vertically, or both. --> + <xs:element ref="Sk:skew"/> + <!-- @element translate Translate moves horizontally, vertically, or both. --> + <xs:element ref="Sk:translate"/> + </xs:choice> + <!-- @attribute matrix Nine floats describing a 3x3 matrix. --> + <xs:attribute name="matrix" type="Sk:FloatArray"/> + <!-- @attribute perspectX The [0][2] element of the 3x3 matrix. --> + <xs:attribute name="perspectX" type="Sk:Float"/> + <!-- @attribute perspectY The [1][2] element of the 3x3 matrix. --> + <xs:attribute name="perspectY" type="Sk:Float"/> + <!-- @attribute rotate The angle to rotate in degrees. --> + <xs:attribute name="rotate" type="Sk:Float"/> + <!-- @attribute scale The scale to apply in both X and Y.. --> + <xs:attribute name="scale" type="Sk:Float"/> + <!-- @attribute scaleX The [0][0] element of the 3x3 matrix. --> + <xs:attribute name="scaleX" type="Sk:Float"/> + <!-- @attribute scaleY The [1][1] element of the 3x3 matrix. --> + <xs:attribute name="scaleY" type="Sk:Float"/> + <!-- @attribute skewX The [0][1] element of the 3x3 matrix. --> + <xs:attribute name="skewX" type="Sk:Float"/> + <!-- @attribute skewY The [1][0] element of the 3x3 matrix. --> + <xs:attribute name="skewY" type="Sk:Float"/> + <!-- @attribute translate A point specifying the translation in X and Y. --> + <xs:attribute name="translate" type="Sk:Point"/> + <!-- @attribute translateX The [2][0] element of the 3x3 matrix. --> + <xs:attribute name="translateX" type="Sk:Float"/> + <!-- @attribute translateY The [2][1] element of the 3x3 matrix. --> + <xs:attribute name="translateY" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** move + Move an element in the display list in front or behind other elements. + If where and offset are omitted, the element is moved to the end of the display list. + If where is specified, the element is moved before the first occurance of where in the display list. + If offset and where are specified, the element is moved before where plus offset. + A positive offset without where moves the element to the start of the list plus offset. + A negative offset without where moves the element to the end of the list minus offset. + */ --> + <xs:element name="move"> + <xs:complexType> + <!-- @attribute mode Has no effect. --> + <xs:attribute name="mode" type="Sk:AddMode"/> + <!-- @attribute offset The destination position using the rules listed above. --> + <xs:attribute name="offset" type="Sk:Int"/> + <!-- @attribute use The element to move. --> + <xs:attribute name="use" type="Sk:Drawable"/> + <!-- @attribute where The ID of the first display list entry to move to. --> + <xs:attribute name="where" type="Sk:Drawable"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** moveTo + MoveTo specifies the first point in a path contour. + */ --> + <xs:element name="moveTo"> + <xs:complexType> + <!-- @attribute x The point's x coordinate. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The point's y coordinate. --> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** movie + Movie describes a display list within the current canvas and paint. Movies can contain + movies. One movie cannot affect how another movie draws, but movies can communicate + with each other by posting events. + */ --> + <xs:element name="movie"> + <xs:complexType> + <!-- @attribute src The URI reference, local to the containing document, containing the movie's XML. --> + <xs:attribute name="src" type="Sk:String"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** oval + Oval describes a circle stretched to fit in a rectangle. + The width and height attribute compute the oval's right and bottom edges when the oval + description is first seen. Animating the oval's left or top will not recompute the right or bottom + if the width or height have been specified. + */ --> + <xs:element name="oval"> + <xs:complexType> + <!-- @attribute bottom The bottom edge of the oval. --> + <xs:attribute name="bottom" type="Sk:Float"/> + <!-- @attribute height The height of the oval. --> + <xs:attribute name="height" type="Sk:Float"/> + <!-- @attribute left The left edge of the oval. --> + <xs:attribute name="left" type="Sk:Float"/> + <!-- @attribute needsRedraw Set to true if last draw was visible. --> + <xs:attribute name="needsRedraw" type="Sk:Boolean"/> + <!-- @attribute right The right edge of the oval. --> + <xs:attribute name="right" type="Sk:Float"/> + <!-- @attribute top The top edge of the oval. --> + <xs:attribute name="top" type="Sk:Float"/> + <!-- @attribute width The width of the oval. --> + <xs:attribute name="width" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** paint + Paint uses color, flags, path effects, mask filters, shaders, and stroke effects when drawing + geometries, images, and text. + */ --> + <xs:element name="paint"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <!-- @element bitmapShader Sets or cancels an image to draw as the color. --> + <xs:element ref="Sk:bitmapShader"/> + <!-- @element blur Blur radially draws the shape with varying transparency. --> + <xs:element ref="Sk:blur"/> + <!-- @element color Color specifies a solid color in RGB or HSV. --> + <xs:element ref="Sk:color"/> + <!-- @element dash Dashes alternates stroking with dashes and gaps. --> + <xs:element ref="Sk:dash"/> + <!-- @element discrete Discrete wobbles the geometry randomly. --> + <xs:element ref="Sk:discrete"/> + <!-- @element emboss Emboss simulates a 3D light to show highlights and relief. --> + <xs:element ref="Sk:emboss"/> + <!-- @element linearGradient LinearGradient linearly ramps between two or more colors. --> + <xs:element ref="Sk:linearGradient"/> + <!-- @element maskFilter MaskFilter cancels a blur or emboss. --> + <xs:element ref="Sk:maskFilter"/> + <!-- @element pathEffect PathEffect cancels a discrete or dash. --> + <xs:element ref="Sk:pathEffect"/> + <!-- @element radialGradient RadialGradient radially ramps between two or more colors. --> + <xs:element ref="Sk:radialGradient"/> + <!-- @element shader Shader cancels a linear or radial gradient. --> + <xs:element ref="Sk:shader"/> + <!-- @element typeface Typeface chooses a font out of a font family. --> + <xs:element ref="Sk:typeface"/> + <!-- @element transparentShader TransparentShader ? [not sure what this is for] --> + <xs:element ref="Sk:transparentShader"/> + </xs:choice> + <!-- @attribute antiAlias AntiAlias uses gray shades to increase the definition of paths. --> + <xs:attribute name="antiAlias" type="Sk:Boolean"/> + <!-- @attribute ascent Ascent returns the height above the baseline defined by the font. --> + <xs:attribute name="ascent" type="Sk:Float"/> + <!-- @attribute color Color sets the paint to the color element with this ID. --> + <xs:attribute name="color" type="Sk:Color"/> + <!-- @attribute descent Descent returns the height below the baseline defined by thte font --> + <xs:attribute name="descent" type="Sk:Float"/> + <!-- @attribute fakeBold FakeBold enables a faked bold for text. --> + <xs:attribute name="fakeBold" type="Sk:Boolean"/> + <!-- @attribute filterType FilterType --> + <xs:attribute name="filterType" type="Sk:FilterType"/> + <!-- @attribute linearText LinearText uses the ideal path metrics at all sizes to describe text. --> + <xs:attribute name="linearText" type="Sk:Boolean"/> + <!-- @attribute maskFilter MaskFilter specifies a blur or emboss with this ID. --> + <xs:attribute name="maskFilter" type="Sk:MaskFilter"/> + <!-- @attribute measureText MeasureText(String) returns the width of the string in this paint. --> + <xs:attribute name="measureText" type="Sk:Float"/> + <!-- @attribute pathEffect PathEffect specifies a discrete or dash with this ID. --> + <xs:attribute name="pathEffect" type="Sk:PathEffect"/> + <!-- @attribute shader Shader specifies a gradient with this ID. --> + <xs:attribute name="shader" type="Sk:Shader"/> + <!-- @attribute strikeThru StrikeThru adds a line through the middle of drawn text. --> + <xs:attribute name="strikeThru" type="Sk:Boolean"/> + <!-- @attribute stroke Stroke draws the outline of geometry according to the pen attributes. + If style is also present, its setting overrides stroke. --> + <xs:attribute name="stroke" type="Sk:Boolean"/> + <!-- @attribute strokeCap StrokeCap is one of @pattern. --> + <xs:attribute name="strokeCap" type="Sk:Cap"/> + <!-- @attribute strokeJoin StrokeJoin is one of @pattern. --> + <xs:attribute name="strokeJoin" type="Sk:Join"/> + <!-- @attribute strokeMiter StrokeMiter limits the pen's joins on narrow angles. --> + <xs:attribute name="strokeMiter" type="Sk:Float"/> + <!-- @attribute strokeWidth StrokeWidth specifies the width of the pen. --> + <xs:attribute name="strokeWidth" type="Sk:Float"/> + <!-- @attribute style Style fills, strokes, or strokes and fills the geometry with the paint's color. --> + <xs:attribute name="style" type="Sk:Style"/> + <!-- @attribute textAlign TextAlign is one of @pattern. --> + <xs:attribute name="textAlign" type="Sk:Align"/> + <!-- @attribute textScaleX TextScaleX condenses or exapnds the text. --> + <xs:attribute name="textScaleX" type="Sk:Float"/> + <!-- @attribute textSize TextSize specifies the point size of the text. --> + <xs:attribute name="textSize" type="Sk:Float"/> + <!-- @attribute textSkewX TextSkewX draws the text obliquely. --> + <xs:attribute name="textSkewX" type="Sk:Float"/> + <!-- @attribute textTracking TextTracking specifies the space between letters. --> + <xs:attribute name="textTracking" type="Sk:Float"/> + <!-- @attribute typeface Typeface specifies a typeface element with this ID. --> + <xs:attribute name="typeface" type="Sk:Typeface"/> + <!-- @attribute underline Underline draws a line under the baseline of the text. --> + <xs:attribute name="underline" type="Sk:Boolean"/> + <!-- @attribute xfermode Xfermode specifies a transfer mode, one of @pattern. --> + <xs:attribute name="xfermode" type="Sk:Xfermode"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** path + Path creates a geometry out of lines and curves. + */ --> + <xs:element name="path"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <!-- @element addCircle Adds a circle to the path. --> + <xs:element ref="Sk:addCircle"/> + <!-- @element addOval Adds an oval to the path. --> + <xs:element ref="Sk:addOval"/> + <!-- @element addPath Adds another path to the path. --> + <xs:element ref="Sk:addPath"/> + <!-- @element addRoundRect Adds a rounded-corner rectangle to the path. --> + <xs:element ref="Sk:addRoundRect"/> + <!-- @element close Connects the last point on the path to the first. --> + <xs:element ref="Sk:close"/> + <!-- @element cubicTo Extends the path with a cubic curve. --> + <xs:element ref="Sk:cubicTo"/> + <!-- @element lineTo Extends the path with a line. --> + <xs:element ref="Sk:lineTo"/> + <!-- @element moveTo Starts a new path contour. --> + <xs:element ref="Sk:moveTo"/> + <!-- @element quadTo Extends the path with a quadratic curve. --> + <xs:element ref="Sk:quadTo"/> + <!-- @element rCubicTo Extends the path with a cubic curve expressed with relative offsets. --> + <xs:element ref="Sk:rCubicTo"/> + <!-- @element rLineTo Extends the path with a line expressed with relative offsets. --> + <xs:element ref="Sk:rLineTo"/> + <!-- @element rMoveTo Starts a new path contour relative to the path's last point. --> + <xs:element ref="Sk:rMoveTo"/> + <!-- @element rQuadTo Extends the path with a quadratic curve expressed with relative offsets. --> + <xs:element ref="Sk:rQuadTo"/> + </xs:choice> + <!-- @attribute d Creates a path using SVG path notation. --> + <xs:attribute name="d" type="Sk:String"/> + <!-- @attribute fillType One of @pattern. --> + <xs:attribute name="fillType" type="Sk:FillType"/> + <!-- @attribute length Returns the length of the path. --> + <xs:attribute name="length" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** pathEffect + PathEffect cancels any current path effect within the paint, such as dashing or discrete. + */ --> + <xs:element name="pathEffect"> + <xs:complexType> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** point + Point describes a two dimensional point in space. The point element can be added + to the display list and drawn. + */ --> + <xs:element name="point"> + <xs:complexType> + <!-- @attribute x The x coordinate of the point. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The y coordinate of the point. --> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** polygon + Polygon creates a geometry out of lines. Polygon is a specialization of path; element that + refers to a path can refer to a polygon also. A polygon specified through elements behaves identically + to a path. A polygon specified by the points attribute contains a single contour, and the contour is + automatically closed. + */ --> + <xs:element name="polygon"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <!-- @element close Connects the last point on the path to the first. --> + <xs:element ref="Sk:close"/> + <!-- @element addPath Adds another path to the path. --> + <xs:element ref="Sk:addPath"/> + <!-- @element lineTo Extends the path with a line. --> + <xs:element ref="Sk:lineTo"/> + <!-- @element moveTo Starts a new path contour. --> + <xs:element ref="Sk:moveTo"/> + <!-- @element rLineTo Extends the path with a line expressed with relative offsets. --> + <xs:element ref="Sk:rLineTo"/> + <!-- @element rMoveTo Starts a new path contour relative to the path's last point. --> + <xs:element ref="Sk:rMoveTo"/> + </xs:choice> + <!-- @attribute points An array of values that describe a sequence of points, compatible with SVG. --> + <xs:attribute name="points" type="Sk:FloatArray"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** polyline + Polyline creates a geometry out of lines. Polygon is a specialization of path; element that + refers to a path can refer to a polygon also. A polygon specified through elements behaves identically + to a path. A polygon specified by the points attribute contains a single contour, and the contour is + not automatically closed. + */ --> + <xs:element name="polyline"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <!-- @element close Connects the last point on the path to the first. --> + <xs:element ref="Sk:close"/> + <!-- @element addPath Adds another path to the path. --> + <xs:element ref="Sk:addPath"/> + <!-- @element lineTo Extends the path with a line. --> + <xs:element ref="Sk:lineTo"/> + <!-- @element moveTo Starts a new path contour. --> + <xs:element ref="Sk:moveTo"/> + <!-- @element rLineTo Extends the path with a line expressed with relative offsets. --> + <xs:element ref="Sk:rLineTo"/> + <!-- @element rMoveTo Starts a new path contour relative to the path's last point. --> + <xs:element ref="Sk:rMoveTo"/> + </xs:choice> + <!-- @attribute points An array of values that describe a sequence of points, compatible with SVG. --> + <xs:attribute name="points" type="Sk:FloatArray"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** polyToPoly + PolyToPoly creates a matrix which maps points proportionally from one polygon to the other. + */ --> + <xs:element name="polyToPoly"> + <xs:complexType> + <xs:choice maxOccurs="2"> + <xs:element ref="Sk:polygon"/> + </xs:choice> + <!-- @attribute source The polygon to map from.. --> + <xs:attribute name="source" type="Sk:polygon"/> + <!-- @attribute destination The polygon to map to.. --> + <xs:attribute name="destination" type="Sk:polygon"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** post + Post activates an event. The event can trigger one or more actions, and can carry a data payload. + */ --> + <xs:element name="post"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <xs:element ref="Sk:data"/> + </xs:choice> + <!-- @attribute delay Time in seconds that must elapse before the target event is activated. --> + <xs:attribute name="delay" type="Sk:MSec"/> + <!-- @attribute mode One of @pattern. @patternDescription --> + <xs:attribute name="mode" type="Sk:EventMode"/> + <!-- @attribute sink The optional named EventSink to direct the event to. --> + <xs:attribute name="sink" type="Sk:String"/> + <!-- @attribute target The ID of the user event to trigger. --> + <xs:attribute name="target" type="Sk:String"/> + <!-- @attribute type The name of the external event to post. --> + <xs:attribute name="type" type="Sk:String"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** quadTo + QuadTo adds a quadratic curve to a path. + */ --> + <xs:element name="quadTo"> + <xs:complexType> + <!-- @attribute x1 The x position of the off-curve point. --> + <xs:attribute name="x1" type="Sk:Float"/> + <!-- @attribute x2 The x position of the final point. --> + <xs:attribute name="x2" type="Sk:Float"/> + <!-- @attribute y1 The y position of the off-curve point. --> + <xs:attribute name="y1" type="Sk:Float"/> + <!-- @attribute y2 The y position of the final point. --> + <xs:attribute name="y2" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** rCubicTo + RCubicTo adds a cubic to the path, using the last point in the path as the first point of the cubic. THe + added points are offsets from the last point in the path. + */ --> + <xs:element name="rCubicTo"> + <xs:complexType> + <!-- @attribute x1 The x offset of the first off-curve point. --> + <xs:attribute name="x1" type="Sk:Float"/> + <!-- @attribute x2 The x offset of the second off-curve point. --> + <xs:attribute name="x2" type="Sk:Float"/> + <!-- @attribute x3 The x offset of the final on-curve point. --> + <xs:attribute name="x3" type="Sk:Float"/> + <!-- @attribute y1 The y offset of the first off-curve point. --> + <xs:attribute name="y1" type="Sk:Float"/> + <!-- @attribute y2 The y offset of the second off-curve point. --> + <xs:attribute name="y2" type="Sk:Float"/> + <!-- @attribute y3 The y offset of the final on-curve point. --> + <xs:attribute name="y3" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** rLineTo + RLineTo adds a line from the last point in a path to the specified point. The specified + point is relative to the last point in the path. + */ --> + <xs:element name="rLineTo"> + <xs:complexType> + <!-- @attribute x The final path x coordinate. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The final path y coordinate. --> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** rMoveTo + RMoveTo specifies the first point in a path contour. The specified + point is relative to the last point in the path. + */ --> + <xs:element name="rMoveTo"> + <xs:complexType> + <!-- @attribute x The point's x coordinate. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The point's y coordinate. --> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** rQuadTo + RQuadTo adds a quadratic curve to a path. The quadratic + points are relative to the last point in the path. + */ --> + <xs:element name="rQuadTo"> + <xs:complexType> + <!-- @attribute x1 The x position of the off-curve point. --> + <xs:attribute name="x1" type="Sk:Float"/> + <!-- @attribute x2 The x position of the final point. --> + <xs:attribute name="x2" type="Sk:Float"/> + <!-- @attribute y1 The y position of the off-curve point. --> + <xs:attribute name="y1" type="Sk:Float"/> + <!-- @attribute y2 The y position of the final point. --> + <xs:attribute name="y2" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** radialGradient + RadialGradient sets the paint shader to ramp between two or more colors in concentric circles. + */ --> + <xs:element name="radialGradient"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <xs:element ref="Sk:color"/> + <xs:element ref="Sk:matrix"/> + </xs:choice> + <!-- @attribute matrix Matrix applies a 3x3 transform to the gradient. --> + <xs:attribute name="matrix" type="Sk:Matrix"/> + <!-- @attribute tileMode One of @pattern. @patternDescription --> + <xs:attribute name="tileMode" type="Sk:TileMode"/> + <!-- @attribute center The center point of the radial gradient. --> + <xs:attribute name="center" type="Sk:Point"/> + <!-- @attribute offsets An optional array of values used to bias the colors. The first entry + in the array must be 0.0, the last must be 1.0, and intermediate values must ascend. --> + <xs:attribute name="offsets" type="Sk:FloatArray"/> + <!-- @attribute radius The distance from the first color to the last color. --> + <xs:attribute name="radius" type="Sk:Float"/> + <!-- @attribute unitMapper A script that returns the mapping for [0,1] for the gradient. + The script can use the predefined variable 'unit' to compute the mapping. For instance, + "unit*unit" squares the value (while still keeping it in the range of [0,1].) The computed number + is pinned to from 0 to 1 after the script is executed. --> + <xs:attribute name="unitMapper" type="Sk:String"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** random + Random generates a random number, from min to max. Each time the random attribute is + read, a new random number is generated. + */ --> + <xs:element name="random"> + <xs:complexType> + <!-- @attribute blend The random bias from 0.0 to 1.0. + 0.0 biias the number towards the start and end of the range. + 1.0 (the default) generates a linear distribution.--> + <xs:attribute name="blend" type="Sk:Float"/> + <!-- @attribute max The largest value to generate. --> + <xs:attribute name="max" type="Sk:Float"/> + <!-- @attribute min The smallest value to generate. --> + <xs:attribute name="min" type="Sk:Float"/> + <!-- @attribute random The generated value. --> + <xs:attribute name="random" type="Sk:Float"/> + <!-- @attribute seed The random seed. Identical seeds generate the same series of + numbers. --> + <xs:attribute name="seed" type="Sk:Int"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** rect + Rect describes a bounding box. + The width and height attribute compute the rectangle's right and bottom edges when the rectangle + description is first seen. Animating the rectangle's left or top will not recompute the right or bottom + if the width or height have been specified. + */ --> + <xs:element name="rect"> + <xs:complexType> + <!-- @attribute bottom The bottom edge of the rectangle. --> + <xs:attribute name="bottom" type="Sk:Float"/> + <!-- @attribute height The height of the rectangle. Setting height computes the + bottom attribute from the top attribute. --> + <xs:attribute name="height" type="Sk:Float"/> + <!-- @attribute left The left edge of the rectangle. --> + <xs:attribute name="left" type="Sk:Float"/> + <!-- @attribute needsRedraw Set to true if last draw was visible. --> + <xs:attribute name="needsRedraw" type="Sk:Boolean"/> + <!-- @attribute right The right edge of the rectangle. --> + <xs:attribute name="right" type="Sk:Float"/> + <!-- @attribute top The top edge of the rectangle. --> + <xs:attribute name="top" type="Sk:Float"/> + <!-- @attribute width The width of the rectangle. --> + <xs:attribute name="width" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** rectToRect + RectToRect adds a matrix to map one rectangle's coordinates to another. + */ --> + <xs:element name="rectToRect"> + <xs:complexType> + <xs:choice maxOccurs="2"> + <xs:element ref="Sk:rect"/> + </xs:choice> + <!-- @attribute source The rectangle to map from. --> + <xs:attribute name="source" type="Sk:rect"/> + <!-- @attribute destination The rectangle to map to. --> + <xs:attribute name="destination" type="Sk:rect"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** remove + Remove an item from the display list. + If where is specified, the first occurance of where in the display list is removed. + If offset and where are specified, the element at where plus offset is removed. + A positive offset without where removes the element at the start of the list plus offset. + A negative offset without where removes the element at the end of the list minus offset. + */ --> + <xs:element name="remove"> + <xs:complexType> + <!-- @attribute delete If true, reverse the action of apply's attribute mode="create". + (Experimental.) --> + <xs:attribute name="delete" type="Sk:Boolean"/> + <!-- @attribute offset The destination position using the rules listed above. --> + <xs:attribute name="offset" type="Sk:Int"/> + <!-- @attribute where The ID of the first display list entry to remove. --> + <xs:attribute name="where" type="Sk:Drawable"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** replace + Replace an item in the display list. + If where is specified, the first occurance of where in the display list is replaced by use. + If offset and where are specified, the element at where plus offset is replaced by use. + A positive offset without where replaces the element at the start of the list plus offset. + A negative offset without where replaces the element at the end of the list minus offset. + */ --> + <xs:element name="replace"> + <xs:complexType> + <!-- @attribute mode Has no effect. --> + <xs:attribute name="mode" type="Sk:AddMode"/> + <!-- @attribute offset The destination position using the rules listed above. --> + <xs:attribute name="offset" type="Sk:Int"/> + <!-- @attribute use The element to be added to the display list.. --> + <xs:attribute name="use" type="Sk:Drawable"/> + <!-- @attribute where The ID of the first display list entry to remove. --> + <xs:attribute name="where" type="Sk:Drawable"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** rotate + Rotate creates a matrix that rotates a unit vector about a center point, and concatenated + with the containing matrix. + */ --> + <xs:element name="rotate"> + <xs:complexType> + <!-- @attribute center A point the rotation is centered about; by default, [0.0, 0.0]. --> + <xs:attribute name="center" type="Sk:Point"/> + <!-- @attribute degrees The rotation in degrees. --> + <xs:attribute name="degrees" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** roundRect + RoundRect creates a rectangle with rounded corners. The rounded corners are specified by + two axes, which describe an quarter-section of the oval which is used in each corner. + The width and height attribute compute the rectangle's right and bottom edges when the rectangle + description is first seen. Animating the rectangle's left or top will not recompute the right or bottom + if the width or height have been specified. + */ --> + <xs:element name="roundRect"> + <xs:complexType> + <!-- @attribute bottom The bottom edge of the rectangle. --> + <xs:attribute name="bottom" type="Sk:Float"/> + <!-- @attribute height The height of the rectangle. Setting height computes the + bottom attribute from the top attribute. --> + <xs:attribute name="height" type="Sk:Float"/> + <!-- @attribute left The left edge of the rectangle. --> + <xs:attribute name="left" type="Sk:Float"/> + <!-- @attribute needsRedraw Set to true if last draw was visible. --> + <xs:attribute name="needsRedraw" type="Sk:Boolean"/> + <!-- @attribute right The right edge of the rectangle. --> + <xs:attribute name="right" type="Sk:Float"/> + <!-- @attribute top The top edge of the rectangle. --> + <xs:attribute name="top" type="Sk:Float"/> + <!-- @attribute rx The radius of the corners on the x axis. --> + <xs:attribute name="rx" type="Sk:Float"/> + <!-- @attribute ry The radius of the corners on the y axis. --> + <xs:attribute name="ry" type="Sk:Float"/> + <!-- @attribute width The width of the rectangle. Setting width computes the + right attribute from the left attribute. --> + <xs:attribute name="width" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** save + The save element collects a series of elements into a group. The state of the paint and + canvas are saved, so that edits to the paint and canvas within the group are restored + to their original value at the end of the group. + The save element can be referenced + or defined within elements, like apply, which operate on any kind of element. Groups + may contain groups. + */ --> + <xs:element name="save"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <xs:element ref="Sk:add"/> + <xs:element ref="Sk:apply"/> + <xs:element ref="Sk:array"/> + <xs:element ref="Sk:bitmap"/> + <xs:element ref="Sk:boolean"/> + <xs:element ref="Sk:bounds"/> + <!-- <xs:element ref="Sk3D:camera"/> --> + <xs:element ref="Sk:clear"/> + <xs:element ref="Sk:clip"/> + <xs:element ref="Sk:color"/> + <xs:element ref="Sk:drawTo"/> + <xs:element ref="Sk:float"/> + <xs:element ref="Sk:full"/> + <xs:element ref="Sk:group"/> + <xs:element ref="Sk:hitClear"/> + <xs:element ref="Sk:hitTest"/> + <xs:element ref="Sk:image"/> + <xs:element ref="Sk:int"/> + <xs:element ref="Sk:line"/> + <xs:element ref="Sk:matrix"/> + <xs:element ref="Sk:move"/> + <xs:element ref="Sk:oval"/> + <xs:element ref="Sk:paint"/> + <!-- <xs:element ref="Sk:patch"/> --> + <xs:element ref="Sk:path"/> + <xs:element ref="Sk:point"/> + <xs:element ref="Sk:polygon"/> + <xs:element ref="Sk:polyline"/> + <xs:element ref="Sk:post"/> + <xs:element ref="Sk:random"/> + <xs:element ref="Sk:rect"/> + <xs:element ref="Sk:remove"/> + <xs:element ref="Sk:replace"/> + <xs:element ref="Sk:roundRect"/> + <xs:element ref="Sk:save"/> + <xs:element ref="Sk:set"/> + <xs:element ref="Sk:snapshot"/> + <xs:element ref="Sk:string"/> + <xs:element ref="Sk:text"/> + <xs:element ref="Sk:textBox"/> + <xs:element ref="Sk:textOnPath"/> + <xs:element ref="Sk:textToPath"/> + </xs:choice> + <!-- @attribute condition If present and zero, the contained elements are ignored. --> + <xs:attribute name="condition" type="Sk:DynamicString"/> + <!-- @attribute enableCondition If present and zero, the contained elements are ignored + when enabled. --> + <xs:attribute name="enableCondition" type="Sk:DynamicString"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** scale + Scale creates a matrix that scales a unit vector about a center point, and concatenated + with the containing matrix. + */ --> + <xs:element name="scale"> + <xs:complexType> + <!-- @attribute center A point the scale is centered about; by default, [0.0, 0.0]. --> + <xs:attribute name="center" type="Sk:Point"/> + <!-- @attribute x The factor all x values are scaled by; by default, 1.0. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The factor all y values are scaled by; by default, 1.0. --> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** screenplay + Screenplay contains all events and elements referenced by the events. + A document may only contain a single screenplay element. + */ --> + <xs:element name="screenplay"> + <xs:complexType> + <xs:choice maxOccurs="unbounded" > + <xs:element ref="Sk:add"/> + <xs:element ref="Sk:apply"/> + <xs:element ref="Sk:array"/> + <xs:element ref="Sk:bitmap"/> + <xs:element ref="Sk:boolean"/> + <xs:element ref="Sk:bounds"/> + <!-- <xs:element ref="Sk3D:camera"/> --> + <xs:element ref="Sk:clear"/> + <xs:element ref="Sk:clip"/> + <xs:element ref="Sk:color"/> + <xs:element ref="Sk:drawTo"/> + <xs:element ref="Sk:event"/> + <xs:element ref="Sk:float"/> + <xs:element ref="Sk:full"/> + <xs:element ref="Sk:group"/> + <xs:element ref="Sk:hitClear"/> + <xs:element ref="Sk:hitTest"/> + <xs:element ref="Sk:image"/> + <xs:element ref="Sk:include"/> + <xs:element ref="Sk:int"/> + <xs:element ref="Sk:line"/> + <xs:element ref="Sk:matrix"/> + <xs:element ref="Sk:move"/> + <xs:element ref="Sk:movie"/> + <xs:element ref="Sk:oval"/> + <xs:element ref="Sk:paint"/> + <!-- <xs:element ref="Sk:patch"/> --> + <xs:element ref="Sk:path"/> + <xs:element ref="Sk:point"/> + <xs:element ref="Sk:polygon"/> + <xs:element ref="Sk:polyline"/> + <xs:element ref="Sk:post"/> + <xs:element ref="Sk:random"/> + <xs:element ref="Sk:rect"/> + <xs:element ref="Sk:remove"/> + <xs:element ref="Sk:replace"/> + <xs:element ref="Sk:roundRect"/> + <xs:element ref="Sk:save"/> + <xs:element ref="Sk:set"/> + <xs:element ref="Sk:snapshot"/> + <xs:element ref="Sk:string"/> + <xs:element ref="Sk:text"/> + <xs:element ref="Sk:textBox"/> + <xs:element ref="Sk:textOnPath"/> + <xs:element ref="Sk:textToPath"/> + </xs:choice> + <!-- @attribute time The time of the draw (readable from script; not part of the document XML) --> + <xs:attribute name="time" type="Sk:MSec"/> + </xs:complexType> + </xs:element> + + <!-- /** set + Set animates the target element's attribute directly to the specified value. + */ --> + <xs:element name="set"> + <xs:complexType> + <!-- @attribute begin An optional offset that must elapse before the animation begins. The apply + begin attribute is added to any animator's begin attribute. --> + <xs:attribute name="begin" type="Sk:MSec"/> + <!-- @attribute dur The duration of the animation in milliseconds. --> + <xs:attribute name="dur" type="Sk:MSec"/> + <!-- @attribute dynamic If true, restart the animation if any of the simple values the + 'lval' or 'to' attributes reference are changed. Simple values are contained by the array, boolean, float, int, + and string elements. --> + <!-- @attribute dynamic [Depreciated.] --> + <xs:attribute name="dynamic" type="Sk:Boolean" /> + <!-- @attribute field The attribute to animate. --> + <xs:attribute name="field" type="Sk:String"/> + <!-- @attribute formula A script to execute over time to compute the field's value. Typically, + the fomula is a script expression which includes a reference to the time attribute of the + containing apply element. --> + <xs:attribute name="formula" type="Sk:DynamicString"/> + <!-- @attribute lval An expression evaluating to the attribute to animate. + If present, lval overrides 'field'. The expression is typically an array element, + e.g. lval="x[y]" . --> + <xs:attribute name="lval" type="Sk:DynamicString"/> + <!-- @attribute reset If true, the computed value is the initial value after the + animation is complete. If false, or by default, the computed value is the final value + after the animation is complete. --> + <xs:attribute name="reset" type="Sk:Boolean"/> + <!-- @attribute step When apply's attribute mode="immediate" or "create", the step attribute can be read by + script to determine the current animation iteration. --> + <xs:attribute name="step" type="Sk:Int" /> + <!-- @attribute target The element to animate. By default, the element contained by the apply + or referenced by the apply's scope attribute is the animate target. --> + <xs:attribute name="target" type="Sk:DynamicString"/> + <!-- @attribute to The ending value (requires a 'from' attribute) --> + <xs:attribute name="to" type="Sk:DynamicString"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** skew + Skew creates a matrix that skews a unit vector about a center point, and concatenated + with the containing matrix. + */ --> + <xs:element name="skew"> + <xs:complexType> + <!-- @attribute center A point the skew is centered about; by default, [0.0, 0.0]. --> + <xs:attribute name="center" type="Sk:Point"/> + <!-- @attribute x The factor all x values are skewed by; by default, 0.0. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The factor all y values are skewed by; by default, 0.0. --> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** snapshot + Snapshot creates an image file containing the display list. + */ --> + <xs:element name="snapshot"> + <xs:complexType> + <!-- @attribute filename The name of the file to generate. --> + <xs:attribute name="filename" type="Sk:String"/> + <!-- @attribute quality The quality of the image, from 0 to 100. --> + <xs:attribute name="quality" type="Sk:Float"/> + <!-- @attribute sequence Set to true to number the filenames sequentially. --> + <xs:attribute name="sequence" type="Sk:Boolean"/> + <!-- @attribute type One of @pattern. The type of encoding to use. --> + <xs:attribute name="type" type="Sk:BitmapEncoding"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** string + String contains an array of characters. + */ --> + <xs:element name="string" > + <xs:complexType> + <!-- @attribute length The number of characters in the string (read only). --> + <xs:attribute name="length" type="Sk:Int"/> + <!-- @attribute slice An ECMAScript compatible function that returns part of the string. --> + <xs:attribute name="slice" type="Sk:String"/> + <!-- @attribute value The string itself. --> + <xs:attribute name="value" type="Sk:String"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** text + A drawable string with a position. + */ --> + <xs:element name="text"> + <xs:complexType> + <!-- @attribute length The number of characters in the string (read only). --> + <xs:attribute name="length" type="Sk:Int"/> + <!-- @attribute text The string itself. --> + <xs:attribute name="text" type="Sk:String"/> + <!-- @attribute x The x coordinate of the string. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The y coordinate of the string. --> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** textBox + A drawable string fit into a box. + */ --> + <xs:element name="textBox" > + <xs:complexType> + <!-- @attribute bottom The bottom of the box. --> + <xs:attribute name="bottom" type="Sk:Float"/> + <!-- @attribute height The height of the box, computed from top and bottom. --> + <xs:attribute name="height" type="Sk:Float"/> + <!-- @attribute left The left side of the box. --> + <xs:attribute name="left" type="Sk:Float"/> + <!-- @attribute mode One of @pattern. --> + <xs:attribute name="mode" type="Sk:TextBoxMode"/> + <!-- @attribute needsRedraw Set to true if last draw was visible. --> + <xs:attribute name="needsRedraw" type="Sk:Boolean"/> + <!-- @attribute right The right side of the box. --> + <xs:attribute name="right" type="Sk:Float"/> + <!-- @attribute spacingAdd The extra spacing between lines. --> + <xs:attribute name="spacingAdd" type="Sk:Float"/> + <!-- @attribute spacingAlign One of @pattern. --> + <xs:attribute name="spacingAlign" type="Sk:TextBoxAlign"/> + <!-- @attribute spacingMul The line spacing scaled by the text height. --> + <xs:attribute name="spacingMul" type="Sk:Float"/> + <!-- @attribute text The text to fit to the box. --> + <xs:attribute name="text" type="Sk:String"/> + <!-- @attribute top The top of the box. --> + <xs:attribute name="top" type="Sk:Float"/> + <!-- @attribute width The width of the box, computed from left and right. --> + <xs:attribute name="width" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** textOnPath + TextOnPath specifies the baseline for a string of text with a path. + */ --> + <xs:element name="textOnPath"> + <xs:complexType> + <xs:choice > + <xs:element ref="Sk:text" minOccurs="0" /> + <xs:element ref="Sk:path" minOccurs="0" /> + </xs:choice> + <!-- @attribute offset The distance along the path to place the first text character. --> + <xs:attribute name="offset" type="Sk:Float"/> + <!-- @attribute path The baseline of the text. --> + <xs:attribute name="path" type="Sk:Path"/> + <!-- @attribute text The text to place along the path. --> + <xs:attribute name="text" type="Sk:Text"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** textToPath + TextToPath sets the path to the contours described by the text's glyphs, using the current paint. + */ --> + <xs:element name="textToPath"> + <xs:complexType> + <xs:choice > + <xs:element ref="Sk:text" minOccurs="0" /> + <xs:element ref="Sk:paint" minOccurs="0" /> + <xs:element ref="Sk:path" minOccurs="0" /> + </xs:choice> + <!-- @attribute paint The paint selects the text font, size and other text properties. --> + <xs:attribute name="paint" type="Sk:Paint"/> + <!-- @attribute path The reference to the path element where the text as path is stored. --> + <xs:attribute name="path" type="Sk:Path"/> + <!-- @attribute text The reference to the text element to turn into a path. --> + <xs:attribute name="text" type="Sk:Text"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** translate + Translate concatenates a translation-only matrix onto the current matrix. + */ --> + <xs:element name="translate"> + <xs:complexType> + <!-- @attribute x The translation in x. --> + <xs:attribute name="x" type="Sk:Float"/> + <!-- @attribute y The translation in y. --> + <xs:attribute name="y" type="Sk:Float"/> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** transparentShader + TransparentShader uses the background for its paint. Works well with emboss. + */ --> + <xs:element name="transparentShader"> + <xs:complexType> + <xs:attribute name="id" type="xs:ID"/> + </xs:complexType> + </xs:element> + + <!-- /** typeface + Typeface describes the text font. + */ --> + <xs:element name="typeface"> + <xs:complexType> + <!-- @attribute fontName The name of the font. --> + <xs:attribute name="fontName" type="Sk:String"/> + </xs:complexType> + </xs:element> + +</xs:schema> + diff --git a/libs/graphics/animator/SkAnimateSchema.xsx b/libs/graphics/animator/SkAnimateSchema.xsx new file mode 100644 index 0000000000..ceb7d890c9 --- /dev/null +++ b/libs/graphics/animator/SkAnimateSchema.xsx @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!--This file is auto-generated by the XML Schema Designer. It holds layout information for components on the designer surface.-->
+<XSDDesignerLayout /> diff --git a/libs/graphics/animator/SkAnimateSet.cpp b/libs/graphics/animator/SkAnimateSet.cpp new file mode 100644 index 0000000000..4de2de5600 --- /dev/null +++ b/libs/graphics/animator/SkAnimateSet.cpp @@ -0,0 +1,81 @@ +#include "SkAnimateSet.h" +#include "SkAnimateMaker.h" +#include "SkAnimateProperties.h" +#include "SkParse.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkSet::fInfo[] = { + SK_MEMBER(begin, MSec), + SK_MEMBER(dur, MSec), + SK_MEMBER_PROPERTY(dynamic, Boolean), + SK_MEMBER(field, String), +// SK_MEMBER(formula, DynamicString), + SK_MEMBER(lval, DynamicString), +// SK_MEMBER_PROPERTY(reset, Boolean), + SK_MEMBER_PROPERTY(step, Int), + SK_MEMBER(target, DynamicString), + SK_MEMBER(to, DynamicString) +}; + +#endif + +DEFINE_GET_MEMBER(SkSet); + +SkSet::SkSet() { + dur = 1; +} + +#ifdef SK_DUMP_ENABLED +void SkSet::dump(SkAnimateMaker* maker) { + INHERITED::dump(maker); + if (dur != 1) { +#ifdef SK_CAN_USE_FLOAT + SkDebugf("dur=\"%g\" ", SkScalarToFloat(SkScalarDiv(dur,1000))); +#else + SkDebugf("dur=\"%x\" ", SkScalarDiv(dur,1000)); +#endif + } + //don't want double />\n's + SkDebugf("/>\n"); + +} +#endif + +void SkSet::refresh(SkAnimateMaker& maker) { + fFieldInfo->setValue(maker, &fValues, 0, fFieldInfo->fCount, nil, + fFieldInfo->getType(), to); +} + +void SkSet::onEndElement(SkAnimateMaker& maker) { + if (resolveCommon(maker) == false) + return; + if (fFieldInfo == nil) { + maker.setErrorCode(SkDisplayXMLParserError::kFieldNotInTarget); + return; + } + fReset = dur != 1; + SkDisplayTypes outType = fFieldInfo->getType(); + int comps = outType == SkType_String || outType == SkType_DynamicString ? 1 : + fFieldInfo->getSize((const SkDisplayable*) fTarget) / sizeof(int); + if (fValues.getType() == SkType_Unknown) { + fValues.setType(outType); + fValues.setCount(comps); + if (outType == SkType_String || outType == SkType_DynamicString) + fValues[0].fString = SkNEW(SkString); + else + memset(fValues.begin(), 0, fValues.count() * sizeof(fValues.begin()[0])); + } else { + SkASSERT(fValues.getType() == outType); + if (fFieldInfo->fType == SkType_Array) + comps = fValues.count(); + else + SkASSERT(fValues.count() == comps); + } + if (formula.size() > 0) { + comps = 1; + outType = SkType_MSec; + } + fFieldInfo->setValue(maker, &fValues, fFieldOffset, comps, this, outType, formula.size() > 0 ? formula : to); + fComponents = fValues.count(); +} diff --git a/libs/graphics/animator/SkAnimateSet.h b/libs/graphics/animator/SkAnimateSet.h new file mode 100644 index 0000000000..476459f5b7 --- /dev/null +++ b/libs/graphics/animator/SkAnimateSet.h @@ -0,0 +1,19 @@ +#ifndef SkAnimateSet_DEFINED +#define SkAnimateSet_DEFINED + +#include "SkAnimate.h" + +class SkSet : public SkAnimate { + DECLARE_MEMBER_INFO(Set); + SkSet(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual void onEndElement(SkAnimateMaker& ); + virtual void refresh(SkAnimateMaker& ); +private: + typedef SkAnimate INHERITED; +}; + +#endif // SkAnimateSet_DEFINED + diff --git a/libs/graphics/animator/SkAnimator.cpp b/libs/graphics/animator/SkAnimator.cpp new file mode 100644 index 0000000000..17f6855355 --- /dev/null +++ b/libs/graphics/animator/SkAnimator.cpp @@ -0,0 +1,705 @@ +#include "SkAnimator.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkDisplayApply.h" +#include "SkDisplayMovie.h" +#include "SkDisplayTypes.h" +#include "SkDisplayXMLParser.h" +#include "SkStream.h" +#include "SkScript.h" +#include "SkScript2.h" // compiled script experiment +#include "SkSystemEventTypes.h" +#include "SkTypedArray.h" +#ifdef ANDROID +#include "SkDrawExtraPathEffect.h" +#endif +#ifdef SK_DEBUG +#include "SkTime.h" +#endif + +#if defined SK_BUILD_FOR_WIN32 && defined SK_DEBUG + #define _static + extern const char gMathPrimerText[]; + extern const char gMathPrimerBinary[]; +#else + #define _static static +#endif + +#if !defined SK_BUILD_FOR_BREW || defined SK_DEBUG + _static const char gMathPrimerText[] = + "<screenplay>" + "<Math id=\"Math\"/>" + "<Number id=\"Number\"/>" + "</screenplay>"; +#endif + +#if defined SK_BUILD_FOR_BREW || defined SK_DEBUG + _static const char gMathPrimerBinary[] = + "\x0Ascreenplay\x04Mathbid\x04Math@@"; // !!! now out of date -- does not include Number +#endif + +#if defined SK_BUILD_FOR_BREW + #define gMathPrimer gMathPrimerBinary +#else + #define gMathPrimer gMathPrimerText +#endif + +SkAnimator::SkAnimator() : fMaker(nil) { + initialize(); +} + +SkAnimator::~SkAnimator() { + SkDELETE(fMaker); +} + +void SkAnimator::addExtras(SkExtras* extras) { + *fMaker->fExtras.append() = extras; +} + +bool SkAnimator::appendStream(SkStream* stream) { + return decodeStream(stream); +} + +bool SkAnimator::decodeMemory(const void* buffer, size_t size) +{ + fMaker->fFileName.reset(); + SkDisplayXMLParser parser(*fMaker); + return parser.parse((const char*)buffer, size); +} + +bool SkAnimator::decodeStream(SkStream* stream) +{ + SkDisplayXMLParser parser(*fMaker); + bool result = parser.parse(*stream); + fMaker->setErrorString(); + return result; +} + +bool SkAnimator::decodeDOM(const SkDOM& dom, const SkDOMNode* node) +{ + fMaker->fFileName.reset(); + SkDisplayXMLParser parser(*fMaker); + return parser.parse(dom, node); +} + +bool SkAnimator::decodeURI(const char uri[]) { +// SkDebugf("animator decode %s\n", uri); + SkStream* stream = SkStream::GetURIStream(fMaker->fPrefix.c_str(), uri); + SkAutoTDelete<SkStream> autoDel(stream); + setURIBase(uri); + return decodeStream(stream); +} + +bool SkAnimator::doCharEvent(SkUnichar code) { + if (code == 0) + return false; + struct SkEventState state; + state.fCode = code; + fMaker->fEnableTime = fMaker->getAppTime(); + bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyChar, &state); + fMaker->notifyInval(); + return result; +} + +bool SkAnimator::doClickEvent(int clickState, SkScalar x, SkScalar y) { + SkASSERT(clickState >= 0 && clickState <= 2); + struct SkEventState state; + state.fX = x; + state.fY = y; + fMaker->fEnableTime = fMaker->getAppTime(); + bool result = fMaker->fEvents.doEvent(*fMaker, + clickState == 0 ? SkDisplayEvent::kMouseDown : + clickState == 1 ? SkDisplayEvent::kMouseDrag : + SkDisplayEvent::kMouseUp, &state); + fMaker->notifyInval(); + return result; +} + +bool SkAnimator::doKeyEvent(SkKey code) { + if (code == 0) + return false; + struct SkEventState state; + state.fCode = code; + fMaker->fEnableTime = fMaker->getAppTime(); + bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyPress, &state); + fMaker->notifyInval(); + return result; +} + +bool SkAnimator::doKeyUpEvent(SkKey code) { + if (code == 0) + return false; + struct SkEventState state; + state.fCode = code; + fMaker->fEnableTime = fMaker->getAppTime(); + bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyPressUp, &state); + fMaker->notifyInval(); + return result; +} + +bool SkAnimator::doUserEvent(const SkEvent& evt) { + fMaker->fEnableTime = fMaker->getAppTime(); + return onEvent(evt); +} + +SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkPaint* paint, SkMSec time) { + if (paint == nil) + return draw(canvas, time); + fMaker->fScreenplay.time = time; + fMaker->fCanvas = canvas; + fMaker->fPaint = paint; + fMaker->fCanvas->getPixels(&fMaker->fBitmap); + fMaker->fDisplayList.fHasUnion = false; + int result = fMaker->fDisplayList.draw(*fMaker, time); + if (result) + result += fMaker->fDisplayList.fHasUnion; + return (DifferenceType) result; +} + +SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkMSec time) { + SkPaint paint; + return draw(canvas, &paint, time); +} + +#ifdef SK_DEBUG +void SkAnimator::eventDone(const SkEvent& ) { +} +#endif + +bool SkAnimator::findClickEvent(SkScalar x, SkScalar y) { + struct SkEventState state; + state.fDisable = true; + state.fX = x; + state.fY = y; + fMaker->fEnableTime = fMaker->getAppTime(); + bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kMouseDown, &state); + fMaker->notifyInval(); + return result; +} + +const SkAnimator* SkAnimator::getAnimator(const SkDisplayable* displayable) const { + if (displayable->getType() != SkType_Movie) + return nil; + const SkDisplayMovie* movie = (const SkDisplayMovie*) displayable; + return movie->getAnimator(); +} + +const SkDisplayable* SkAnimator::getElement(const char* id) { + SkDisplayable* element; + if (fMaker->find(id, &element) == false) + return nil; + return (const SkDisplayable*) element; +} + +SkElementType SkAnimator::getElementType(const SkDisplayable* ae) { + SkDisplayable* element = (SkDisplayable*) ae; + const SkMemberInfo* info = SkDisplayType::GetMembers(fMaker, element->getType(), nil); + return (SkElementType) SkDisplayType::Find(fMaker, info); +} + +SkElementType SkAnimator::getElementType(const char* id) { + const SkDisplayable* element = getElement(id); + return getElementType(element); +} + +const SkMemberInfo* SkAnimator::getField(const SkDisplayable* ae, const char* field) { + SkDisplayable* element = (SkDisplayable*) ae; + const SkMemberInfo* info = element->getMember(field); + return (const SkMemberInfo*) info; +} + +const SkMemberInfo* SkAnimator::getField(const char* elementID, const char* field) { + const SkDisplayable* element = getElement(elementID); + return getField(element, field); +} + +SkFieldType SkAnimator::getFieldType(const SkMemberInfo* ai) { + const SkMemberInfo* info = (const SkMemberInfo*) ai; + return (SkFieldType) info->getType(); +} + +SkFieldType SkAnimator::getFieldType(const char* id, const char* fieldID) { + const SkMemberInfo* field = getField(id, fieldID); + return getFieldType(field); +} + + static bool getArrayCommon(const SkDisplayable* ae, const SkMemberInfo* ai, + int index, SkOperand* operand, SkDisplayTypes type) { + const SkDisplayable* element = (const SkDisplayable*) ae; + const SkMemberInfo* info = (const SkMemberInfo*) ai; + SkASSERT(info->fType == SkType_Array); + return info->getArrayValue(element, index, operand); +} + +int32_t SkAnimator::getArrayInt(const SkDisplayable* ae, + const SkMemberInfo* ai, int index) { + SkOperand operand; + bool result = getArrayCommon(ae, ai, index, &operand, SkType_Int); + return result ? operand.fS32 : SK_NaN32; +} + +int32_t SkAnimator::getArrayInt(const char* id, const char* fieldID, int index) { + const SkDisplayable* element = getElement(id); + if (element == nil) + return SK_NaN32; + const SkMemberInfo* field = getField(element, fieldID); + if (field == nil) + return SK_NaN32; + return getArrayInt(element, field, index); +} + +SkScalar SkAnimator::getArrayScalar(const SkDisplayable* ae, + const SkMemberInfo* ai, int index) { + SkOperand operand; + bool result = getArrayCommon(ae, ai, index, &operand, SkType_Float); + return result ? operand.fScalar : SK_ScalarNaN; +} + +SkScalar SkAnimator::getArrayScalar(const char* id, const char* fieldID, int index) { + const SkDisplayable* element = getElement(id); + if (element == nil) + return SK_ScalarNaN; + const SkMemberInfo* field = getField(element, fieldID); + if (field == nil) + return SK_ScalarNaN; + return getArrayScalar(element, field, index); +} + +const char* SkAnimator::getArrayString(const SkDisplayable* ae, + const SkMemberInfo* ai, int index) { + SkOperand operand; + bool result = getArrayCommon(ae, ai, index, &operand, SkType_String); + return result ? operand.fString->c_str() : nil; +} + +const char* SkAnimator::getArrayString(const char* id, const char* fieldID, int index) { + const SkDisplayable* element = getElement(id); + if (element == nil) + return nil; + const SkMemberInfo* field = getField(element, fieldID); + if (field == nil) + return nil; + return getArrayString(element, field, index); +} + +SkMSec SkAnimator::getInterval() { + return fMaker->fMinimumInterval == (SkMSec) -1 ? 0 : fMaker->fMinimumInterval; +} + +void SkAnimator::getInvalBounds(SkRect* inval) { + if (fMaker->fDisplayList.fHasUnion) { + inval->fLeft = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fLeft); + inval->fTop = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fTop); + inval->fRight = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fRight); + inval->fBottom = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fBottom); + } else { + inval->fLeft = inval->fTop = -SK_ScalarMax; + inval->fRight = inval->fBottom = SK_ScalarMax; + } +} + +const SkXMLParserError* SkAnimator::getParserError() { + return &fMaker->fError; +} + +const char* SkAnimator::getParserErrorString() { + if (fMaker->fErrorString.size() == 0 && fMaker->fError.hasError()) + fMaker->setErrorString(); + return fMaker->fErrorString.c_str(); +} + +int32_t SkAnimator::getInt(const SkDisplayable* element, const SkMemberInfo* info) { + if (info->fType != SkType_MemberProperty) { + SkOperand operand; + if (info->getType() == SkType_Int) { + info->getValue(element, &operand, 1); + return operand.fS32; + } + return SK_NaN32; + } + SkScriptValue scriptValue; + bool success = element->getProperty(info->propertyIndex(), &scriptValue); + if (success && scriptValue.fType == SkType_Int) + return scriptValue.fOperand.fS32; + return SK_NaN32; +} + +int32_t SkAnimator::getInt(const char* id, const char* fieldID) { + const SkDisplayable* element = getElement(id); + if (element == nil) + return SK_NaN32; + const SkMemberInfo* field = getField(element, fieldID); + if (field == nil) + return SK_NaN32; + return getInt(element, field); +} + +SkScalar SkAnimator::getScalar(const SkDisplayable* element, const SkMemberInfo* info) { + if (info->fType != SkType_MemberProperty) { + SkOperand operand; + if (info->getType() == SkType_Float) { + info->getValue(element, &operand, 1); + return operand.fScalar; + } + return SK_ScalarNaN; + } + SkScriptValue scriptValue; + bool success = element->getProperty(info->propertyIndex(), &scriptValue); + if (success && scriptValue.fType == SkType_Float) + return scriptValue.fOperand.fScalar; + return SK_ScalarNaN; +} + +SkScalar SkAnimator::getScalar(const char* id, const char* fieldID) { + const SkDisplayable* element = getElement(id); + if (element == nil) + return SK_ScalarNaN; + const SkMemberInfo* field = getField(element, fieldID); + if (field == nil) + return SK_ScalarNaN; + return getScalar(element, field); +} + +const char* SkAnimator::getString(const SkDisplayable* ae, + const SkMemberInfo* ai) { + const SkDisplayable* element = (const SkDisplayable*) ae; + const SkMemberInfo* info = (const SkMemberInfo*) ai; + SkString* temp; + info->getString(element, &temp); + return temp->c_str(); +} + +const char* SkAnimator::getString(const char* id, const char* fieldID) { + const SkDisplayable* element = getElement(id); + if (element == nil) + return nil; + const SkMemberInfo* field = getField(element, fieldID); + if (field == nil) + return nil; + return getString(element, field); +} + +const char* SkAnimator::getURIBase() { + return fMaker->fPrefix.c_str(); +} + +void SkAnimator::initialize() { + SkDELETE(fMaker); + fMaker = SkNEW_ARGS(SkAnimateMaker, (this, nil, nil)); + decodeMemory(gMathPrimer, sizeof(gMathPrimer)-1); +#ifdef ANDROID + InitializeSkExtraPathEffects(this); +#endif +} + + +#ifdef SK_DEBUG +bool SkAnimator::isTrackingEvents() { + return false; +} +#endif + +bool SkAnimator::onEvent(const SkEvent& evt) { +#ifdef SK_DEBUG + SkAnimator* root = fMaker->getRoot(); + if (root == nil) + root = this; + if (root->isTrackingEvents()) + root->eventDone(evt); +#endif + if (evt.isType(SK_EventType_OnEnd)) { + SkEventState eventState; + bool success = evt.findPtr("anim", (void**) &eventState.fDisplayable); + SkASSERT(success); + success = evt.findS32("time", (int32_t*) &fMaker->fEnableTime); + SkASSERT(success); + fMaker->fAdjustedStart = fMaker->getAppTime() - fMaker->fEnableTime; + fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kOnEnd, &eventState); + fMaker->fAdjustedStart = 0; + goto inval; + } + if (evt.isType(SK_EventType_Delay)) { + fMaker->doDelayedEvent(); + goto inval; + } + { + const char* id = evt.findString("id"); + if (id == nil) + return false; + SkDisplayable** firstMovie = fMaker->fMovies.begin(); + SkDisplayable** endMovie = fMaker->fMovies.end(); + for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) { + SkDisplayMovie* movie = (SkDisplayMovie*) *ptr; + movie->doEvent(evt); + } + { + SkDisplayable* event; + if (fMaker->find(id, &event) == false) + return false; + #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + SkString debugOut; + SkMSec realTime = fMaker->getAppTime(); + debugOut.appendS32(realTime - fMaker->fDebugTimeBase); + debugOut.append(" onEvent id="); + debugOut.append(id); + #endif + SkMSec time = evt.getFast32(); + if (time != 0) { + SkMSec app = fMaker->getAppTime(); + fMaker->setEnableTime(app, time); + #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + debugOut.append(" time="); + debugOut.appendS32(time - fMaker->fDebugTimeBase); + debugOut.append(" adjust="); + debugOut.appendS32(fMaker->fAdjustedStart); + #endif + } + #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + SkDebugf("%s\n", debugOut.c_str()); + #endif + SkASSERT(event->isEvent()); + SkDisplayEvent* displayEvent = (SkDisplayEvent*) event; + displayEvent->populateInput(*fMaker, evt); + displayEvent->enableEvent(*fMaker); + } + } +inval: + fMaker->notifyInval(); + return true; +} + +void SkAnimator::onEventPost(SkEvent* evt, SkEventSinkID sinkID) +{ +#ifdef SK_DEBUG + SkAnimator* root = fMaker->getRoot(); + if (root) { + root->onEventPost(evt, sinkID); + return; + } +#else + SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID); +#endif + SkEvent::Post(evt, sinkID); +} + +void SkAnimator::onEventPostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time) +{ +#ifdef SK_DEBUG + SkAnimator* root = fMaker->getRoot(); + if (root) { + root->onEventPostTime(evt, sinkID, time); + return; + } +#else + SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID); +#endif + SkEvent::PostTime(evt, sinkID, time); +} + +void SkAnimator::reset() { + fMaker->fDisplayList.reset(); +} + +SkEventSinkID SkAnimator::getHostEventSinkID() const { + return fMaker->fHostEventSinkID; +} + +void SkAnimator::setHostEventSinkID(SkEventSinkID target) { + fMaker->fHostEventSinkID = target; +} + +void SkAnimator::onSetHostHandler(Handler ) { +} + +void SkAnimator::setJavaOwner(Handler ) { +} + +bool SkAnimator::setArrayString(const char* id, const char* fieldID, const char** array, int num) +{ + SkTypedArray tArray(SkType_String); + tArray.setCount(num); + for (int i = 0; i < num; i++) { + SkOperand op; + op.fString = new SkString(array[i]); + tArray[i] = op; + } + return setArray(id, fieldID, tArray); +} +bool SkAnimator::setArrayInt(const char* id, const char* fieldID, const int* array, int num) +{ + SkTypedArray tArray(SkType_Int); + tArray.setCount(num); + for (int i = 0; i < num; i++) { + SkOperand op; + op.fS32 = array[i]; + tArray[i] = op; + } + return setArray(id, fieldID, tArray); +} + +bool SkAnimator::setArray(SkDisplayable* element, const SkMemberInfo* info, SkTypedArray array) { + if (info->fType != SkType_Array) + return false; //the field is not an array + //i think we can handle the case where the displayable itself is an array differently from the + //case where it has an array - for one thing, if it is an array, i think we can change its type + //if it's not, we cannot + SkDisplayTypes type = element->getType(); + if (type == SkType_Array) { + SkDisplayArray* dispArray = (SkDisplayArray*) element; + dispArray->values = array; + return true; + } + else + return false; //currently i don't care about this case +} + +bool SkAnimator::setArray(const char* id, const char* fieldID, SkTypedArray array) { + SkDisplayable* element = (SkDisplayable*) getElement(id); + //should I go ahead and change all 'nil's to 'NULL'? + if (element == nil) + return false; + const SkMemberInfo* field = getField(element, fieldID); + if (field == nil) + return false; + return setArray(element, field, array); +} + +bool SkAnimator::setInt(SkDisplayable* element, const SkMemberInfo* info, int32_t s32) { + if (info->fType != SkType_MemberProperty) { + SkOperand operand; + operand.fS32 = s32; + SkASSERT(info->getType() == SkType_Int); + info->setValue(element, &operand, 1); + } else { + SkScriptValue scriptValue; + scriptValue.fType = SkType_Int; + scriptValue.fOperand.fS32 = s32; + element->setProperty(info->propertyIndex(), scriptValue); + } + return true; +} + +bool SkAnimator::setInt(const char* id, const char* fieldID, int32_t s32) { + SkDisplayable* element = (SkDisplayable*) getElement(id); + if (element == nil) + return false; + const SkMemberInfo* field = getField(element, fieldID); + if (field == nil) + return false; + return setInt(element, field, s32); +} + +bool SkAnimator::setScalar(SkDisplayable* element, const SkMemberInfo* info, SkScalar scalar) { + if (info->fType != SkType_MemberProperty) { + SkOperand operand; + operand.fScalar = scalar; + SkASSERT(info->getType() == SkType_Float); + info->setValue(element, &operand, 1); + } else { + SkScriptValue scriptValue; + scriptValue.fType = SkType_Float; + scriptValue.fOperand.fScalar = scalar; + element->setProperty(info->propertyIndex(), scriptValue); + } + return true; +} + +bool SkAnimator::setScalar(const char* id, const char* fieldID, SkScalar scalar) { + SkDisplayable* element = (SkDisplayable*) getElement(id); + if (element == nil) + return false; + const SkMemberInfo* field = getField(element, fieldID); + if (field == nil) + return false; + return setScalar(element, field, scalar); +} + +bool SkAnimator::setString(SkDisplayable* element, + const SkMemberInfo* info, const char* str) { + // !!! until this is fixed, can't call script with global references from here + info->setValue(*fMaker, nil, 0, info->fCount, element, info->getType(), str, strlen(str)); + return true; +} + +bool SkAnimator::setString(const char* id, const char* fieldID, const char* str) { + SkDisplayable* element = (SkDisplayable*) getElement(id); + if (element == nil) + return false; + const SkMemberInfo* field = getField(element, fieldID); + if (field == nil) + return false; + return setString(element, field, str); +} + +void SkAnimator::setTimeline(const Timeline& timeline) { + fMaker->fTimeline = &timeline; +} + +void SkAnimator::setURIBase(const char* uri) { + if (uri) + { + const char* tail = strrchr(uri, '/'); + if (tail) { + SkString prefix(uri, tail - uri + 1); + if (SkStream::IsAbsoluteURI(uri)) + fMaker->fPrefix.reset(); + fMaker->fPrefix.append(prefix); + fMaker->fFileName.set(tail + 1); + } else + fMaker->fFileName.set(uri); + } +} + +#ifdef SK_DEBUG +bool SkAnimator::NoLeaks() { +#ifdef SK_BUILD_FOR_MAC + if (SkDisplayable::fAllocations.count() == 0) + return true; +// return SkDisplayable::fAllocationCount == 0; + SkDebugf("!!! leaked %d displayables:\n", SkDisplayable::fAllocations.count()); + for (SkDisplayable** leak = SkDisplayable::fAllocations.begin(); leak < SkDisplayable::fAllocations.end(); leak++) + SkDebugf("%08x %s\n", *leak, (*leak)->id); +#endif + return false; +} +#endif + +#ifdef SK_SUPPORT_UNITTEST +#include "SkAnimatorScript.h" +#include "SkBase64.h" +#include "SkParse.h" +#include "SkMemberInfo.h" + +#define unittestline(type) { #type , type::UnitTest } +#endif + + +void SkAnimator::Init(bool runUnitTests) { +#ifdef SK_SUPPORT_UNITTEST + if (runUnitTests == false) + return; + static const struct { + const char* fTypeName; + void (*fUnitTest)( ); + } gUnitTests[] = { + unittestline(SkBase64), + unittestline(SkDisplayType), + unittestline(SkParse), + unittestline(SkScriptEngine), +// unittestline(SkScriptEngine2), // compiled script experiment + unittestline(SkAnimatorScript) + }; + for (int i = 0; i < (int)SK_ARRAY_COUNT(gUnitTests); i++) + { + SkDebugf("SkAnimator: Running UnitTest for %s\n", gUnitTests[i].fTypeName); + gUnitTests[i].fUnitTest(); + SkDebugf("SkAnimator: End UnitTest for %s\n", gUnitTests[i].fTypeName); + } +#endif +} + +void SkAnimator::Term() { +} + + + diff --git a/libs/graphics/animator/SkAnimatorScript.cpp b/libs/graphics/animator/SkAnimatorScript.cpp new file mode 100644 index 0000000000..cce5723416 --- /dev/null +++ b/libs/graphics/animator/SkAnimatorScript.cpp @@ -0,0 +1,590 @@ +#include "SkAnimatorScript.h" +#include "SkAnimateBase.h" +#include "SkAnimateMaker.h" +#include "SkDisplayTypes.h" +#include "SkExtras.h" +#include "SkMemberInfo.h" +#include "SkParse.h" + +static const SkDisplayEnumMap gEnumMaps[] = { + { SkType_AddMode, "indirect|immediate" }, + { SkType_Align, "left|center|right" }, + { SkType_ApplyMode, "create|immediate|once" }, + { SkType_ApplyTransition, "normal|reverse" }, + { SkType_BitmapEncoding, "jpeg|png" }, + { SkType_BitmapFormat, "none|A1|A8|Index8|RGB16|RGB32" }, + { SkType_Boolean, "false|true" }, + { SkType_Cap, "butt|round|square" }, + { SkType_EventCode, "none|leftSoftKey|rightSoftKey|home|back|send|end|key0|key1|key2|key3|key4|key5|key6|key7|key8|key9|star|hash|up|down|left|right|OK|volUp|volDown|camera" }, + { SkType_EventKind, "none|keyChar|keyPress|keyPressUp|mouseDown|mouseDrag|mouseMove|mouseUp|onEnd|onLoad|user" }, + { SkType_EventMode, "deferred|immediate" }, + { SkType_FillType, "winding|evenOdd" }, + { SkType_FilterType, "none|bilinear" }, + { SkType_FontStyle, "normal|bold|italic|boldItalic" }, + { SkType_FromPathMode, "normal|angle|position" }, + { SkType_Join, "miter|round|blunt" }, + { SkType_MaskFilterBlurStyle, "normal|solid|outer|inner" }, + { SkType_PathDirection, "cw|ccw" }, + { SkType_Style, "fill|stroke|strokeAndFill" }, + { SkType_TextBoxAlign, "start|center|end" }, + { SkType_TextBoxMode, "oneLine|lineBreak" }, + { SkType_TileMode, "clamp|repeat|mirror" }, + { SkType_Xfermode, "clear|src|dst|srcOver|dstOver|srcIn|dstIn|srcOut|dstOut|" + "srcATop|dstATop|xor|darken|lighten" }, +}; + +static int gEnumMapCount = SK_ARRAY_COUNT(gEnumMaps); + +SkAnimatorScript::SkAnimatorScript(SkAnimateMaker& maker, SkDisplayable* working, SkDisplayTypes type) + : SkScriptEngine(SkScriptEngine::ToOpType(type)), fMaker(maker), fParent(NULL), fWorking(working) +{ + memberCallBack(EvalMember, (void*) this); + memberFunctionCallBack(EvalMemberFunction, (void*) this); + boxCallBack(Box, (void*) this); + unboxCallBack(Unbox, (void*) &maker); + propertyCallBack(EvalID, (void*) this); // must be first (entries are prepended, will be last), since it never fails + propertyCallBack(Infinity, (void*) this); + propertyCallBack(NaN, (void*) this); + functionCallBack(Eval, (void*) this); + functionCallBack(IsFinite, (void*) this); + functionCallBack(IsNaN, (void*) this); + if (type == SkType_ARGB) { + functionCallBack(EvalRGB, (void*) this); + propertyCallBack(EvalNamedColor, (void*) &maker.fIDs); + } + if (SkDisplayType::IsEnum(&maker, type)) { + // !!! for SpiderMonkey, iterate through the enum values, and map them to globals + const SkDisplayEnumMap& map = GetEnumValues(type); + propertyCallBack(EvalEnum, (void*) map.fValues); + } + for (SkExtras** extraPtr = maker.fExtras.begin(); extraPtr < maker.fExtras.end(); extraPtr++) { + SkExtras* extra = *extraPtr; + if (extra->fExtraCallBack) + propertyCallBack(extra->fExtraCallBack, extra->fExtraStorage); + } +} + +SkAnimatorScript::~SkAnimatorScript() { + for (SkDisplayable** dispPtr = fTrackDisplayable.begin(); dispPtr < fTrackDisplayable.end(); dispPtr++) + delete *dispPtr; +} + +bool SkAnimatorScript::evaluate(const char* original, SkScriptValue* result, SkDisplayTypes type) { + const char* script = original; + bool success = evaluateScript(&script, result); + if (success == false || result->fType != type) { + fMaker.setScriptError(*this); + return false; + } + return true; +} + +bool SkAnimatorScript::Box(void* user, SkScriptValue* scriptValue) { + SkAnimatorScript* engine = (SkAnimatorScript*) user; + SkDisplayTypes type = scriptValue->fType; + SkDisplayable* displayable; + switch (type) { + case SkType_Array: { + SkDisplayArray* boxedValue = new SkDisplayArray(*scriptValue->fOperand.fArray); + displayable = boxedValue; + } break; + case SkType_Boolean: { + SkDisplayBoolean* boxedValue = new SkDisplayBoolean; + displayable = boxedValue; + boxedValue->value = !! scriptValue->fOperand.fS32; + } break; + case SkType_Int: { + SkDisplayInt* boxedValue = new SkDisplayInt; + displayable = boxedValue; + boxedValue->value = scriptValue->fOperand.fS32; + } break; + case SkType_Float: { + SkDisplayFloat* boxedValue = new SkDisplayFloat; + displayable = boxedValue; + boxedValue->value = scriptValue->fOperand.fScalar; + } break; + case SkType_String: { + SkDisplayString* boxedValue = new SkDisplayString(*scriptValue->fOperand.fString); + displayable = boxedValue; + } break; + case SkType_Displayable: + scriptValue->fOperand.fObject = scriptValue->fOperand.fDisplayable; + scriptValue->fType = SkType_Displayable; + return true; + default: + SkASSERT(0); + return false; + } + engine->track(displayable); + scriptValue->fOperand.fObject = displayable; + scriptValue->fType = SkType_Displayable; + return true; +} + +bool SkAnimatorScript::Eval(const char* function, size_t len, SkTDArray<SkScriptValue>& params, + void* eng, SkScriptValue* value) { + if (SK_LITERAL_STR_EQUAL("eval", function, len) == false) + return false; + if (params.count() != 1) + return false; + SkAnimatorScript* host = (SkAnimatorScript*) eng; + SkAnimatorScript engine(host->fMaker, host->fWorking, SkScriptEngine::ToDisplayType(host->fReturnType)); + SkScriptValue* scriptValue = params.begin(); + bool success = true; + if (scriptValue->fType == SkType_String) { + const char* script = scriptValue->fOperand.fString->c_str(); + success = engine.evaluateScript(&script, value); + } else + *value = *scriptValue; + return success; +} + +bool SkAnimatorScript::EvalEnum(const char* token, size_t len, void* callBack, SkScriptValue* value) { + const char* tokens = (const char*) callBack; + value->fType = SkType_Int; + if (MapEnums(tokens, token, len, (int*)&value->fOperand.fS32)) + return true; + return false; +} + +bool SkAnimatorScript::EvalID(const char* token, size_t len, void* user, SkScriptValue* value) { + SkAnimatorScript* engine = (SkAnimatorScript*) user; + SkTDict<SkDisplayable*>* ids = &engine->fMaker.fIDs; + SkDisplayable* displayable; + bool success = ids->find(token, len, &displayable); + if (success == false) { + displayable = engine->fWorking; + if (SK_LITERAL_STR_EQUAL("parent", token, len)) { + SkDisplayable* parent = displayable->getParent(); + if (parent == false) + parent = engine->fParent; + if (parent) { + value->fOperand.fDisplayable = parent; + value->fType = SkType_Displayable; + return true; + } + } + if (displayable && EvalMember(token, len, displayable, engine, value)) + return true; + value->fOperand.fString = NULL; + value->fType = SkType_String; + } else { + SkDisplayable* working = engine->fWorking; + value->fOperand.fDisplayable = displayable; + value->fType = SkType_Displayable; + if (displayable->canContainDependents() && working && working->isAnimate()) { + SkAnimateBase* animator = (SkAnimateBase*) working; + if (animator->isDynamic()) { + SkDisplayDepend* depend = (SkDisplayDepend* ) displayable; + depend->addDependent(working); + } + } + } + return true; +} + +bool SkAnimatorScript::EvalNamedColor(const char* token, size_t len, void* callback, SkScriptValue* value) { + value->fType = SkType_Int; + if (SkParse::FindNamedColor(token, len, (SkColor*) &value->fOperand.fS32) != NULL) + return true; + return false; +} + +bool SkAnimatorScript::EvalRGB(const char* function, size_t len, SkTDArray<SkScriptValue>& params, + void* eng, SkScriptValue* value) { + if (SK_LITERAL_STR_EQUAL("rgb", function, len) == false) + return false; + if (params.count() != 3) + return false; + SkScriptEngine* engine = (SkScriptEngine*) eng; + unsigned result = 0xFF000000; + int shift = 16; + for (SkScriptValue* valuePtr = params.begin(); valuePtr < params.end(); valuePtr++) { + engine->convertTo(SkType_Int, valuePtr); + result |= SkClampMax(valuePtr->fOperand.fS32, 255) << shift; + shift -= 8; + } + value->fOperand.fS32 = result; + value->fType = SkType_Int; + return true; +} + +bool SkAnimatorScript::EvalMemberCommon(SkScriptEngine* engine, const SkMemberInfo* info, + SkDisplayable* displayable, SkScriptValue* value) { + SkDisplayTypes original; + SkDisplayTypes type = original = (SkDisplayTypes) info->getType(); + if (info->fType == SkType_Array) + type = SkType_Array; + switch (type) { + case SkType_ARGB: + type = SkType_Int; + case SkType_Boolean: + case SkType_Int: + case SkType_MSec: + case SkType_Float: + SkASSERT(info->getCount() == 1); + if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) + value->fOperand.fS32 = *(int32_t*) info->memberData(displayable); // OK for SkScalar too + if (type == SkType_MSec) { + value->fOperand.fScalar = SkScalarDiv((SkScalar) value->fOperand.fS32, 1000); // dividing two ints is the same as dividing two scalars + type = SkType_Float; + } + break; + case SkType_String: { + SkString* displayableString; + if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) { + info->getString(displayable, &displayableString); + value->fOperand.fString = new SkString(*displayableString); + } + } break; + case SkType_Array: { + SkASSERT(info->fType != SkType_MemberProperty); // !!! incomplete + SkTDOperandArray* displayableArray = (SkTDOperandArray*) info->memberData(displayable); + if (displayable->getType() == SkType_Array) { + SkDisplayArray* typedArray = (SkDisplayArray*) displayable; + original = typedArray->values.getType(); + } + SkASSERT(original != SkType_Unknown); + SkTypedArray* array = value->fOperand.fArray = new SkTypedArray(original); + engine->track(array); + int count = displayableArray->count(); + if (count > 0) { + array->setCount(count); + memcpy(array->begin(), displayableArray->begin(), count * sizeof(SkOperand)); + } + } break; + default: + SkASSERT(0); // unimplemented + } + value->fType = type; + return true; +} + +bool SkAnimatorScript::EvalMember(const char* member, size_t len, void* object, void* eng, + SkScriptValue* value) { + SkScriptEngine* engine = (SkScriptEngine*) eng; + SkDisplayable* displayable = (SkDisplayable*) object; + SkString name(member, len); + SkDisplayable* named = displayable->contains(name); + if (named) { + value->fOperand.fDisplayable = named; + value->fType = SkType_Displayable; + return true; + } + const SkMemberInfo* info = displayable->getMember(name.c_str()); + if (info == NULL) + return false; + if (info->fType == SkType_MemberProperty) { + if (displayable->getProperty(info->propertyIndex(), value) == false) { + SkASSERT(0); + return false; + } + } + return EvalMemberCommon(engine, info, displayable, value); +} + +bool SkAnimatorScript::EvalMemberFunction(const char* member, size_t len, void* object, + SkTDArray<SkScriptValue>& params, void* eng, SkScriptValue* value) { + SkScriptEngine* engine = (SkScriptEngine*) eng; + SkDisplayable* displayable = (SkDisplayable*) object; + SkString name(member, len); + const SkMemberInfo* info = displayable->getMember(name.c_str()); + SkASSERT(info != NULL); /* !!! error handling unimplemented */ + if (info->fType != SkType_MemberFunction) { + SkASSERT(0); + return false; + } + displayable->executeFunction(displayable, info->functionIndex(), params, info->getType(), + value); + return EvalMemberCommon(engine, info, displayable, value); +} + +bool SkAnimatorScript::EvaluateDisplayable(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, SkDisplayable** result) { + SkAnimatorScript engine(maker, displayable, SkType_Displayable); + SkScriptValue value; + bool success = engine.evaluate(script, &value, SkType_Displayable); + if (success) + *result = value.fOperand.fDisplayable; + return success; +} + +bool SkAnimatorScript::EvaluateInt(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, int32_t* result) { + SkAnimatorScript engine(maker, displayable, SkType_Int); + SkScriptValue value; + bool success = engine.evaluate(script, &value, SkType_Int); + if (success) + *result = value.fOperand.fS32; + return success; +} + +bool SkAnimatorScript::EvaluateFloat(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, SkScalar* result) { + SkAnimatorScript engine(maker, displayable, SkType_Float); + SkScriptValue value; + bool success = engine.evaluate(script, &value, SkType_Float); + if (success) + *result = value.fOperand.fScalar; + return success; +} + +bool SkAnimatorScript::EvaluateString(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, SkString* result) { + SkAnimatorScript engine(maker, displayable, SkType_String); + SkScriptValue value; + bool success = engine.evaluate(script, &value, SkType_String); + if (success) + result->set(*(value.fOperand.fString)); + return success; +} + +bool SkAnimatorScript::EvaluateString(SkAnimateMaker& maker, SkDisplayable* displayable, SkDisplayable* parent, const char* script, SkString* result) { + SkAnimatorScript engine(maker, displayable, SkType_String); + engine.fParent = parent; + SkScriptValue value; + bool success = engine.evaluate(script, &value, SkType_String); + if (success) + result->set(*(value.fOperand.fString)); + return success; +} + +const SkDisplayEnumMap& SkAnimatorScript::GetEnumValues(SkDisplayTypes type) { + int index = SkTSearch<SkDisplayTypes>(&gEnumMaps[0].fType, gEnumMapCount, type, + sizeof(SkDisplayEnumMap)); + SkASSERT(index >= 0); + return gEnumMaps[index]; +} + +bool SkAnimatorScript::Infinity(const char* token, size_t len, void* user, SkScriptValue* value) { + if (SK_LITERAL_STR_EQUAL("Infinity", token, len) == false) + return false; + value->fType = SkType_Float; + value->fOperand.fScalar = SK_ScalarInfinity; + return true; +} + +bool SkAnimatorScript::IsFinite(const char* function, size_t len, SkTDArray<SkScriptValue>& params, + void* eng, SkScriptValue* value) { + if (SK_LITERAL_STR_EQUAL(function, "isFinite", len) == false) + return false; + if (params.count() != 1) + return false; + SkScriptValue* scriptValue = params.begin(); + SkDisplayTypes type = scriptValue->fType; + SkScalar scalar = scriptValue->fOperand.fScalar; + value->fType = SkType_Int; + value->fOperand.fS32 = type == SkType_Float ? SkScalarIsNaN(scalar) == false && + SkScalarAbs(scalar) != SK_ScalarInfinity : type == SkType_Int; + return true; +} + +bool SkAnimatorScript::IsNaN(const char* function, size_t len, SkTDArray<SkScriptValue>& params, + void* eng, SkScriptValue* value) { + if (SK_LITERAL_STR_EQUAL("isNaN", function, len) == false) + return false; + if (params.count() != 1) + return false; + SkScriptValue* scriptValue = params.begin(); + value->fType = SkType_Int; + value->fOperand.fS32 = scriptValue->fType == SkType_Float ? SkScalarIsNaN(scriptValue->fOperand.fScalar) : 0; + return true; +} + +bool SkAnimatorScript::MapEnums(const char* ptr, const char* match, size_t len, int* value) { + int index = 0; + bool more = true; + do { + const char* last = strchr(ptr, '|'); + if (last == NULL) { + last = &ptr[strlen(ptr)]; + more = false; + } + size_t length = last - ptr; + if (len == length && strncmp(ptr, match, length) == 0) { + *value = index; + return true; + } + index++; + ptr = last + 1; + } while (more); + return false; +} + +bool SkAnimatorScript::NaN(const char* token, size_t len, void* user, SkScriptValue* value) { + if (SK_LITERAL_STR_EQUAL("NaN", token, len) == false) + return false; + value->fType = SkType_Float; + value->fOperand.fScalar = SK_ScalarNaN; + return true; +} + +#if 0 +bool SkAnimatorScript::ObjectToString(void* object, void* user, SkScriptValue* value) { + SkTDict<SkDisplayable*>* ids = (SkTDict<SkDisplayable*>*) user; + SkDisplayable* displayable = (SkDisplayable*) object; + const char* key; + bool success = ids->findKey(displayable, &key); + if (success == false) + return false; + value->fOperand.fString = new SkString(key); + value->fType = SkType_String; + return true; +} +#endif + +bool SkAnimatorScript::Unbox(void* m, SkScriptValue* scriptValue) { + SkAnimateMaker* maker = (SkAnimateMaker*) m; + SkASSERT((unsigned) scriptValue->fType == (unsigned) SkType_Displayable); + SkDisplayable* displayable = (SkDisplayable*) scriptValue->fOperand.fObject; + SkDisplayTypes type = displayable->getType(); + switch (displayable->getType()) { + case SkType_Array: { + SkDisplayArray* boxedValue = (SkDisplayArray*) displayable; + scriptValue->fOperand.fArray = &boxedValue->values; + } break; + case SkType_Boolean: { + SkDisplayBoolean* boxedValue = (SkDisplayBoolean*) displayable; + scriptValue->fOperand.fS32 = boxedValue->value; + } break; + case SkType_Int: { + SkDisplayInt* boxedValue = (SkDisplayInt*) displayable; + scriptValue->fOperand.fS32 = boxedValue->value; + } break; + case SkType_Float: { + SkDisplayFloat* boxedValue = (SkDisplayFloat*) displayable; + scriptValue->fOperand.fScalar = boxedValue->value; + } break; + case SkType_String: { + SkDisplayString* boxedValue = (SkDisplayString*) displayable; + scriptValue->fOperand.fString = SkNEW_ARGS(SkString, (boxedValue->value)); + } break; + default: { + const char* id; + bool success = maker->findKey(displayable, &id); + SkASSERT(success); + scriptValue->fOperand.fString = SkNEW_ARGS(SkString, (id)); + type = SkType_String; + } + } + scriptValue->fType = type; + return true; +} + +#if defined SK_SUPPORT_UNITTEST + +#include "SkAnimator.h" + +static const char scriptTestSetup[] = +"<screenplay>\n" + "<text id='label' text='defg'/>\n" + "<add id='addLabel' use='label'/>\n" + "<text id='text1' text='test'/>\n" + "<apply scope='addLabel'>\n" + "<set target='label' field='text' to='#script:text1.text'/>\n" + "</apply>\n" + "<apply>\n" + "<paint id='labelPaint'>\n" + "<emboss id='emboss' direction='[1,1,1]' />\n" + "</paint>\n" + "<animate id='animation' field='direction' target='emboss' from='[1,1,1]' to='[-1,1,1]' dur='1'/>\n" + "<set lval='direction[0]' target='emboss' to='-1' />\n" + "</apply>\n" + "<color id='testColor' color='0 ? rgb(0,0,0) : rgb(255,255,255)' />\n" + "<color id='xColor' color='rgb(12,34,56)' />\n" + "<array id='emptyArray' />\n" + "<array id='intArray' values='[1, 4, 6]' />\n" + "<int id='idx' value='2' />\n" + "<int id='idy' value='2' />\n" + "<string id='alpha' value='abc' />\n" + "<rect id='testRect' left='Math.cos(0)' top='2' right='12' bottom='5' />\n" + "<event id='evt'>\n" + "<input name='x' />\n" + "<apply scope='idy'>\n" + "<set field='value' to='evt.x.int' />\n" + "</apply>\n" + "</event>\n" +"</screenplay>"; + +#if !defined(SK_BUILD_FOR_BREW) + +#define DEFAULT_ANSWER , 0 + +static const SkScriptNAnswer scriptTests[] = { + { "label.text.length == 4", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, +// { "labelPaint.measureText(label.text) > 0 ? labelPaint.measureText(label.text)+10 : 40", SkType_Float, 0, SkIntToScalar(0x23) }, + { "Number.POSITIVE_INFINITY >= Number.MAX_VALUE ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "Infinity >= Number.MAX_VALUE ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "Number.NEGATIVE_INFINITY <= -Number.MAX_VALUE ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "Number.MIN_VALUE > 0 ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "isNaN(Number.NaN)", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "isNaN(NaN)", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "Math.sin(0)", SkType_Float, 0, SkIntToScalar(0) DEFAULT_ANSWER }, + { "alpha+alpha", SkType_String, 0, 0, "abcabc" }, + { "intArray[4]", SkType_Unknown DEFAULT_ANSWER DEFAULT_ANSWER DEFAULT_ANSWER }, + { "emptyArray[4]", SkType_Unknown DEFAULT_ANSWER DEFAULT_ANSWER DEFAULT_ANSWER }, + { "idx", SkType_Int, 2 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "intArray.length", SkType_Int, 3 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "intArray.values[0]", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "intArray[0]", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "idx.value", SkType_Int, 2 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "alpha.value", SkType_String, 0, 0, "abc" }, + { "alpha", SkType_String, 0, 0, "abc" }, + { "alpha.value+alpha.value", SkType_String, 0, 0, "abcabc" }, + { "alpha+idx", SkType_String, 0, 0, "abc2" }, + { "idx+alpha", SkType_String, 0, 0, "2abc" }, + { "intArray[idx]", SkType_Int, 6 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "alpha.slice(1,2)", SkType_String, 0, 0, "b" }, + { "alpha.value.slice(1,2)", SkType_String, 0, 0, "b" }, + { "testRect.left+2", SkType_Float, 0, SkIntToScalar(3) DEFAULT_ANSWER }, + { "0 ? Math.sin(0) : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "0 ? intArray[0] : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "0 ? intArray.values[0] : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "0 ? idx : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "0 ? idx.value : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "0 ? alpha.slice(1,2) : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "0 ? alpha.value.slice(1,2) : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER }, + { "idy", SkType_Int, 3 DEFAULT_ANSWER DEFAULT_ANSWER } +}; +#endif + +#define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) + +void SkAnimatorScript::UnitTest() { +#if !defined(SK_BUILD_FOR_BREW) && defined(SK_SUPPORT_UNITTEST) + SkAnimator animator; + SkASSERT(animator.decodeMemory(scriptTestSetup, sizeof(scriptTestSetup)-1)); + SkEvent evt; + evt.setString("id", "evt"); + evt.setS32("x", 3); + animator.doUserEvent(evt); + // set up animator with memory script above, then run value tests + for (unsigned index = 0; index < SkScriptNAnswer_testCount; index++) { + SkAnimatorScript engine(*animator.fMaker, NULL, scriptTests[index].fType); + SkScriptValue value; + const char* script = scriptTests[index].fScript; + bool success = engine.evaluateScript(&script, &value); + if (success == false) { + SkDebugf("script failed: %s\n", scriptTests[index].fScript); + SkASSERT(scriptTests[index].fType == SkType_Unknown); + continue; + } + SkASSERT(value.fType == scriptTests[index].fType); + SkScalar error; + switch (value.fType) { + case SkType_Int: + SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); + break; + case SkType_Float: + error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); + SkASSERT(error < SK_Scalar1 / 10000); + break; + case SkType_String: + SkASSERT(strcmp(value.fOperand.fString->c_str(), scriptTests[index].fStringAnswer) == 0); + break; + default: + SkASSERT(0); + } + } +#endif +} + +#endif + + diff --git a/libs/graphics/animator/SkAnimatorScript.h b/libs/graphics/animator/SkAnimatorScript.h new file mode 100644 index 0000000000..2a02a2f5e6 --- /dev/null +++ b/libs/graphics/animator/SkAnimatorScript.h @@ -0,0 +1,67 @@ +#ifndef SkAnimatorScript_DEFINED +#define SkAnimatorScript_DEFINED + +#include "SkDisplayable.h" +#include "SkScript.h" +#include "SkTypedArray.h" + +class SkAnimateMaker; +struct SkMemberInfo; + +struct SkDisplayEnumMap { + SkDisplayTypes fType; + const char* fValues; +}; + +class SkAnimatorScript : public SkScriptEngine { +public: + SkAnimatorScript(SkAnimateMaker& , SkDisplayable* , SkDisplayTypes type); + ~SkAnimatorScript(); + bool evaluate(const char* script, SkScriptValue* , SkDisplayTypes type); + void track(SkDisplayable* displayable) { + SkASSERT(fTrackDisplayable.find(displayable) < 0); + *fTrackDisplayable.append() = displayable; } + static bool EvaluateDisplayable(SkAnimateMaker& , SkDisplayable* , const char* script, SkDisplayable** ); + static bool EvaluateFloat(SkAnimateMaker& , SkDisplayable* , const char* script, SkScalar* ); + static bool EvaluateInt(SkAnimateMaker& , SkDisplayable* , const char* script, int32_t* ); + static bool EvaluateString(SkAnimateMaker& , SkDisplayable* , const char* script, SkString* ); + static bool EvaluateString(SkAnimateMaker& , SkDisplayable* , SkDisplayable* parent, const char* script, SkString* ); + static bool MapEnums(const char* ptr, const char* match, size_t len, int* value); +protected: + static bool Box(void* user, SkScriptValue* ); + static bool Eval(const char* function, size_t len, SkTDArray<SkScriptValue>& params, + void* callBack, SkScriptValue* ); + static bool EvalEnum(const char* token, size_t len, void* callBack, SkScriptValue* ); + static bool EvalID(const char* token, size_t len, void* callBack, SkScriptValue* ); + static bool EvalMember(const char* member, size_t len, void* object, void* eng, + SkScriptValue* value); + static bool EvalMemberCommon(SkScriptEngine* , const SkMemberInfo* info, + SkDisplayable* displayable, SkScriptValue* value); + static bool EvalMemberFunction(const char* member, size_t len, void* object, + SkTDArray<SkScriptValue>& params, void* user, SkScriptValue* value); + static bool EvalNamedColor(const char* token, size_t len, void* callBack, SkScriptValue* ); + static bool EvalRGB(const char* function, size_t len, SkTDArray<SkScriptValue>& params, + void* callBack, SkScriptValue* ); + static const SkDisplayEnumMap& GetEnumValues(SkDisplayTypes type); + static bool Infinity(const char* token, size_t len, void* callBack, SkScriptValue* ); + static bool IsFinite(const char* function, size_t len, SkTDArray<SkScriptValue>& params, + void* callBack, SkScriptValue* ); + static bool IsNaN(const char* function, size_t len, SkTDArray<SkScriptValue>& params, + void* callBack, SkScriptValue* ); + static bool NaN(const char* token, size_t len, void* callBack, SkScriptValue* ); + static bool Unbox(void* , SkScriptValue* scriptValue); + SkTDDisplayableArray fTrackDisplayable; + SkAnimateMaker& fMaker; + SkDisplayable* fParent; + SkDisplayable* fWorking; +private: + friend class SkDump; + friend struct SkScriptNAnswer; +#ifdef SK_SUPPORT_UNITTEST +public: + static void UnitTest(); +#endif +}; + +#endif // SkAnimatorScript_DEFINED + diff --git a/libs/graphics/animator/SkAnimatorScript2.cpp b/libs/graphics/animator/SkAnimatorScript2.cpp new file mode 100755 index 0000000000..a3aeaf6fac --- /dev/null +++ b/libs/graphics/animator/SkAnimatorScript2.cpp @@ -0,0 +1,618 @@ +#include "SkAnimatorScript2.h" +#include "SkAnimateBase.h" +#include "SkAnimateMaker.h" +#include "SkDisplayTypes.h" +#include "SkExtras.h" +#include "SkMemberInfo.h" +#include "SkOpArray.h" +#include "SkParse.h" +#include "SkScript2.h" +#include "SkScriptCallBack.h" + +static const SkDisplayEnumMap gEnumMaps[] = { + { SkType_AddMode, "indirect|immediate" }, + { SkType_Align, "left|center|right" }, + { SkType_ApplyMode, "immediate|once" }, + { SkType_ApplyTransition, "reverse" }, + { SkType_BitmapEncoding, "jpeg|png" }, + { SkType_BitmapFormat, "none|A1|A8|Index8|RGB16|RGB32" }, + { SkType_Boolean, "false|true" }, + { SkType_Cap, "butt|round|square" }, + { 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" }, + { SkType_EventKind, "none|keyChar|keyPress|mouseDown|mouseDrag|mouseMove|mouseUp|onEnd|onLoad|user" }, + { SkType_EventMode, "deferred|immediate" }, + { SkType_FillType, "winding|evenOdd" }, + { SkType_FilterType, "none|bilinear" }, + { SkType_FromPathMode, "normal|angle|position" }, + { SkType_Join, "miter|round|blunt" }, + { SkType_MaskFilterBlurStyle, "normal|solid|outer|inner" }, + { SkType_PathDirection, "cw|ccw" }, + { SkType_Style, "fill|stroke|strokeAndFill" }, + { SkType_TextBoxAlign, "start|center|end" }, + { SkType_TextBoxMode, "oneLine|lineBreak" }, + { SkType_TileMode, "clamp|repeat|mirror" }, + { SkType_Xfermode, "clear|src|dst|srcOver|dstOver|srcIn|dstIn|srcOut|dstOut|" + "srcATop|dstATop|xor|darken|lighten" }, +}; + +static int gEnumMapCount = SK_ARRAY_COUNT(gEnumMaps); + + +class SkAnimatorScript_Box : public SkScriptCallBackConvert { +public: + SkAnimatorScript_Box() {} + + ~SkAnimatorScript_Box() { + for (SkDisplayable** dispPtr = fTrackDisplayable.begin(); dispPtr < fTrackDisplayable.end(); dispPtr++) + delete *dispPtr; + } + + virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) { + SkDisplayable* displayable; + switch (type) { + case SkOperand2::kArray: { + SkDisplayArray* boxedValue = new SkDisplayArray(*operand->fArray); + displayable = boxedValue; + } break; + case SkOperand2::kS32: { + SkDisplayInt* boxedValue = new SkDisplayInt; + displayable = boxedValue; + boxedValue->value = operand->fS32; + } break; + case SkOperand2::kScalar: { + SkDisplayFloat* boxedValue = new SkDisplayFloat; + displayable = boxedValue; + boxedValue->value = operand->fScalar; + } break; + case SkOperand2::kString: { + SkDisplayString* boxedValue = new SkDisplayString(*operand->fString); + displayable = boxedValue; + } break; + case SkOperand2::kObject: + return true; + default: + SkASSERT(0); + return false; + } + track(displayable); + operand->fObject = (void*) displayable; + return true; + } + + virtual SkOperand2::OpType getReturnType(int index) { + return SkOperand2::kObject; + } + + virtual Type getType() const { + return kBox; + } + + void track(SkDisplayable* displayable) { + SkASSERT(fTrackDisplayable.find(displayable) < 0); + *fTrackDisplayable.append() = displayable; + } + + SkTDDisplayableArray fTrackDisplayable; +}; + + +class SkAnimatorScript_Enum : public SkScriptCallBackProperty { +public: + SkAnimatorScript_Enum(const char* tokens) : fTokens(tokens) {} + + virtual bool getConstValue(const char* name, int len, SkOperand2* value) { + return SkAnimatorScript2::MapEnums(fTokens, name, len, &value->fS32); + } + +private: + const char* fTokens; +}; + + // !!! if type is string, call invoke + // if any other type, return original value + // distinction is undone: could do this by returning index == 0 only if param is string + // still, caller of getParamTypes will attempt to convert param to string (I guess) +class SkAnimatorScript_Eval : public SkScriptCallBackFunction { +public: + SkAnimatorScript_Eval(SkAnimatorScript2* engine) : fEngine(engine) {} + + virtual bool getIndex(const char* name, int len, size_t* result) { + if (SK_LITERAL_STR_EQUAL("eval", name, len) != 0) + return false; + *result = 0; + return true; + } + + virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { + types->setCount(1); + SkOperand2::OpType* type = types->begin(); + type[0] = SkOperand2::kString; + } + + virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) { + SkAnimatorScript2 engine(fEngine->getMaker(), fEngine->getWorking(), + SkAnimatorScript2::ToDisplayType(fEngine->getReturnType())); + SkOperand2* op = params->begin(); + const char* script = op->fString->c_str(); + SkScriptValue2 value; + return engine.evaluateScript(&script, &value); + SkASSERT(value.fType == fEngine->getReturnType()); + *answer = value.fOperand; + // !!! incomplete ? + return true; + } + +private: + SkAnimatorScript2* fEngine; +}; + +class SkAnimatorScript_ID : public SkScriptCallBackProperty { +public: + SkAnimatorScript_ID(SkAnimatorScript2* engine) : fEngine(engine) {} + + virtual bool getIndex(const char* token, int len, size_t* result) { + SkDisplayable* displayable; + bool success = fEngine->getMaker().find(token, len, &displayable); + if (success == false) { + *result = 0; + } else { + *result = (size_t) displayable; + SkDisplayable* working = fEngine->getWorking(); + if (displayable->canContainDependents() && working && working->isAnimate()) { + SkAnimateBase* animator = (SkAnimateBase*) working; + if (animator->isDynamic()) { + SkDisplayDepend* depend = (SkDisplayDepend* ) displayable; + depend->addDependent(working); + } + } + } + return true; + } + + virtual bool getResult(size_t ref, SkOperand2* answer) { + answer->fObject = (void*) ref; + return true; + } + + virtual SkOperand2::OpType getReturnType(size_t index) { + return index == 0 ? SkOperand2::kString : SkOperand2::kObject; + } + +private: + SkAnimatorScript2* fEngine; +}; + + +class SkAnimatorScript_Member : public SkScriptCallBackMember { +public: + + SkAnimatorScript_Member(SkAnimatorScript2* engine) : fEngine(engine) {} + + bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) { + SkDisplayable* displayable = (SkDisplayable*) object; + SkString name(member, len); + SkDisplayable* named = displayable->contains(name); + if (named) { + ref->fType = SkOperand2::kObject; + ref->fOperand.fObject = named; + return true; + } + const SkMemberInfo* info = displayable->getMember(name.c_str()); + if (info == nil) + return false; // !!! add additional error info? + ref->fType = SkAnimatorScript2::ToOpType(info->getType()); + ref->fOperand.fObject = (void*) info; + return true; + } + + bool invoke(size_t ref, void* object, SkOperand2* value) { + const SkMemberInfo* info = (const SkMemberInfo* ) ref; + SkDisplayable* displayable = (SkDisplayable*) object; + if (info->fType == SkType_MemberProperty) { + if (displayable->getProperty2(info->propertyIndex(), value) == false) { + return false; + } + } + return fEngine->evalMemberCommon(info, displayable, value); + } + + SkAnimatorScript2* fEngine; +}; + + +class SkAnimatorScript_MemberFunction : public SkScriptCallBackMemberFunction { +public: + SkAnimatorScript_MemberFunction(SkAnimatorScript2* engine) : fEngine(engine) {} + + bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) { + SkDisplayable* displayable = (SkDisplayable*) object; + SkString name(member, len); + const SkMemberInfo* info = displayable->getMember(name.c_str()); + if (info == nil || info->fType != SkType_MemberFunction) + return false; // !!! add additional error info? + ref->fType = SkAnimatorScript2::ToOpType(info->getType()); + ref->fOperand.fObject = (void*) info; + return true; + } + + virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { + types->setCount(3); + SkOperand2::OpType* type = types->begin(); + type[0] = type[1] = type[2] = SkOperand2::kS32; + } + + bool invoke(size_t ref, void* object, SkOpArray* params, SkOperand2* value) + { + const SkMemberInfo* info = (const SkMemberInfo* ) ref; + SkDisplayable* displayable = (SkDisplayable*) object; + displayable->executeFunction2(displayable, info->functionIndex(), params, info->getType(), + value); + return fEngine->evalMemberCommon(info, displayable, value); + } + + SkAnimatorScript2* fEngine; +}; + + +class SkAnimatorScript_NamedColor : public SkScriptCallBackProperty { +public: + virtual bool getConstValue(const char* name, int len, SkOperand2* value) { + return SkParse::FindNamedColor(name, len, (SkColor*) &value->fS32) != nil; + } +}; + + +class SkAnimatorScript_RGB : public SkScriptCallBackFunction { +public: + virtual bool getIndex(const char* name, int len, size_t* result) { + if (SK_LITERAL_STR_EQUAL("rgb", name, len) != 0) + return false; + *result = 0; + return true; + } + + virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { + types->setCount(3); + SkOperand2::OpType* type = types->begin(); + type[0] = type[1] = type[2] = SkOperand2::kS32; + } + + virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) { + SkASSERT(index == 0); + unsigned result = 0xFF000000; + int shift = 16; + for (int index = 0; index < 3; index++) { + result |= SkClampMax(params->begin()[index].fS32, 255) << shift; + shift -= 8; + } + answer->fS32 = result; + return true; + } + +}; + + +class SkAnimatorScript_Unbox : public SkScriptCallBackConvert { +public: + SkAnimatorScript_Unbox(SkAnimatorScript2* engine) : fEngine(engine) {} + + virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) { + SkASSERT(type == SkOperand2::kObject); + SkDisplayable* displayable = (SkDisplayable*) operand->fObject; + switch (displayable->getType()) { + case SkType_Array: { + SkDisplayArray* boxedValue = (SkDisplayArray*) displayable; + operand->fArray = new SkOpArray(SkAnimatorScript2::ToOpType(boxedValue->values.getType())); + int count = boxedValue->values.count(); + operand->fArray->setCount(count); + memcpy(operand->fArray->begin(), boxedValue->values.begin(), count * sizeof(SkOperand2)); + fEngine->track(operand->fArray); + } break; + case SkType_Boolean: { + SkDisplayBoolean* boxedValue = (SkDisplayBoolean*) displayable; + operand->fS32 = boxedValue->value; + } break; + case SkType_Int: { + SkDisplayInt* boxedValue = (SkDisplayInt*) displayable; + operand->fS32 = boxedValue->value; + } break; + case SkType_Float: { + SkDisplayFloat* boxedValue = (SkDisplayFloat*) displayable; + operand->fScalar = boxedValue->value; + } break; + case SkType_String: { + SkDisplayString* boxedValue = (SkDisplayString*) displayable; + operand->fString = SkNEW_ARGS(SkString, (boxedValue->value)); + } break; + default: { + const char* id; + bool success = fEngine->getMaker().findKey(displayable, &id); + SkASSERT(success); + operand->fString = SkNEW_ARGS(SkString, (id)); + } + } + return true; + } + + virtual SkOperand2::OpType getReturnType(int /*index*/, SkOperand2* operand) { + SkDisplayable* displayable = (SkDisplayable*) operand->fObject; + switch (displayable->getType()) { + case SkType_Array: + return SkOperand2::kArray; + case SkType_Int: + return SkOperand2::kS32; + case SkType_Float: + return SkOperand2::kScalar; + case SkType_String: + default: + return SkOperand2::kString; + } + } + + virtual Type getType() const { + return kUnbox; + } + + SkAnimatorScript2* fEngine; +}; + +SkAnimatorScript2::SkAnimatorScript2(SkAnimateMaker& maker, SkDisplayable* working, SkDisplayTypes type) : + SkScriptEngine2(ToOpType(type)), fMaker(maker), fWorking(working) { + *fCallBackArray.append() = new SkAnimatorScript_Member(this); + *fCallBackArray.append() = new SkAnimatorScript_MemberFunction(this); + *fCallBackArray.append() = new SkAnimatorScript_Box(); + *fCallBackArray.append() = new SkAnimatorScript_Unbox(this); + *fCallBackArray.append() = new SkAnimatorScript_ID(this); + if (type == SkType_ARGB) { + *fCallBackArray.append() = new SkAnimatorScript_RGB(); + *fCallBackArray.append() = new SkAnimatorScript_NamedColor(); + } + if (SkDisplayType::IsEnum(&maker, type)) { + // !!! for SpiderMonkey, iterate through the enum values, and map them to globals + const SkDisplayEnumMap& map = GetEnumValues(type); + *fCallBackArray.append() = new SkAnimatorScript_Enum(map.fValues); + } + *fCallBackArray.append() = new SkAnimatorScript_Eval(this); +#if 0 // !!! no extra support for now + for (SkExtras** extraPtr = maker.fExtras.begin(); extraPtr < maker.fExtras.end(); extraPtr++) { + SkExtras* extra = *extraPtr; + if (extra->fExtraCallBack) + *fCallBackArray.append() = new propertyCallBack(extra->fExtraCallBack, extra->fExtraStorage); + } +#endif +} + +SkAnimatorScript2::~SkAnimatorScript2() { + SkScriptCallBack** end = fCallBackArray.end(); + for (SkScriptCallBack** ptr = fCallBackArray.begin(); ptr < end; ptr++) + delete *ptr; +} + +bool SkAnimatorScript2::evalMemberCommon(const SkMemberInfo* info, + SkDisplayable* displayable, SkOperand2* value) { + SkDisplayTypes original; + SkDisplayTypes type = original = (SkDisplayTypes) info->getType(); + if (info->fType == SkType_Array) + type = SkType_Array; + switch (type) { + case SkType_ARGB: + type = SkType_Int; + case SkType_Boolean: + case SkType_Int: + case SkType_MSec: + case SkType_Float: + SkASSERT(info->getCount() == 1); + if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) + value->fS32 = *(int32_t*) info->memberData(displayable); // OK for SkScalar too + if (type == SkType_MSec) { + value->fScalar = SkScalarDiv((SkScalar) value->fS32, 1000); // dividing two ints is the same as dividing two scalars + type = SkType_Float; + } + break; + case SkType_String: { + SkString* displayableString; + if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) { + info->getString(displayable, &displayableString); + value->fString = new SkString(*displayableString); + } + } break; + case SkType_Array: { + SkASSERT(info->fType != SkType_MemberProperty); // !!! incomplete + SkTDOperandArray* displayableArray = (SkTDOperandArray*) info->memberData(displayable); + if (displayable->getType() == SkType_Array) { + SkDisplayArray* typedArray = (SkDisplayArray*) displayable; + original = typedArray->values.getType(); + } + SkASSERT(original != SkType_Unknown); + SkOpArray* array = value->fArray = new SkOpArray(ToOpType(original)); + track(array); + int count = displayableArray->count(); + if (count > 0) { + array->setCount(count); + memcpy(array->begin(), displayableArray->begin(), count * sizeof(SkOperand2)); + } + } break; + default: + SkASSERT(0); // unimplemented + } + return true; +} + +const SkDisplayEnumMap& SkAnimatorScript2::GetEnumValues(SkDisplayTypes type) { + int index = SkTSearch<SkDisplayTypes>(&gEnumMaps[0].fType, gEnumMapCount, type, + sizeof(SkDisplayEnumMap)); + SkASSERT(index >= 0); + return gEnumMaps[index]; +} + +SkDisplayTypes SkAnimatorScript2::ToDisplayType(SkOperand2::OpType type) { + int val = type; + switch (val) { + case SkOperand2::kNoType: + return SkType_Unknown; + case SkOperand2::kS32: + return SkType_Int; + case SkOperand2::kScalar: + return SkType_Float; + case SkOperand2::kString: + return SkType_String; + case SkOperand2::kArray: + return SkType_Array; + case SkOperand2::kObject: + return SkType_Displayable; + default: + SkASSERT(0); + return SkType_Unknown; + } +} + +SkOperand2::OpType SkAnimatorScript2::ToOpType(SkDisplayTypes type) { + if (SkDisplayType::IsDisplayable(nil /* fMaker */, type)) + return SkOperand2::kObject; + if (SkDisplayType::IsEnum(nil /* fMaker */, type)) + return SkOperand2::kS32; + switch (type) { + case SkType_ARGB: + case SkType_MSec: + case SkType_Int: + return SkOperand2::kS32; + case SkType_Float: + case SkType_Point: + case SkType_3D_Point: + return SkOperand2::kScalar; + case SkType_Base64: + case SkType_DynamicString: + case SkType_String: + return SkOperand2::kString; + case SkType_Array: + return SkOperand2::kArray; + case SkType_Unknown: + return SkOperand2::kNoType; + default: + SkASSERT(0); + return SkOperand2::kNoType; + } +} + +bool SkAnimatorScript2::MapEnums(const char* ptr, const char* match, size_t len, int* value) { + int index = 0; + bool more = true; + do { + const char* last = strchr(ptr, '|'); + if (last == nil) { + last = &ptr[strlen(ptr)]; + more = false; + } + size_t length = last - ptr; + if (len == length && strncmp(ptr, match, length) == 0) { + *value = index; + return true; + } + index++; + ptr = last + 1; + } while (more); + return false; +} + +#if defined SK_DEBUG + +#include "SkAnimator.h" + +static const char scriptTestSetup[] = +"<screenplay>" + "<apply>" + "<paint>" + "<emboss id='emboss' direction='[1,1,1]' />" + "</paint>" + "<animateField id='animation' field='direction' target='emboss' from='[1,1,1]' to='[-1,1,1]' dur='1'/>" + "<set lval='direction[0]' target='emboss' to='-1' />" + "</apply>" + "<color id='testColor' color='0 ? rgb(0,0,0) : rgb(255,255,255)' />" + "<color id='xColor' color='rgb(12,34,56)' />" + "<typedArray id='emptyArray' />" + "<typedArray id='intArray' values='[1, 4, 6]' />" + "<s32 id='idx' value='2' />" + "<s32 id='idy' value='2' />" + "<string id='alpha' value='abc' />" + "<rectangle id='testRect' left='Math.cos(0)' top='2' right='12' bottom='5' />" + "<event id='evt'>" + "<input name='x' />" + "<apply scope='idy'>" + "<set field='value' to='evt.x.s32' />" + "</apply>" + "</event>" +"</screenplay>"; + +#if !defined(SK_BUILD_FOR_BREW) +static const SkScriptNAnswer scriptTests[] = { + { "alpha+alpha", SkType_String, 0, 0, "abcabc" }, + { "0 ? Math.sin(0) : 1", SkType_Int, 1 }, + { "intArray[4]", SkType_Unknown }, + { "emptyArray[4]", SkType_Unknown }, + { "idx", SkType_Int, 2 }, + { "intArray.length", SkType_Int, 3 }, + { "intArray.values[0]", SkType_Int, 1 }, + { "intArray[0]", SkType_Int, 1 }, + { "idx.value", SkType_Int, 2 }, + { "alpha.value", SkType_String, 0, 0, "abc" }, + { "alpha", SkType_String, 0, 0, "abc" }, + { "alpha.value+alpha.value", SkType_String, 0, 0, "abcabc" }, + { "alpha+idx", SkType_String, 0, 0, "abc2" }, + { "idx+alpha", SkType_String, 0, 0, "2abc" }, + { "intArray[idx]", SkType_Int, 6 }, + { "alpha.slice(1,2)", SkType_String, 0, 0, "b" }, + { "alpha.value.slice(1,2)", SkType_String, 0, 0, "b" }, + { "Math.sin(0)", SkType_Float, 0, SkIntToScalar(0) }, + { "testRect.left+2", SkType_Float, 0, SkIntToScalar(3) }, + { "0 ? intArray[0] : 1", SkType_Int, 1 }, + { "0 ? intArray.values[0] : 1", SkType_Int, 1 }, + { "0 ? idx : 1", SkType_Int, 1 }, + { "0 ? idx.value : 1", SkType_Int, 1 }, + { "0 ? alpha.slice(1,2) : 1", SkType_Int, 1 }, + { "0 ? alpha.value.slice(1,2) : 1", SkType_Int, 1 }, + { "idy", SkType_Int, 3 } +}; +#endif + +#define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) + +void SkAnimatorScript2::UnitTest() { +#if !defined(SK_BUILD_FOR_BREW) && defined(SK_SUPPORT_UNITTEST) + SkAnimator animator; + SkASSERT(animator.decodeMemory(scriptTestSetup, sizeof(scriptTestSetup)-1)); + SkEvent evt; + evt.setString("id", "evt"); + evt.setS32("x", 3); + animator.doUserEvent(evt); + // set up animator with memory script above, then run value tests + for (int index = 0; index < SkScriptNAnswer_testCount; index++) { + SkAnimatorScript2 engine(*animator.fMaker, nil, scriptTests[index].fType); + SkScriptValue2 value; + const char* script = scriptTests[index].fScript; + bool success = engine.evaluateScript(&script, &value); + if (success == false) { + SkASSERT(scriptTests[index].fType == SkType_Unknown); + continue; + } + SkASSERT(value.fType == ToOpType(scriptTests[index].fType)); + SkScalar error; + switch (value.fType) { + case SkOperand2::kS32: + SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); + break; + case SkOperand2::kScalar: + error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); + SkASSERT(error < SK_Scalar1 / 10000); + break; + case SkOperand2::kString: + SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer)); + break; + default: + SkASSERT(0); + } + } +#endif +} + +#endif + diff --git a/libs/graphics/animator/SkAnimatorScript2.h b/libs/graphics/animator/SkAnimatorScript2.h new file mode 100755 index 0000000000..61261e91eb --- /dev/null +++ b/libs/graphics/animator/SkAnimatorScript2.h @@ -0,0 +1,43 @@ +#ifndef SkAnimatorScript2_DEFINED +#define SkAnimatorScript2_DEFINED + +#include "SkDisplayable.h" +#include "SkScript2.h" +#include "SkTypedArray.h" + +class SkAnimateMaker; +struct SkMemberInfo; + +#ifndef SkAnimatorScript_DEFINED +struct SkDisplayEnumMap { + SkDisplayTypes fType; + const char* fValues; +}; +#endif + +class SkAnimatorScript2 : public SkScriptEngine2 { +public: + SkAnimatorScript2(SkAnimateMaker& , SkDisplayable* working, SkDisplayTypes type); + ~SkAnimatorScript2(); + bool evalMemberCommon(const SkMemberInfo* info, + SkDisplayable* displayable, SkOperand2* value); + SkAnimateMaker& getMaker() { return fMaker; } + SkDisplayable* getWorking() { return fWorking; } + static bool MapEnums(const char* ptr, const char* match, size_t len, int* value); + static const SkDisplayEnumMap& GetEnumValues(SkDisplayTypes type); + static SkDisplayTypes ToDisplayType(SkOperand2::OpType type); + static SkOperand2::OpType ToOpType(SkDisplayTypes type); +private: + SkAnimateMaker& fMaker; + SkDisplayable* fWorking; + friend class SkDump; + friend struct SkScriptNAnswer; + // illegal + SkAnimatorScript2& operator=(const SkAnimatorScript2&); +#ifdef SK_DEBUG +public: + static void UnitTest(); +#endif +}; + +#endif // SkAnimatorScript2_DEFINED diff --git a/libs/graphics/animator/SkBase64.cpp b/libs/graphics/animator/SkBase64.cpp new file mode 100644 index 0000000000..664841ab1f --- /dev/null +++ b/libs/graphics/animator/SkBase64.cpp @@ -0,0 +1,171 @@ +#include "SkBase64.h" + +#define DecodePad -2 +#define EncodePad 64 + +static const char encode[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/="; + +static const signed char decodeData[] = { + 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, DecodePad, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 +}; + +SkBase64::SkBase64() : fLength((size_t) -1), fData(nil) { +} + +#if defined _WIN32 && _MSC_VER >= 1300 // disable 'two', etc. may be used without having been initialized +#pragma warning ( push ) +#pragma warning ( disable : 4701 ) +#endif + +SkBase64::Error SkBase64::decode(const void* srcPtr, size_t size, bool writeDestination) { + unsigned char* dst = (unsigned char*) fData; + const unsigned char* dstStart = (const unsigned char*) fData; + const unsigned char* src = (const unsigned char*) srcPtr; + bool padTwo = false; + bool padThree = false; + const unsigned char* end = src + size; + while (src < end) { + unsigned char bytes[4]; + int byte = 0; + do { + unsigned char srcByte = *src++; + if (srcByte == 0) + goto goHome; + if (srcByte <= ' ') + continue; // treat as white space + if (srcByte < '+' || srcByte > 'z') + return kBadCharError; + signed char decoded = decodeData[srcByte - '+']; + bytes[byte] = decoded; + if (decoded < 0) { + if (decoded == DecodePad) + goto handlePad; + return kBadCharError; + } else + byte++; + if (*src) + continue; + if (byte == 0) + goto goHome; + if (byte == 4) + break; +handlePad: + if (byte < 2) + return kPadError; + padThree = true; + if (byte == 2) + padTwo = true; + break; + } while (byte < 4); + int two, three; + if (writeDestination) { + int one = (U8) (bytes[0] << 2); + two = bytes[1]; + one |= two >> 4; + two = (U8) (two << 4); + three = bytes[2]; + two |= three >> 2; + three = (U8) (three << 6); + three |= bytes[3]; + SkASSERT(one < 256 && two < 256 && three < 256); + *dst = (unsigned char) one; + } + dst++; + if (padTwo) + break; + if (writeDestination) + *dst = (unsigned char) two; + dst++; + if (padThree) + break; + if (writeDestination) + *dst = (unsigned char) three; + dst++; + } +goHome: + fLength = dst - dstStart; + return kNoError; +} + +#if defined _WIN32 && _MSC_VER >= 1300 +#pragma warning ( pop ) +#endif + +size_t SkBase64::Encode(const void* srcPtr, size_t length, void* dstPtr) { + const unsigned char* src = (const unsigned char*) srcPtr; + unsigned char* dst = (unsigned char*) dstPtr; + if (dst) { + size_t remainder = length % 3; + const unsigned char* end = &src[length - remainder]; + while (src < end) { + unsigned a = *src++; + unsigned b = *src++; + unsigned c = *src++; + int d = c & 0x3F; + c = (c >> 6 | b << 2) & 0x3F; + b = (b >> 4 | a << 4) & 0x3F; + a = a >> 2; + *dst++ = encode[a]; + *dst++ = encode[b]; + *dst++ = encode[c]; + *dst++ = encode[d]; + } + if (remainder > 0) { + int k1 = 0; + int k2 = EncodePad; + int a = (U8) *src++; + if (remainder == 2) + { + int b = *src++; + k1 = b >> 4; + k2 = (b << 2) & 0x3F; + } + *dst++ = encode[a >> 2]; + *dst++ = encode[(k1 | a << 4) & 0x3F]; + *dst++ = encode[k2]; + *dst++ = encode[EncodePad]; + } + } + return (length + 2) / 3 * 4; +} + +SkBase64::Error SkBase64::decode(const char* src, size_t len) { + Error err = decode(src, len, false); + SkASSERT(err == kNoError); + if (err != kNoError) + return err; + fData = new char[fLength]; // should use sk_malloc/sk_free + decode(src, len, true); + return kNoError; +} + +#ifdef SK_SUPPORT_UNITTEST +void SkBase64::UnitTest() { + signed char all[256]; + for (int index = 0; index < 256; index++) + all[index] = (signed char) (index + 1); + for (int offset = 0; offset < 6; offset++) { + size_t length = 256 - offset; + size_t encodeLength = Encode(all + offset, length, nil); + char* src = (char*)sk_malloc_throw(encodeLength + 1); + Encode(all + offset, length, src); + src[encodeLength] = '\0'; + SkBase64 tryMe; + tryMe.decode(src, encodeLength); + SkASSERT(length == tryMe.fLength); + SkASSERT(strcmp((const char*) (all + offset), tryMe.fData) == 0); + sk_free(src); + delete[] tryMe.fData; + } +} +#endif + + diff --git a/libs/graphics/animator/SkBase64.h b/libs/graphics/animator/SkBase64.h new file mode 100644 index 0000000000..4132dd3d20 --- /dev/null +++ b/libs/graphics/animator/SkBase64.h @@ -0,0 +1,30 @@ +#ifndef SkBase64_DEFINED +#define SkBase64_DEFINED + +#include "SkTypes.h" + +struct SkBase64 { +public: + enum Error { + kNoError, + kPadError, + kBadCharError + }; + + SkBase64(); + Error decode(const char* src, size_t length); + char* getData() { return fData; } + static size_t Encode(const void* src, size_t length, void* dest); + +#ifdef SK_SUPPORT_UNITTEST + static void UnitTest(); +#endif +private: + Error decode(const void* srcPtr, size_t length, bool writeDestination); + + size_t fLength; + char* fData; + friend class SkImage; +}; + +#endif // SkBase64_DEFINED diff --git a/libs/graphics/animator/SkBoundable.cpp b/libs/graphics/animator/SkBoundable.cpp new file mode 100644 index 0000000000..92c8fd00b1 --- /dev/null +++ b/libs/graphics/animator/SkBoundable.cpp @@ -0,0 +1,47 @@ +#include "SkBoundable.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" + +SkBoundable::SkBoundable() { + clearBounds(); + fBounds.fTop = 0; + fBounds.fRight = 0; + fBounds.fBottom = 0; +} + +void SkBoundable::clearBounder() { + fBounds.fLeft = 0x7fff; +} + +void SkBoundable::getBounds(SkRect* rect) { + SkASSERT(rect); + if (fBounds.fLeft == (S16)0x8000U) { + INHERITED::getBounds(rect); + return; + } + rect->fLeft = SkIntToScalar(fBounds.fLeft); + rect->fTop = SkIntToScalar(fBounds.fTop); + rect->fRight = SkIntToScalar(fBounds.fRight); + rect->fBottom = SkIntToScalar(fBounds.fBottom); +} + +void SkBoundable::enableBounder() { + fBounds.fLeft = 0; +} + + +SkBoundableAuto::SkBoundableAuto(SkBoundable* boundable, + SkAnimateMaker& maker) : fBoundable(boundable), fMaker(maker) { + if (fBoundable->hasBounds()) { + fMaker.fCanvas->setBounder(&maker.fDisplayList); + fMaker.fDisplayList.fBounds.setEmpty(); + } +} + +SkBoundableAuto::~SkBoundableAuto() { + if (fBoundable->hasBounds() == false) + return; + fMaker.fCanvas->setBounder(nil); + fBoundable->setBounds(fMaker.fDisplayList.fBounds); +} + diff --git a/libs/graphics/animator/SkBoundable.h b/libs/graphics/animator/SkBoundable.h new file mode 100644 index 0000000000..d3e3586527 --- /dev/null +++ b/libs/graphics/animator/SkBoundable.h @@ -0,0 +1,33 @@ +#ifndef SkBoundable_DEFINED +#define SkBoundable_DEFINED + +#include "SkDrawable.h" +#include "SkRect.h" + +class SkBoundable : public SkDrawable { +public: + SkBoundable(); + virtual void clearBounder(); + virtual void enableBounder(); + virtual void getBounds(SkRect* ); + bool hasBounds() { return fBounds.fLeft != (S16)0x8000U; } + void setBounds(SkRect16& bounds) { fBounds = bounds; } +protected: + void clearBounds() { fBounds.fLeft = (S16) SkToU16(0x8000); }; // mark bounds as unset + SkRect16 fBounds; +private: + typedef SkDrawable INHERITED; +}; + +class SkBoundableAuto { +public: + SkBoundableAuto(SkBoundable* boundable, SkAnimateMaker& maker); + ~SkBoundableAuto(); +private: + SkBoundable* fBoundable; + SkAnimateMaker& fMaker; + SkBoundableAuto& operator= (const SkBoundableAuto& ); +}; + +#endif // SkBoundable_DEFINED + diff --git a/libs/graphics/animator/SkBuildCondensedInfo.cpp b/libs/graphics/animator/SkBuildCondensedInfo.cpp new file mode 100644 index 0000000000..6c29499302 --- /dev/null +++ b/libs/graphics/animator/SkBuildCondensedInfo.cpp @@ -0,0 +1,275 @@ +#include "SkTypes.h" +#if defined SK_BUILD_CONDENSED +#include "SkMemberInfo.h" +#if SK_USE_CONDENSED_INFO == 1 +#error "SK_USE_CONDENSED_INFO must be zero to build condensed info" +#endif +#if !defined SK_BUILD_FOR_WIN32 +#error "SK_BUILD_FOR_WIN32 must be defined to build condensed info" +#endif +#include "SkDisplayType.h" +#include "SkIntArray.h" +#include <stdio.h> + +SkTDMemberInfoArray gInfos; +SkTDIntArray gInfosCounts; +SkTDDisplayTypesArray gInfosTypeIDs; +SkTDMemberInfoArray gUnknowns; +SkTDIntArray gUnknownsCounts; + +static void AddInfo(SkDisplayTypes type, const SkMemberInfo* info, int infoCount) { + SkASSERT(gInfos[type] == nil); + gInfos[type] = info; + gInfosCounts[type] = infoCount; + *gInfosTypeIDs.append() = type; + size_t allStrs = 0; + for (int inner = 0; inner < infoCount; inner++) { + SkASSERT(info[inner].fCount < 256); + int offset = (int) info[inner].fOffset; + SkASSERT(offset < 128 && offset > -129); + SkASSERT(allStrs < 256); + if (info[inner].fType == SkType_BaseClassInfo) { + const SkMemberInfo* innerInfo = (const SkMemberInfo*) info[inner].fName; + if (gUnknowns.find(innerInfo) == -1) { + *gUnknowns.append() = innerInfo; + *gUnknownsCounts.append() = info[inner].fCount; + } + } + if (info[inner].fType != SkType_BaseClassInfo && info[inner].fName) + allStrs += strlen(info[inner].fName); + allStrs += 1; + SkASSERT(info[inner].fType < 256); + } +} + +static void WriteInfo(FILE* condensed, const SkMemberInfo* info, int infoCount, + const char* typeName, bool draw, bool display) { + fprintf(condensed, "static const char g%sStrings[] = \n", typeName); + int inner; + // write strings + for (inner = 0; inner < infoCount; inner++) { + const char* name = (info[inner].fType != SkType_BaseClassInfo && info[inner].fName) ? + info[inner].fName : ""; + const char* zero = inner < infoCount - 1 ? "\\0" : ""; + fprintf(condensed, "\t\"%s%s\"\n", name, zero); + } + fprintf(condensed, ";\n\nstatic const SkMemberInfo g%s", draw ? "Draw" : display ? "Display" : ""); + fprintf(condensed, "%sInfo[] = {", typeName); + size_t nameOffset = 0; + // write info tables + for (inner = 0; inner < infoCount; inner++) { + size_t offset = info[inner].fOffset; + if (info[inner].fType == SkType_BaseClassInfo) { + offset = (size_t) gInfos.find((const SkMemberInfo* ) info[inner].fName); + SkASSERT((int) offset >= 0); + offset = gInfosTypeIDs.find((SkDisplayTypes) offset); + SkASSERT((int) offset >= 0); + } + fprintf(condensed, "\n\t{%d, %d, %d, %d}", nameOffset, offset, + info[inner].fType, info[inner].fCount); + if (inner < infoCount - 1) + putc(',', condensed); + if (info[inner].fType != SkType_BaseClassInfo && info[inner].fName) + nameOffset += strlen(info[inner].fName); + nameOffset += 1; + } + fprintf(condensed, "\n};\n\n"); +} + +static void Get3DName(char* scratch, const char* name) { + if (strncmp("skia3d:", name, sizeof("skia3d:") - 1) == 0) { + strcpy(scratch, "3D_"); + scratch[3]= name[7] & ~0x20; + strcpy(&scratch[4], &name[8]); + } else { + scratch[0] = name[0] & ~0x20; + strcpy(&scratch[1], &name[1]); + } +} + +int type_compare(const void* a, const void* b) { + SkDisplayTypes first = *(SkDisplayTypes*) a; + SkDisplayTypes second = *(SkDisplayTypes*) b; + return first < second ? -1 : first == second ? 0 : 1; +} + +void SkDisplayType::BuildCondensedInfo(SkAnimateMaker* maker) { + gInfos.setCount(kNumberOfTypes); + memset(gInfos.begin(), 0, sizeof(gInfos[0]) * kNumberOfTypes); + gInfosCounts.setCount(kNumberOfTypes); + memset(gInfosCounts.begin(), -1, sizeof(gInfosCounts[0]) * kNumberOfTypes); + // check to see if it is condensable + int index, infoCount; + for (index = 0; index < kTypeNamesSize; index++) { + const SkMemberInfo* info = GetMembers(maker, gTypeNames[index].fType, &infoCount); + if (info == nil) + continue; + AddInfo(gTypeNames[index].fType, info, infoCount); + } + const SkMemberInfo* extraInfo = + SkDisplayType::GetMembers(maker, SkType_3D_Point, &infoCount); + AddInfo(SkType_Point, extraInfo, infoCount); + AddInfo(SkType_3D_Point, extraInfo, infoCount); +// int baseInfos = gInfos.count(); + do { + SkTDMemberInfoArray oldRefs = gUnknowns; + SkTDIntArray oldRefCounts = gUnknownsCounts; + gUnknowns.reset(); + gUnknownsCounts.reset(); + for (index = 0; index < oldRefs.count(); index++) { + const SkMemberInfo* info = oldRefs[index]; + if (gInfos.find(info) == -1) { + int typeIndex = 0; + for (; typeIndex < kNumberOfTypes; typeIndex++) { + const SkMemberInfo* temp = SkDisplayType::GetMembers( + maker, (SkDisplayTypes) typeIndex, nil); + if (temp == info) + break; + } + SkASSERT(typeIndex < kNumberOfTypes); + AddInfo((SkDisplayTypes) typeIndex, info, oldRefCounts[index]); + } + } + } while (gUnknowns.count() > 0); + qsort(gInfosTypeIDs.begin(), gInfosTypeIDs.count(), sizeof(gInfosTypeIDs[0]), &type_compare); +#ifdef SK_DEBUG + FILE* condensed = fopen("../../src/animator/SkCondensedDebug.cpp", "w+"); + fprintf(condensed, "#include \"SkTypes.h\"\n"); + fprintf(condensed, "#ifdef SK_DEBUG\n"); +#else + FILE* condensed = fopen("../../src/animator/SkCondensedRelease.cpp", "w+"); + fprintf(condensed, "#include \"SkTypes.h\"\n"); + fprintf(condensed, "#ifdef SK_RELEASE\n"); +#endif + // write header + fprintf(condensed, "// This file was automatically generated.\n"); + fprintf(condensed, "// To change it, edit the file with the matching debug info.\n"); + fprintf(condensed, "// Then execute SkDisplayType::BuildCondensedInfo() to " + "regenerate this file.\n\n"); + // write name of memberInfo + int typeNameIndex = 0; + int unknown = 1; + for (index = 0; index < gInfos.count(); index++) { + const SkMemberInfo* info = gInfos[index]; + if (info == nil) + continue; + char scratch[64]; + bool drawPrefix, displayPrefix; + while (gTypeNames[typeNameIndex].fType < index) + typeNameIndex++; + if (gTypeNames[typeNameIndex].fType == index) { + Get3DName(scratch, gTypeNames[typeNameIndex].fName); + drawPrefix = gTypeNames[typeNameIndex].fDrawPrefix; + displayPrefix = gTypeNames[typeNameIndex].fDisplayPrefix; + } else { + sprintf(scratch, "Unknown%d", unknown++); + drawPrefix = displayPrefix = false; + } + WriteInfo(condensed, info, gInfosCounts[index], scratch, drawPrefix, displayPrefix); + } + // write array of table pointers +// start here; + fprintf(condensed, "static const SkMemberInfo* const gInfoTables[] = {"); + typeNameIndex = 0; + unknown = 1; + for (index = 0; index < gInfos.count(); index++) { + const SkMemberInfo* info = gInfos[index]; + if (info == nil) + continue; + char scratch[64]; + bool drawPrefix, displayPrefix; + while (gTypeNames[typeNameIndex].fType < index) + typeNameIndex++; + if (gTypeNames[typeNameIndex].fType == index) { + Get3DName(scratch, gTypeNames[typeNameIndex].fName); + drawPrefix = gTypeNames[typeNameIndex].fDrawPrefix; + displayPrefix = gTypeNames[typeNameIndex].fDisplayPrefix; + } else { + sprintf(scratch, "Unknown%d", unknown++); + drawPrefix = displayPrefix = false; + } + fprintf(condensed, "\n\tg"); + if (drawPrefix) + fprintf(condensed, "Draw"); + if (displayPrefix) + fprintf(condensed, "Display"); + fprintf(condensed, "%sInfo", scratch); + if (index < gInfos.count() - 1) + putc(',', condensed); + } + fprintf(condensed, "\n};\n\n"); + // write the array of number of entries in the info table + fprintf(condensed, "static const unsigned char gInfoCounts[] = {\n\t"); + int written = 0; + for (index = 0; index < gInfosCounts.count(); index++) { + int count = gInfosCounts[index]; + if (count < 0) + continue; + if (written > 0) + putc(',', condensed); + if (written % 20 == 19) + fprintf(condensed, "\n\t"); + fprintf(condensed, "%d",count); + written++; + } + fprintf(condensed, "\n};\n\n"); + // write array of type ids table entries correspond to + fprintf(condensed, "static const unsigned char gTypeIDs[] = {\n\t"); + int typeIDCount = 0; + typeNameIndex = 0; + unknown = 1; + for (index = 0; index < gInfosCounts.count(); index++) { + const SkMemberInfo* info = gInfos[index]; + if (info == nil) + continue; + typeIDCount++; + char scratch[64]; + while (gTypeNames[typeNameIndex].fType < index) + typeNameIndex++; + if (gTypeNames[typeNameIndex].fType == index) { + Get3DName(scratch, gTypeNames[typeNameIndex].fName); + } else + sprintf(scratch, "Unknown%d", unknown++); + fprintf(condensed, "%d%c // %s\n\t", index, + index < gInfosCounts.count() ? ',' : ' ', scratch); + } + fprintf(condensed, "\n};\n\n"); + fprintf(condensed, "static const int kTypeIDs = %d;\n\n", typeIDCount); + // write the array of string pointers + fprintf(condensed, "static const char* const gInfoNames[] = {"); + typeNameIndex = 0; + unknown = 1; + written = 0; + for (index = 0; index < gInfosCounts.count(); index++) { + const SkMemberInfo* info = gInfos[index]; + if (info == nil) + continue; + if (written > 0) + putc(',', condensed); + written++; + fprintf(condensed, "\n\tg"); + char scratch[64]; + while (gTypeNames[typeNameIndex].fType < index) + typeNameIndex++; + if (gTypeNames[typeNameIndex].fType == index) { + Get3DName(scratch, gTypeNames[typeNameIndex].fName); + } else + sprintf(scratch, "Unknown%d", unknown++); + fprintf(condensed, "%sStrings", scratch); + } + fprintf(condensed, "\n};\n\n"); + fprintf(condensed, "#endif\n"); + fclose(condensed); + gInfos.reset(); + gInfosCounts.reset(); + gInfosTypeIDs.reset(); + gUnknowns.reset(); + gUnknownsCounts.reset(); +} + +#elif defined SK_DEBUG +#include "SkDisplayType.h" +void SkDisplayType::BuildCondensedInfo(SkAnimateMaker* ) {} +#endif + + diff --git a/libs/graphics/animator/SkCondensedDebug.cpp b/libs/graphics/animator/SkCondensedDebug.cpp new file mode 100644 index 0000000000..f60487ba87 --- /dev/null +++ b/libs/graphics/animator/SkCondensedDebug.cpp @@ -0,0 +1,1380 @@ +#include "SkTypes.h" +#ifndef SK_BUILD_FOR_UNIX +#ifdef SK_DEBUG +// This file was automatically generated. +// To change it, edit the file with the matching debug info. +// Then execute SkDisplayType::BuildCondensedInfo() to regenerate this file. + +static const char gMathStrings[] = + "E\0" + "LN10\0" + "LN2\0" + "LOG10E\0" + "LOG2E\0" + "PI\0" + "SQRT1_2\0" + "SQRT2\0" + "abs\0" + "acos\0" + "asin\0" + "atan\0" + "atan2\0" + "ceil\0" + "cos\0" + "exp\0" + "floor\0" + "log\0" + "max\0" + "min\0" + "pow\0" + "random\0" + "round\0" + "sin\0" + "sqrt\0" + "tan" +; + +static const SkMemberInfo gMathInfo[] = { + {0, -1, 67, 98}, + {2, -2, 67, 98}, + {7, -3, 67, 98}, + {11, -4, 67, 98}, + {18, -5, 67, 98}, + {24, -6, 67, 98}, + {27, -7, 67, 98}, + {35, -8, 67, 98}, + {41, -1, 66, 98}, + {45, -2, 66, 98}, + {50, -3, 66, 98}, + {55, -4, 66, 98}, + {60, -5, 66, 98}, + {66, -6, 66, 98}, + {71, -7, 66, 98}, + {75, -8, 66, 98}, + {79, -9, 66, 98}, + {85, -10, 66, 98}, + {89, -11, 66, 98}, + {93, -12, 66, 98}, + {97, -13, 66, 98}, + {101, -14, 66, 98}, + {108, -15, 66, 98}, + {114, -16, 66, 98}, + {118, -17, 66, 98}, + {123, -18, 66, 98} +}; + +static const char gAddStrings[] = + "inPlace\0" + "offset\0" + "use\0" + "where" +; + +static const SkMemberInfo gAddInfo[] = { + {0, 16, 26, 1}, + {8, 20, 96, 1}, + {15, 24, 37, 1}, + {19, 28, 37, 1} +}; + +static const char gAddCircleStrings[] = + "\0" + "radius\0" + "x\0" + "y" +; + +static const SkMemberInfo gAddCircleInfo[] = { + {0, 3, 18, 1}, + {1, 24, 98, 1}, + {8, 28, 98, 1}, + {10, 32, 98, 1} +}; + +static const char gUnknown1Strings[] = + "direction" +; + +static const SkMemberInfo gUnknown1Info[] = { + {0, 20, 75, 1} +}; + +static const char gAddOvalStrings[] = + "" +; + +static const SkMemberInfo gAddOvalInfo[] = { + {0, 6, 18, 5} +}; + +static const char gAddPathStrings[] = + "matrix\0" + "path" +; + +static const SkMemberInfo gAddPathInfo[] = { + {0, 20, 65, 1}, + {7, 24, 74, 1} +}; + +static const char gAddRectangleStrings[] = + "\0" + "bottom\0" + "left\0" + "right\0" + "top" +; + +static const SkMemberInfo gAddRectangleInfo[] = { + {0, 3, 18, 1}, + {1, 36, 98, 1}, + {8, 24, 98, 1}, + {13, 32, 98, 1}, + {19, 28, 98, 1} +}; + +static const char gAddRoundRectStrings[] = + "\0" + "rx\0" + "ry" +; + +static const SkMemberInfo gAddRoundRectInfo[] = { + {0, 6, 18, 5}, + {1, 40, 98, 1}, + {4, 44, 98, 1} +}; + +static const char gUnknown2Strings[] = + "begin\0" + "blend\0" + "dur\0" + "dynamic\0" + "field\0" + "formula\0" + "from\0" + "mirror\0" + "repeat\0" + "reset\0" + "target\0" + "to\0" + "values" +; + +static const SkMemberInfo gUnknown2Info[] = { + {0, 16, 71, 1}, + {6, 20, 119, 98}, + {12, 36, 71, 1}, + {16, -1, 67, 26}, + {24, 40, 108, 2}, + {30, 48, 40, 2}, + {38, 56, 40, 2}, + {43, -2, 67, 26}, + {50, 64, 98, 1}, + {57, -3, 67, 26}, + {63, 68, 40, 2}, + {70, 76, 40, 2}, + {73, -4, 67, 40} +}; + +static const char gAnimateFieldStrings[] = + "" +; + +static const SkMemberInfo gAnimateFieldInfo[] = { + {0, 8, 18, 13} +}; + +static const char gApplyStrings[] = + "animator\0" + "begin\0" + "dontDraw\0" + "dynamicScope\0" + "interval\0" + "mode\0" + "pickup\0" + "restore\0" + "scope\0" + "step\0" + "steps\0" + "time\0" + "transition" +; + +static const SkMemberInfo gApplyInfo[] = { + {0, -1, 67, 10}, + {9, 16, 71, 1}, + {15, 20, 26, 1}, + {24, 24, 108, 2}, + {37, 32, 71, 1}, + {46, 36, 13, 1}, + {51, 40, 26, 1}, + {58, 44, 26, 1}, + {66, 48, 37, 1}, + {72, -2, 67, 96}, + {77, 52, 96, 1}, + {83, -3, 67, 71}, + {88, 56, 14, 1} +}; + +static const char gUnknown3Strings[] = + "x\0" + "y" +; + +static const SkMemberInfo gUnknown3Info[] = { + {0, 48, 98, 1}, + {2, 52, 98, 1} +}; + +static const char gBitmapStrings[] = + "\0" + "erase\0" + "format\0" + "height\0" + "rowBytes\0" + "width" +; + +static const SkMemberInfo gDrawBitmapInfo[] = { + {0, 11, 18, 2}, + {1, -1, 67, 15}, + {7, 56, 21, 1}, + {14, 60, 96, 1}, + {21, 64, 96, 1}, + {30, 68, 96, 1} +}; + +static const char gBitmapShaderStrings[] = + "\0" + "filterType\0" + "image" +; + +static const SkMemberInfo gDrawBitmapShaderInfo[] = { + {0, 67, 18, 2}, + {1, 28, 47, 1}, + {12, 32, 17, 1} +}; + +static const char gBlurStrings[] = + "blurStyle\0" + "radius" +; + +static const SkMemberInfo gDrawBlurInfo[] = { + {0, 24, 63, 1}, + {10, 20, 98, 1} +}; + +static const char gBoundsStrings[] = + "\0" + "inval" +; + +static const SkMemberInfo gDisplayBoundsInfo[] = { + {0, 58, 18, 7}, + {1, 44, 26, 1} +}; + +static const char gClipStrings[] = + "path\0" + "rectangle" +; + +static const SkMemberInfo gDrawClipInfo[] = { + {0, 20, 74, 1}, + {5, 16, 91, 1} +}; + +static const char gColorStrings[] = + "alpha\0" + "blue\0" + "color\0" + "green\0" + "hue\0" + "red\0" + "saturation\0" + "value" +; + +static const SkMemberInfo gDrawColorInfo[] = { + {0, -1, 67, 98}, + {6, -2, 67, 98}, + {11, 20, 15, 1}, + {17, -3, 67, 98}, + {23, -4, 67, 98}, + {27, -5, 67, 98}, + {31, -6, 67, 98}, + {42, -7, 67, 98} +}; + +static const char gCubicToStrings[] = + "x1\0" + "x2\0" + "x3\0" + "y1\0" + "y2\0" + "y3" +; + +static const SkMemberInfo gCubicToInfo[] = { + {0, 20, 98, 1}, + {3, 28, 98, 1}, + {6, 36, 98, 1}, + {9, 24, 98, 1}, + {12, 32, 98, 1}, + {15, 40, 98, 1} +}; + +static const char gDashStrings[] = + "intervals\0" + "phase" +; + +static const SkMemberInfo gDashInfo[] = { + {0, 20, 119, 98}, + {10, 36, 98, 1} +}; + +static const char gDataStrings[] = + "\0" + "name" +; + +static const SkMemberInfo gDataInfo[] = { + {0, 33, 18, 3}, + {1, 32, 108, 2} +}; + +static const char gDiscreteStrings[] = + "deviation\0" + "segLength" +; + +static const SkMemberInfo gDiscreteInfo[] = { + {0, 20, 98, 1}, + {10, 24, 98, 1} +}; + +static const char gDrawToStrings[] = + "drawOnce\0" + "use" +; + +static const SkMemberInfo gDrawToInfo[] = { + {0, 72, 26, 1}, + {9, 76, 19, 1} +}; + +static const char gDumpStrings[] = + "displayList\0" + "eventList\0" + "events\0" + "groups\0" + "name\0" + "posts" +; + +static const SkMemberInfo gDumpInfo[] = { + {0, 16, 26, 1}, + {12, 20, 26, 1}, + {22, 24, 26, 1}, + {29, 36, 26, 1}, + {36, 28, 108, 2}, + {41, 40, 26, 1} +}; + +static const char gEmbossStrings[] = + "ambient\0" + "direction\0" + "radius\0" + "specular" +; + +static const SkMemberInfo gDrawEmbossInfo[] = { + {0, -1, 67, 98}, + {8, 20, 119, 98}, + {18, 36, 98, 1}, + {25, -2, 67, 98} +}; + +static const char gEventStrings[] = + "code\0" + "disable\0" + "key\0" + "keys\0" + "kind\0" + "target\0" + "x\0" + "y" +; + +static const SkMemberInfo gDisplayEventInfo[] = { + {0, 16, 43, 1}, + {5, 20, 26, 1}, + {13, -1, 67, 108}, + {17, -2, 67, 108}, + {22, 24, 44, 1}, + {27, 28, 108, 2}, + {34, 36, 98, 1}, + {36, 40, 98, 1} +}; + +static const char gFromPathStrings[] = + "mode\0" + "offset\0" + "path" +; + +static const SkMemberInfo gFromPathInfo[] = { + {0, 20, 49, 1}, + {5, 24, 98, 1}, + {12, 28, 74, 1} +}; + +static const char gUnknown4Strings[] = + "\0" + "offsets\0" + "unitMapper" +; + +static const SkMemberInfo gUnknown4Info[] = { + {0, 67, 18, 2}, + {1, 28, 119, 98}, + {9, 44, 108, 2} +}; + +static const char gGStrings[] = + "condition\0" + "enableCondition" +; + +static const SkMemberInfo gGInfo[] = { + {0, 16, 40, 2}, + {10, 24, 40, 2} +}; + +static const char gHitClearStrings[] = + "targets" +; + +static const SkMemberInfo gHitClearInfo[] = { + {0, 16, 119, 36} +}; + +static const char gHitTestStrings[] = + "bullets\0" + "hits\0" + "targets\0" + "value" +; + +static const SkMemberInfo gHitTestInfo[] = { + {0, 16, 119, 36}, + {8, 32, 119, 96}, + {13, 48, 119, 36}, + {21, 64, 26, 1} +}; + +static const char gImageStrings[] = + "\0" + "base64\0" + "src" +; + +static const SkMemberInfo gImageInfo[] = { + {0, 11, 18, 2}, + {1, 56, 16, 2}, + {8, 64, 108, 2} +}; + +static const char gIncludeStrings[] = + "src" +; + +static const SkMemberInfo gIncludeInfo[] = { + {0, 16, 108, 2} +}; + +static const char gInputStrings[] = + "s32\0" + "scalar\0" + "string" +; + +static const SkMemberInfo gInputInfo[] = { + {0, 16, 96, 1}, + {4, 20, 98, 1}, + {11, 24, 108, 2} +}; + +static const char gLineStrings[] = + "x1\0" + "x2\0" + "y1\0" + "y2" +; + +static const SkMemberInfo gLineInfo[] = { + {0, 24, 98, 1}, + {3, 28, 98, 1}, + {6, 32, 98, 1}, + {9, 36, 98, 1} +}; + +static const char gLineToStrings[] = + "x\0" + "y" +; + +static const SkMemberInfo gLineToInfo[] = { + {0, 20, 98, 1}, + {2, 24, 98, 1} +}; + +static const char gLinearGradientStrings[] = + "\0" + "points" +; + +static const SkMemberInfo gLinearGradientInfo[] = { + {0, 27, 18, 3}, + {1, 88, 77, 4} +}; + +static const char gMatrixStrings[] = + "matrix\0" + "perspectX\0" + "perspectY\0" + "rotate\0" + "scale\0" + "scaleX\0" + "scaleY\0" + "skewX\0" + "skewY\0" + "translate\0" + "translateX\0" + "translateY" +; + +static const SkMemberInfo gDrawMatrixInfo[] = { + {0, 16, 119, 98}, + {7, -1, 67, 98}, + {17, -2, 67, 98}, + {27, -3, 67, 98}, + {34, -4, 67, 98}, + {40, -5, 67, 98}, + {47, -6, 67, 98}, + {54, -7, 67, 98}, + {60, -8, 67, 98}, + {66, -9, 67, 77}, + {76, -10, 67, 98}, + {87, -11, 67, 98} +}; + +static const char gMoveStrings[] = + "" +; + +static const SkMemberInfo gMoveInfo[] = { + {0, 1, 18, 4} +}; + +static const char gMoveToStrings[] = + "x\0" + "y" +; + +static const SkMemberInfo gMoveToInfo[] = { + {0, 20, 98, 1}, + {2, 24, 98, 1} +}; + +static const char gMovieStrings[] = + "src" +; + +static const SkMemberInfo gMovieInfo[] = { + {0, 16, 108, 2} +}; + +static const char gOvalStrings[] = + "" +; + +static const SkMemberInfo gOvalInfo[] = { + {0, 58, 18, 7} +}; + +static const char gPaintStrings[] = + "antiAlias\0" + "ascent\0" + "color\0" + "descent\0" + "filterType\0" + "linearText\0" + "maskFilter\0" + "measureText\0" + "pathEffect\0" + "shader\0" + "strikeThru\0" + "stroke\0" + "strokeCap\0" + "strokeJoin\0" + "strokeMiter\0" + "strokeWidth\0" + "style\0" + "textAlign\0" + "textScaleX\0" + "textSize\0" + "textSkewX\0" + "textTracking\0" + "typeface\0" + "underline\0" + "xfermode" +; + +static const SkMemberInfo gDrawPaintInfo[] = { + {0, 16, 26, 1}, + {10, -1, 67, 98}, + {17, 20, 31, 1}, + {23, -2, 67, 98}, + {31, 24, 47, 1}, + {42, 28, 26, 1}, + {53, 32, 62, 1}, + {64, -1, 66, 98}, + {76, 36, 76, 1}, + {87, 40, 102, 1}, + {94, 44, 26, 1}, + {105, 48, 26, 1}, + {112, 52, 27, 1}, + {122, 56, 58, 1}, + {133, 60, 98, 1}, + {145, 64, 98, 1}, + {157, 68, 109, 1}, + {163, 72, 9, 1}, + {173, 76, 98, 1}, + {184, 80, 98, 1}, + {193, 84, 98, 1}, + {203, 88, 98, 1}, + {216, 92, 120, 1}, + {225, 96, 26, 1}, + {235, 100, 121, 1} +}; + +static const char gPathStrings[] = + "d\0" + "fillType\0" + "length" +; + +static const SkMemberInfo gDrawPathInfo[] = { + {0, 52, 108, 2}, + {2, -1, 67, 46}, + {11, -2, 67, 98} +}; + +static const char gUnknown5Strings[] = + "x\0" + "y\0" + "z" +; + +static const SkMemberInfo gUnknown5Info[] = { + {0, 0, 98, 1}, + {2, 4, 98, 1}, + {4, 8, 98, 1} +}; + +static const char gPointStrings[] = + "x\0" + "y" +; + +static const SkMemberInfo gDrawPointInfo[] = { + {0, 16, 98, 1}, + {2, 20, 98, 1} +}; + +static const char gPolyToPolyStrings[] = + "destination\0" + "source" +; + +static const SkMemberInfo gPolyToPolyInfo[] = { + {0, 24, 80, 1}, + {12, 20, 80, 1} +}; + +static const char gPolygonStrings[] = + "" +; + +static const SkMemberInfo gPolygonInfo[] = { + {0, 48, 18, 1} +}; + +static const char gPolylineStrings[] = + "points" +; + +static const SkMemberInfo gPolylineInfo[] = { + {0, 88, 119, 98} +}; + +static const char gPostStrings[] = + "delay\0" + "initialized\0" + "mode\0" + "sink\0" + "target\0" + "type" +; + +static const SkMemberInfo gPostInfo[] = { + {0, 16, 71, 1}, + {6, 20, 26, 1}, + {18, 24, 45, 1}, + {23, -1, 67, 108}, + {28, -2, 67, 108}, + {35, -3, 67, 108} +}; + +static const char gQuadToStrings[] = + "x1\0" + "x2\0" + "y1\0" + "y2" +; + +static const SkMemberInfo gQuadToInfo[] = { + {0, 20, 98, 1}, + {3, 28, 98, 1}, + {6, 24, 98, 1}, + {9, 32, 98, 1} +}; + +static const char gRCubicToStrings[] = + "" +; + +static const SkMemberInfo gRCubicToInfo[] = { + {0, 18, 18, 6} +}; + +static const char gRLineToStrings[] = + "" +; + +static const SkMemberInfo gRLineToInfo[] = { + {0, 35, 18, 2} +}; + +static const char gRMoveToStrings[] = + "" +; + +static const SkMemberInfo gRMoveToInfo[] = { + {0, 39, 18, 2} +}; + +static const char gRQuadToStrings[] = + "" +; + +static const SkMemberInfo gRQuadToInfo[] = { + {0, 50, 18, 4} +}; + +static const char gRadialGradientStrings[] = + "\0" + "center\0" + "radius" +; + +static const SkMemberInfo gRadialGradientInfo[] = { + {0, 27, 18, 3}, + {1, 88, 77, 2}, + {8, 96, 98, 1} +}; + +static const char gRandomStrings[] = + "blend\0" + "max\0" + "min\0" + "random\0" + "seed" +; + +static const SkMemberInfo gDisplayRandomInfo[] = { + {0, 16, 98, 1}, + {6, 24, 98, 1}, + {10, 20, 98, 1}, + {14, 1, 67, 98}, + {21, -2, 67, 96} +}; + +static const char gRectToRectStrings[] = + "destination\0" + "source" +; + +static const SkMemberInfo gRectToRectInfo[] = { + {0, 24, 91, 1}, + {12, 20, 91, 1} +}; + +static const char gRectangleStrings[] = + "bottom\0" + "height\0" + "left\0" + "needsRedraw\0" + "right\0" + "top\0" + "width" +; + +static const SkMemberInfo gRectangleInfo[] = { + {0, 36, 98, 1}, + {7, -1, 67, 98}, + {14, 24, 98, 1}, + {19, -2, 67, 26}, + {31, 32, 98, 1}, + {37, 28, 98, 1}, + {41, -3, 67, 98} +}; + +static const char gRemoveStrings[] = + "offset\0" + "where" +; + +static const SkMemberInfo gRemoveInfo[] = { + {0, 20, 96, 1}, + {7, 28, 37, 1} +}; + +static const char gReplaceStrings[] = + "" +; + +static const SkMemberInfo gReplaceInfo[] = { + {0, 1, 18, 4} +}; + +static const char gRotateStrings[] = + "center\0" + "degrees" +; + +static const SkMemberInfo gRotateInfo[] = { + {0, 24, 77, 2}, + {7, 20, 98, 1} +}; + +static const char gRoundRectStrings[] = + "\0" + "rx\0" + "ry" +; + +static const SkMemberInfo gRoundRectInfo[] = { + {0, 58, 18, 7}, + {1, 44, 98, 1}, + {4, 48, 98, 1} +}; + +static const char gS32Strings[] = + "value" +; + +static const SkMemberInfo gS32Info[] = { + {0, 16, 96, 1} +}; + +static const char gScalarStrings[] = + "value" +; + +static const SkMemberInfo gScalarInfo[] = { + {0, 16, 98, 1} +}; + +static const char gScaleStrings[] = + "center\0" + "x\0" + "y" +; + +static const SkMemberInfo gScaleInfo[] = { + {0, 28, 77, 2}, + {7, 20, 98, 1}, + {9, 24, 98, 1} +}; + +static const char gSetStrings[] = + "begin\0" + "dur\0" + "dynamic\0" + "field\0" + "formula\0" + "reset\0" + "target\0" + "to" +; + +static const SkMemberInfo gSetInfo[] = { + {0, 16, 71, 1}, + {6, 36, 71, 1}, + {10, -1, 67, 26}, + {18, 40, 108, 2}, + {24, 48, 40, 2}, + {32, -3, 67, 26}, + {38, 68, 40, 2}, + {45, 76, 40, 2} +}; + +static const char gShaderStrings[] = + "matrix\0" + "tileMode" +; + +static const SkMemberInfo gShaderInfo[] = { + {0, 20, 65, 1}, + {7, 24, 116, 1} +}; + +static const char gSkewStrings[] = + "center\0" + "x\0" + "y" +; + +static const SkMemberInfo gSkewInfo[] = { + {0, 28, 77, 2}, + {7, 20, 98, 1}, + {9, 24, 98, 1} +}; + +static const char g3D_CameraStrings[] = + "axis\0" + "hackHeight\0" + "hackWidth\0" + "location\0" + "observer\0" + "patch\0" + "zenith" +; + +static const SkMemberInfo g3D_CameraInfo[] = { + {0, 36, 106, 3}, + {5, 20, 98, 1}, + {16, 16, 98, 1}, + {26, 24, 106, 3}, + {35, 60, 106, 3}, + {44, 108, 105, 1}, + {50, 48, 106, 3} +}; + +static const char g3D_PatchStrings[] = + "origin\0" + "rotateDegrees\0" + "u\0" + "v" +; + +static const SkMemberInfo g3D_PatchInfo[] = { + {0, 40, 106, 3}, + {7, -1, 66, 98}, + {21, 16, 106, 3}, + {23, 28, 106, 3} +}; + +static const char gUnknown6Strings[] = + "x\0" + "y\0" + "z" +; + +static const SkMemberInfo gUnknown6Info[] = { + {0, 0, 98, 1}, + {2, 4, 98, 1}, + {4, 8, 98, 1} +}; + +static const char gSnapshotStrings[] = + "filename\0" + "quality\0" + "sequence\0" + "type" +; + +static const SkMemberInfo gSnapshotInfo[] = { + {0, 16, 108, 2}, + {9, 24, 98, 1}, + {17, 28, 26, 1}, + {26, 32, 20, 1} +}; + +static const char gStringStrings[] = + "length\0" + "slice\0" + "value" +; + +static const SkMemberInfo gStringInfo[] = { + {0, -1, 67, 96}, + {7, -1, 66, 108}, + {13, 16, 108, 2} +}; + +static const char gTextStrings[] = + "length\0" + "text\0" + "x\0" + "y" +; + +static const SkMemberInfo gTextInfo[] = { + {0, -1, 67, 96}, + {7, 24, 108, 2}, + {12, 32, 98, 1}, + {14, 36, 98, 1} +}; + +static const char gTextBoxStrings[] = + "\0" + "mode\0" + "spacingAdd\0" + "spacingAlign\0" + "spacingMul\0" + "text" +; + +static const SkMemberInfo gTextBoxInfo[] = { + {0, 58, 18, 7}, + {1, 60, 113, 1}, + {6, 56, 98, 1}, + {17, 64, 112, 1}, + {30, 52, 98, 1}, + {41, 44, 108, 2} +}; + +static const char gTextOnPathStrings[] = + "offset\0" + "path\0" + "text" +; + +static const SkMemberInfo gTextOnPathInfo[] = { + {0, 24, 98, 1}, + {7, 28, 74, 1}, + {12, 32, 110, 1} +}; + +static const char gTextToPathStrings[] = + "path\0" + "text" +; + +static const SkMemberInfo gTextToPathInfo[] = { + {0, 16, 74, 1}, + {5, 20, 110, 1} +}; + +static const char gTranslateStrings[] = + "x\0" + "y" +; + +static const SkMemberInfo gTranslateInfo[] = { + {0, 20, 98, 1}, + {2, 24, 98, 1} +}; + +static const char gTypedArrayStrings[] = + "length\0" + "values" +; + +static const SkMemberInfo gTypedArrayInfo[] = { + {0, -1, 67, 96}, + {7, 16, 119, 0} +}; + +static const char gTypefaceStrings[] = + "fontName" +; + +static const SkMemberInfo gTypefaceInfo[] = { + {0, 20, 108, 2} +}; + +static const SkMemberInfo* const gInfoTables[] = { + gMathInfo, + gAddInfo, + gAddCircleInfo, + gUnknown1Info, + gAddOvalInfo, + gAddPathInfo, + gAddRectangleInfo, + gAddRoundRectInfo, + gUnknown2Info, + gAnimateFieldInfo, + gApplyInfo, + gUnknown3Info, + gDrawBitmapInfo, + gDrawBitmapShaderInfo, + gDrawBlurInfo, + gDisplayBoundsInfo, + gDrawClipInfo, + gDrawColorInfo, + gCubicToInfo, + gDashInfo, + gDataInfo, + gDiscreteInfo, + gDrawToInfo, + gDumpInfo, + gDrawEmbossInfo, + gDisplayEventInfo, + gFromPathInfo, + gUnknown4Info, + gGInfo, + gHitClearInfo, + gHitTestInfo, + gImageInfo, + gIncludeInfo, + gInputInfo, + gLineInfo, + gLineToInfo, + gLinearGradientInfo, + gDrawMatrixInfo, + gMoveInfo, + gMoveToInfo, + gMovieInfo, + gOvalInfo, + gDrawPaintInfo, + gDrawPathInfo, + gUnknown5Info, + gDrawPointInfo, + gPolyToPolyInfo, + gPolygonInfo, + gPolylineInfo, + gPostInfo, + gQuadToInfo, + gRCubicToInfo, + gRLineToInfo, + gRMoveToInfo, + gRQuadToInfo, + gRadialGradientInfo, + gDisplayRandomInfo, + gRectToRectInfo, + gRectangleInfo, + gRemoveInfo, + gReplaceInfo, + gRotateInfo, + gRoundRectInfo, + gS32Info, + gScalarInfo, + gScaleInfo, + gSetInfo, + gShaderInfo, + gSkewInfo, + g3D_CameraInfo, + g3D_PatchInfo, + gUnknown6Info, + gSnapshotInfo, + gStringInfo, + gTextInfo, + gTextBoxInfo, + gTextOnPathInfo, + gTextToPathInfo, + gTranslateInfo, + gTypedArrayInfo, + gTypefaceInfo, +}; + +static const unsigned char gInfoCounts[] = { + 26,4,4,1,1,2,5,3,13,1,13,2,6,3,2,2,2,8,6, + 2,2,2,2,6,4,8,3,3,2,1,4,3,1,3,4,2,2,12,1, + 2,1,1,25,3,3,2,2,1,1,6,4,1,1,1,1,3,5,2,7, + 2,1,2,3,1,1,3,8,2,3,7,4,3,4,3,4,6,3,2,2, + 2,1 +}; + +static const unsigned char gTypeIDs[] = { + 1, // Math + 2, // Add + 3, // AddCircle + 4, // Unknown1 + 5, // AddOval + 6, // AddPath + 7, // AddRectangle + 8, // AddRoundRect + 10, // Unknown2 + 11, // AnimateField + 12, // Apply + 17, // Unknown3 + 19, // Bitmap + 22, // BitmapShader + 23, // Blur + 25, // Bounds + 29, // Clip + 31, // Color + 32, // CubicTo + 33, // Dash + 34, // Data + 35, // Discrete + 38, // DrawTo + 39, // Dump + 41, // Emboss + 42, // Event + 48, // FromPath + 51, // Unknown4 + 52, // G + 53, // HitClear + 54, // HitTest + 55, // Image + 56, // Include + 57, // Input + 59, // Line + 60, // LineTo + 61, // LinearGradient + 65, // Matrix + 68, // Move + 69, // MoveTo + 70, // Movie + 72, // Oval + 73, // Paint + 74, // Path + 77, // Unknown5 + 78, // Point + 79, // PolyToPoly + 80, // Polygon + 81, // Polyline + 82, // Post + 83, // QuadTo + 84, // RCubicTo + 85, // RLineTo + 86, // RMoveTo + 87, // RQuadTo + 88, // RadialGradient + 89, // Random + 90, // RectToRect + 91, // Rectangle + 92, // Remove + 93, // Replace + 94, // Rotate + 95, // RoundRect + 96, // S32 + 98, // Scalar + 99, // Scale + 101, // Set + 102, // Shader + 103, // Skew + 104, // 3D_Camera + 105, // 3D_Patch + 106, // Unknown6 + 107, // Snapshot + 108, // String + 110, // Text + 111, // TextBox + 114, // TextOnPath + 115, // TextToPath + 117, // Translate + 119, // TypedArray + 120, // Typeface + +}; + +static const int kTypeIDs = 81; + +static const char* const gInfoNames[] = { + gMathStrings, + gAddStrings, + gAddCircleStrings, + gUnknown1Strings, + gAddOvalStrings, + gAddPathStrings, + gAddRectangleStrings, + gAddRoundRectStrings, + gUnknown2Strings, + gAnimateFieldStrings, + gApplyStrings, + gUnknown3Strings, + gBitmapStrings, + gBitmapShaderStrings, + gBlurStrings, + gBoundsStrings, + gClipStrings, + gColorStrings, + gCubicToStrings, + gDashStrings, + gDataStrings, + gDiscreteStrings, + gDrawToStrings, + gDumpStrings, + gEmbossStrings, + gEventStrings, + gFromPathStrings, + gUnknown4Strings, + gGStrings, + gHitClearStrings, + gHitTestStrings, + gImageStrings, + gIncludeStrings, + gInputStrings, + gLineStrings, + gLineToStrings, + gLinearGradientStrings, + gMatrixStrings, + gMoveStrings, + gMoveToStrings, + gMovieStrings, + gOvalStrings, + gPaintStrings, + gPathStrings, + gUnknown5Strings, + gPointStrings, + gPolyToPolyStrings, + gPolygonStrings, + gPolylineStrings, + gPostStrings, + gQuadToStrings, + gRCubicToStrings, + gRLineToStrings, + gRMoveToStrings, + gRQuadToStrings, + gRadialGradientStrings, + gRandomStrings, + gRectToRectStrings, + gRectangleStrings, + gRemoveStrings, + gReplaceStrings, + gRotateStrings, + gRoundRectStrings, + gS32Strings, + gScalarStrings, + gScaleStrings, + gSetStrings, + gShaderStrings, + gSkewStrings, + g3D_CameraStrings, + g3D_PatchStrings, + gUnknown6Strings, + gSnapshotStrings, + gStringStrings, + gTextStrings, + gTextBoxStrings, + gTextOnPathStrings, + gTextToPathStrings, + gTranslateStrings, + gTypedArrayStrings, + gTypefaceStrings +}; + +#endif +#endif + + diff --git a/libs/graphics/animator/SkCondensedRelease.cpp b/libs/graphics/animator/SkCondensedRelease.cpp new file mode 100644 index 0000000000..70bb1b4e12 --- /dev/null +++ b/libs/graphics/animator/SkCondensedRelease.cpp @@ -0,0 +1,1357 @@ +#include "SkTypes.h" +#ifndef SK_BUILD_FOR_UNIX +#ifdef SK_RELEASE +// This file was automatically generated. +// To change it, edit the file with the matching debug info. +// Then execute SkDisplayType::BuildCondensedInfo() to regenerate this file. + +static const char gMathStrings[] = + "E\0" + "LN10\0" + "LN2\0" + "LOG10E\0" + "LOG2E\0" + "PI\0" + "SQRT1_2\0" + "SQRT2\0" + "abs\0" + "acos\0" + "asin\0" + "atan\0" + "atan2\0" + "ceil\0" + "cos\0" + "exp\0" + "floor\0" + "log\0" + "max\0" + "min\0" + "pow\0" + "random\0" + "round\0" + "sin\0" + "sqrt\0" + "tan" +; + +static const SkMemberInfo gMathInfo[] = { + {0, -1, 67, 98}, + {2, -2, 67, 98}, + {7, -3, 67, 98}, + {11, -4, 67, 98}, + {18, -5, 67, 98}, + {24, -6, 67, 98}, + {27, -7, 67, 98}, + {35, -8, 67, 98}, + {41, -1, 66, 98}, + {45, -2, 66, 98}, + {50, -3, 66, 98}, + {55, -4, 66, 98}, + {60, -5, 66, 98}, + {66, -6, 66, 98}, + {71, -7, 66, 98}, + {75, -8, 66, 98}, + {79, -9, 66, 98}, + {85, -10, 66, 98}, + {89, -11, 66, 98}, + {93, -12, 66, 98}, + {97, -13, 66, 98}, + {101, -14, 66, 98}, + {108, -15, 66, 98}, + {114, -16, 66, 98}, + {118, -17, 66, 98}, + {123, -18, 66, 98} +}; + +static const char gAddStrings[] = + "inPlace\0" + "offset\0" + "use\0" + "where" +; + +static const SkMemberInfo gAddInfo[] = { + {0, 4, 26, 1}, + {8, 8, 96, 1}, + {15, 12, 37, 1}, + {19, 16, 37, 1} +}; + +static const char gAddCircleStrings[] = + "\0" + "radius\0" + "x\0" + "y" +; + +static const SkMemberInfo gAddCircleInfo[] = { + {0, 3, 18, 1}, + {1, 12, 98, 1}, + {8, 16, 98, 1}, + {10, 20, 98, 1} +}; + +static const char gUnknown1Strings[] = + "direction" +; + +static const SkMemberInfo gUnknown1Info[] = { + {0, 8, 75, 1} +}; + +static const char gAddOvalStrings[] = + "" +; + +static const SkMemberInfo gAddOvalInfo[] = { + {0, 6, 18, 5} +}; + +static const char gAddPathStrings[] = + "matrix\0" + "path" +; + +static const SkMemberInfo gAddPathInfo[] = { + {0, 8, 65, 1}, + {7, 12, 74, 1} +}; + +static const char gAddRectangleStrings[] = + "\0" + "bottom\0" + "left\0" + "right\0" + "top" +; + +static const SkMemberInfo gAddRectangleInfo[] = { + {0, 3, 18, 1}, + {1, 24, 98, 1}, + {8, 12, 98, 1}, + {13, 20, 98, 1}, + {19, 16, 98, 1} +}; + +static const char gAddRoundRectStrings[] = + "\0" + "rx\0" + "ry" +; + +static const SkMemberInfo gAddRoundRectInfo[] = { + {0, 6, 18, 5}, + {1, 28, 98, 1}, + {4, 32, 98, 1} +}; + +static const char gUnknown2Strings[] = + "begin\0" + "blend\0" + "dur\0" + "dynamic\0" + "field\0" + "formula\0" + "from\0" + "mirror\0" + "repeat\0" + "reset\0" + "target\0" + "to\0" + "values" +; + +static const SkMemberInfo gUnknown2Info[] = { + {0, 4, 71, 1}, + {6, 8, 119, 98}, + {12, 16, 71, 1}, + {16, -1, 67, 26}, + {24, 20, 108, 1}, + {30, 24, 40, 1}, + {38, 28, 40, 1}, + {43, -2, 67, 26}, + {50, 32, 98, 1}, + {57, -3, 67, 26}, + {63, 36, 40, 1}, + {70, 40, 40, 1}, + {73, -4, 67, 40} +}; + +static const char gAnimateFieldStrings[] = + "" +; + +static const SkMemberInfo gAnimateFieldInfo[] = { + {0, 8, 18, 13} +}; + +static const char gApplyStrings[] = + "animator\0" + "begin\0" + "dontDraw\0" + "dynamicScope\0" + "interval\0" + "mode\0" + "pickup\0" + "restore\0" + "scope\0" + "step\0" + "steps\0" + "time\0" + "transition" +; + +static const SkMemberInfo gApplyInfo[] = { + {0, -1, 67, 10}, + {9, 4, 71, 1}, + {15, 8, 26, 1}, + {24, 12, 108, 1}, + {37, 16, 71, 1}, + {46, 20, 13, 1}, + {51, 24, 26, 1}, + {58, 28, 26, 1}, + {66, 32, 37, 1}, + {72, -2, 67, 96}, + {77, 36, 96, 1}, + {83, -3, 67, 71}, + {88, 40, 14, 1} +}; + +static const char gUnknown3Strings[] = + "x\0" + "y" +; + +static const SkMemberInfo gUnknown3Info[] = { + {0, 36, 98, 1}, + {2, 40, 98, 1} +}; + +static const char gBitmapStrings[] = + "\0" + "erase\0" + "format\0" + "height\0" + "rowBytes\0" + "width" +; + +static const SkMemberInfo gDrawBitmapInfo[] = { + {0, 11, 18, 2}, + {1, -1, 67, 15}, + {7, 44, 21, 1}, + {14, 48, 96, 1}, + {21, 52, 96, 1}, + {30, 56, 96, 1} +}; + +static const char gBitmapShaderStrings[] = + "\0" + "filterType\0" + "image" +; + +static const SkMemberInfo gDrawBitmapShaderInfo[] = { + {0, 66, 18, 2}, + {1, 16, 47, 1}, + {12, 20, 17, 1} +}; + +static const char gBlurStrings[] = + "blurStyle\0" + "radius" +; + +static const SkMemberInfo gDrawBlurInfo[] = { + {0, 12, 63, 1}, + {10, 8, 98, 1} +}; + +static const char gBoundsStrings[] = + "\0" + "inval" +; + +static const SkMemberInfo gDisplayBoundsInfo[] = { + {0, 57, 18, 7}, + {1, 32, 26, 1} +}; + +static const char gClipStrings[] = + "path\0" + "rectangle" +; + +static const SkMemberInfo gDrawClipInfo[] = { + {0, 8, 74, 1}, + {5, 4, 91, 1} +}; + +static const char gColorStrings[] = + "alpha\0" + "blue\0" + "color\0" + "green\0" + "hue\0" + "red\0" + "saturation\0" + "value" +; + +static const SkMemberInfo gDrawColorInfo[] = { + {0, -1, 67, 98}, + {6, -2, 67, 98}, + {11, 8, 15, 1}, + {17, -3, 67, 98}, + {23, -4, 67, 98}, + {27, -5, 67, 98}, + {31, -6, 67, 98}, + {42, -7, 67, 98} +}; + +static const char gCubicToStrings[] = + "x1\0" + "x2\0" + "x3\0" + "y1\0" + "y2\0" + "y3" +; + +static const SkMemberInfo gCubicToInfo[] = { + {0, 8, 98, 1}, + {3, 16, 98, 1}, + {6, 24, 98, 1}, + {9, 12, 98, 1}, + {12, 20, 98, 1}, + {15, 28, 98, 1} +}; + +static const char gDashStrings[] = + "intervals\0" + "phase" +; + +static const SkMemberInfo gDashInfo[] = { + {0, 8, 119, 98}, + {10, 16, 98, 1} +}; + +static const char gDataStrings[] = + "\0" + "name" +; + +static const SkMemberInfo gDataInfo[] = { + {0, 32, 18, 3}, + {1, 16, 108, 1} +}; + +static const char gDiscreteStrings[] = + "deviation\0" + "segLength" +; + +static const SkMemberInfo gDiscreteInfo[] = { + {0, 8, 98, 1}, + {10, 12, 98, 1} +}; + +static const char gDrawToStrings[] = + "drawOnce\0" + "use" +; + +static const SkMemberInfo gDrawToInfo[] = { + {0, 36, 26, 1}, + {9, 40, 19, 1} +}; + +static const char gEmbossStrings[] = + "ambient\0" + "direction\0" + "radius\0" + "specular" +; + +static const SkMemberInfo gDrawEmbossInfo[] = { + {0, -1, 67, 98}, + {8, 8, 119, 98}, + {18, 16, 98, 1}, + {25, -2, 67, 98} +}; + +static const char gEventStrings[] = + "code\0" + "disable\0" + "key\0" + "keys\0" + "kind\0" + "target\0" + "x\0" + "y" +; + +static const SkMemberInfo gDisplayEventInfo[] = { + {0, 4, 43, 1}, + {5, 8, 26, 1}, + {13, -1, 67, 108}, + {17, -2, 67, 108}, + {22, 12, 44, 1}, + {27, 16, 108, 1}, + {34, 20, 98, 1}, + {36, 24, 98, 1} +}; + +static const char gFromPathStrings[] = + "mode\0" + "offset\0" + "path" +; + +static const SkMemberInfo gFromPathInfo[] = { + {0, 8, 49, 1}, + {5, 12, 98, 1}, + {12, 16, 74, 1} +}; + +static const char gUnknown4Strings[] = + "\0" + "offsets\0" + "unitMapper" +; + +static const SkMemberInfo gUnknown4Info[] = { + {0, 66, 18, 2}, + {1, 16, 119, 98}, + {9, 24, 108, 1} +}; + +static const char gGStrings[] = + "condition\0" + "enableCondition" +; + +static const SkMemberInfo gGInfo[] = { + {0, 4, 40, 1}, + {10, 8, 40, 1} +}; + +static const char gHitClearStrings[] = + "targets" +; + +static const SkMemberInfo gHitClearInfo[] = { + {0, 4, 119, 36} +}; + +static const char gHitTestStrings[] = + "bullets\0" + "hits\0" + "targets\0" + "value" +; + +static const SkMemberInfo gHitTestInfo[] = { + {0, 4, 119, 36}, + {8, 12, 119, 96}, + {13, 20, 119, 36}, + {21, 28, 26, 1} +}; + +static const char gImageStrings[] = + "\0" + "base64\0" + "src" +; + +static const SkMemberInfo gImageInfo[] = { + {0, 11, 18, 2}, + {1, 44, 16, 2}, + {8, 52, 108, 1} +}; + +static const char gIncludeStrings[] = + "src" +; + +static const SkMemberInfo gIncludeInfo[] = { + {0, 4, 108, 1} +}; + +static const char gInputStrings[] = + "s32\0" + "scalar\0" + "string" +; + +static const SkMemberInfo gInputInfo[] = { + {0, 4, 96, 1}, + {4, 8, 98, 1}, + {11, 12, 108, 1} +}; + +static const char gLineStrings[] = + "x1\0" + "x2\0" + "y1\0" + "y2" +; + +static const SkMemberInfo gLineInfo[] = { + {0, 12, 98, 1}, + {3, 16, 98, 1}, + {6, 20, 98, 1}, + {9, 24, 98, 1} +}; + +static const char gLineToStrings[] = + "x\0" + "y" +; + +static const SkMemberInfo gLineToInfo[] = { + {0, 8, 98, 1}, + {2, 12, 98, 1} +}; + +static const char gLinearGradientStrings[] = + "\0" + "points" +; + +static const SkMemberInfo gLinearGradientInfo[] = { + {0, 26, 18, 3}, + {1, 48, 77, 4} +}; + +static const char gMatrixStrings[] = + "matrix\0" + "perspectX\0" + "perspectY\0" + "rotate\0" + "scale\0" + "scaleX\0" + "scaleY\0" + "skewX\0" + "skewY\0" + "translate\0" + "translateX\0" + "translateY" +; + +static const SkMemberInfo gDrawMatrixInfo[] = { + {0, 4, 119, 98}, + {7, -1, 67, 98}, + {17, -2, 67, 98}, + {27, -3, 67, 98}, + {34, -4, 67, 98}, + {40, -5, 67, 98}, + {47, -6, 67, 98}, + {54, -7, 67, 98}, + {60, -8, 67, 98}, + {66, -9, 67, 77}, + {76, -10, 67, 98}, + {87, -11, 67, 98} +}; + +static const char gMoveStrings[] = + "" +; + +static const SkMemberInfo gMoveInfo[] = { + {0, 1, 18, 4} +}; + +static const char gMoveToStrings[] = + "x\0" + "y" +; + +static const SkMemberInfo gMoveToInfo[] = { + {0, 8, 98, 1}, + {2, 12, 98, 1} +}; + +static const char gMovieStrings[] = + "src" +; + +static const SkMemberInfo gMovieInfo[] = { + {0, 4, 108, 1} +}; + +static const char gOvalStrings[] = + "" +; + +static const SkMemberInfo gOvalInfo[] = { + {0, 57, 18, 7} +}; + +static const char gPaintStrings[] = + "antiAlias\0" + "ascent\0" + "color\0" + "descent\0" + "filterType\0" + "linearText\0" + "maskFilter\0" + "measureText\0" + "pathEffect\0" + "shader\0" + "strikeThru\0" + "stroke\0" + "strokeCap\0" + "strokeJoin\0" + "strokeMiter\0" + "strokeWidth\0" + "style\0" + "textAlign\0" + "textScaleX\0" + "textSize\0" + "textSkewX\0" + "textTracking\0" + "typeface\0" + "underline\0" + "xfermode" +; + +static const SkMemberInfo gDrawPaintInfo[] = { + {0, 4, 26, 1}, + {10, -1, 67, 98}, + {17, 8, 31, 1}, + {23, -2, 67, 98}, + {31, 12, 47, 1}, + {42, 16, 26, 1}, + {53, 20, 62, 1}, + {64, -1, 66, 98}, + {76, 24, 76, 1}, + {87, 28, 102, 1}, + {94, 32, 26, 1}, + {105, 36, 26, 1}, + {112, 40, 27, 1}, + {122, 44, 58, 1}, + {133, 48, 98, 1}, + {145, 52, 98, 1}, + {157, 56, 109, 1}, + {163, 60, 9, 1}, + {173, 64, 98, 1}, + {184, 68, 98, 1}, + {193, 72, 98, 1}, + {203, 76, 98, 1}, + {216, 80, 120, 1}, + {225, 84, 26, 1}, + {235, 88, 121, 1} +}; + +static const char gPathStrings[] = + "d\0" + "fillType\0" + "length" +; + +static const SkMemberInfo gDrawPathInfo[] = { + {0, 32, 108, 1}, + {2, -1, 67, 46}, + {11, -2, 67, 98} +}; + +static const char gUnknown5Strings[] = + "x\0" + "y\0" + "z" +; + +static const SkMemberInfo gUnknown5Info[] = { + {0, 0, 98, 1}, + {2, 4, 98, 1}, + {4, 8, 98, 1} +}; + +static const char gPointStrings[] = + "x\0" + "y" +; + +static const SkMemberInfo gDrawPointInfo[] = { + {0, 4, 98, 1}, + {2, 8, 98, 1} +}; + +static const char gPolyToPolyStrings[] = + "destination\0" + "source" +; + +static const SkMemberInfo gPolyToPolyInfo[] = { + {0, 12, 80, 1}, + {12, 8, 80, 1} +}; + +static const char gPolygonStrings[] = + "" +; + +static const SkMemberInfo gPolygonInfo[] = { + {0, 47, 18, 1} +}; + +static const char gPolylineStrings[] = + "points" +; + +static const SkMemberInfo gPolylineInfo[] = { + {0, 56, 119, 98} +}; + +static const char gPostStrings[] = + "delay\0" + "initialized\0" + "mode\0" + "sink\0" + "target\0" + "type" +; + +static const SkMemberInfo gPostInfo[] = { + {0, 4, 71, 1}, + {6, 8, 26, 1}, + {18, 12, 45, 1}, + {23, -1, 67, 108}, + {28, -2, 67, 108}, + {35, -3, 67, 108} +}; + +static const char gQuadToStrings[] = + "x1\0" + "x2\0" + "y1\0" + "y2" +; + +static const SkMemberInfo gQuadToInfo[] = { + {0, 8, 98, 1}, + {3, 16, 98, 1}, + {6, 12, 98, 1}, + {9, 20, 98, 1} +}; + +static const char gRCubicToStrings[] = + "" +; + +static const SkMemberInfo gRCubicToInfo[] = { + {0, 18, 18, 6} +}; + +static const char gRLineToStrings[] = + "" +; + +static const SkMemberInfo gRLineToInfo[] = { + {0, 34, 18, 2} +}; + +static const char gRMoveToStrings[] = + "" +; + +static const SkMemberInfo gRMoveToInfo[] = { + {0, 38, 18, 2} +}; + +static const char gRQuadToStrings[] = + "" +; + +static const SkMemberInfo gRQuadToInfo[] = { + {0, 49, 18, 4} +}; + +static const char gRadialGradientStrings[] = + "\0" + "center\0" + "radius" +; + +static const SkMemberInfo gRadialGradientInfo[] = { + {0, 26, 18, 3}, + {1, 48, 77, 2}, + {8, 56, 98, 1} +}; + +static const char gRandomStrings[] = + "blend\0" + "max\0" + "min\0" + "random\0" + "seed" +; + +static const SkMemberInfo gDisplayRandomInfo[] = { + {0, 4, 98, 1}, + {6, 12, 98, 1}, + {10, 8, 98, 1}, + {14, 1, 67, 98}, + {21, -2, 67, 96} +}; + +static const char gRectToRectStrings[] = + "destination\0" + "source" +; + +static const SkMemberInfo gRectToRectInfo[] = { + {0, 12, 91, 1}, + {12, 8, 91, 1} +}; + +static const char gRectangleStrings[] = + "bottom\0" + "height\0" + "left\0" + "needsRedraw\0" + "right\0" + "top\0" + "width" +; + +static const SkMemberInfo gRectangleInfo[] = { + {0, 24, 98, 1}, + {7, -1, 67, 98}, + {14, 12, 98, 1}, + {19, -2, 67, 26}, + {31, 20, 98, 1}, + {37, 16, 98, 1}, + {41, -3, 67, 98} +}; + +static const char gRemoveStrings[] = + "offset\0" + "where" +; + +static const SkMemberInfo gRemoveInfo[] = { + {0, 8, 96, 1}, + {7, 16, 37, 1} +}; + +static const char gReplaceStrings[] = + "" +; + +static const SkMemberInfo gReplaceInfo[] = { + {0, 1, 18, 4} +}; + +static const char gRotateStrings[] = + "center\0" + "degrees" +; + +static const SkMemberInfo gRotateInfo[] = { + {0, 12, 77, 2}, + {7, 8, 98, 1} +}; + +static const char gRoundRectStrings[] = + "\0" + "rx\0" + "ry" +; + +static const SkMemberInfo gRoundRectInfo[] = { + {0, 57, 18, 7}, + {1, 32, 98, 1}, + {4, 36, 98, 1} +}; + +static const char gS32Strings[] = + "value" +; + +static const SkMemberInfo gS32Info[] = { + {0, 4, 96, 1} +}; + +static const char gScalarStrings[] = + "value" +; + +static const SkMemberInfo gScalarInfo[] = { + {0, 4, 98, 1} +}; + +static const char gScaleStrings[] = + "center\0" + "x\0" + "y" +; + +static const SkMemberInfo gScaleInfo[] = { + {0, 16, 77, 2}, + {7, 8, 98, 1}, + {9, 12, 98, 1} +}; + +static const char gSetStrings[] = + "begin\0" + "dur\0" + "dynamic\0" + "field\0" + "formula\0" + "reset\0" + "target\0" + "to" +; + +static const SkMemberInfo gSetInfo[] = { + {0, 4, 71, 1}, + {6, 16, 71, 1}, + {10, -1, 67, 26}, + {18, 20, 108, 1}, + {24, 24, 40, 1}, + {32, -3, 67, 26}, + {38, 36, 40, 1}, + {45, 40, 40, 1} +}; + +static const char gShaderStrings[] = + "matrix\0" + "tileMode" +; + +static const SkMemberInfo gShaderInfo[] = { + {0, 8, 65, 1}, + {7, 12, 116, 1} +}; + +static const char gSkewStrings[] = + "center\0" + "x\0" + "y" +; + +static const SkMemberInfo gSkewInfo[] = { + {0, 16, 77, 2}, + {7, 8, 98, 1}, + {9, 12, 98, 1} +}; + +static const char g3D_CameraStrings[] = + "axis\0" + "hackHeight\0" + "hackWidth\0" + "location\0" + "observer\0" + "patch\0" + "zenith" +; + +static const SkMemberInfo g3D_CameraInfo[] = { + {0, 24, 106, 3}, + {5, 8, 98, 1}, + {16, 4, 98, 1}, + {26, 12, 106, 3}, + {35, 48, 106, 3}, + {44, 96, 105, 1}, + {50, 36, 106, 3} +}; + +static const char g3D_PatchStrings[] = + "origin\0" + "rotateDegrees\0" + "u\0" + "v" +; + +static const SkMemberInfo g3D_PatchInfo[] = { + {0, 28, 106, 3}, + {7, -1, 66, 98}, + {21, 4, 106, 3}, + {23, 16, 106, 3} +}; + +static const char gUnknown6Strings[] = + "x\0" + "y\0" + "z" +; + +static const SkMemberInfo gUnknown6Info[] = { + {0, 0, 98, 1}, + {2, 4, 98, 1}, + {4, 8, 98, 1} +}; + +static const char gSnapshotStrings[] = + "filename\0" + "quality\0" + "sequence\0" + "type" +; + +static const SkMemberInfo gSnapshotInfo[] = { + {0, 4, 108, 1}, + {9, 8, 98, 1}, + {17, 12, 26, 1}, + {26, 16, 20, 1} +}; + +static const char gStringStrings[] = + "length\0" + "slice\0" + "value" +; + +static const SkMemberInfo gStringInfo[] = { + {0, -1, 67, 96}, + {7, -1, 66, 108}, + {13, 4, 108, 1} +}; + +static const char gTextStrings[] = + "length\0" + "text\0" + "x\0" + "y" +; + +static const SkMemberInfo gTextInfo[] = { + {0, -1, 67, 96}, + {7, 12, 108, 1}, + {12, 16, 98, 1}, + {14, 20, 98, 1} +}; + +static const char gTextBoxStrings[] = + "\0" + "mode\0" + "spacingAdd\0" + "spacingAlign\0" + "spacingMul\0" + "text" +; + +static const SkMemberInfo gTextBoxInfo[] = { + {0, 57, 18, 7}, + {1, 44, 113, 1}, + {6, 40, 98, 1}, + {17, 48, 112, 1}, + {30, 36, 98, 1}, + {41, 32, 108, 1} +}; + +static const char gTextOnPathStrings[] = + "offset\0" + "path\0" + "text" +; + +static const SkMemberInfo gTextOnPathInfo[] = { + {0, 12, 98, 1}, + {7, 16, 74, 1}, + {12, 20, 110, 1} +}; + +static const char gTextToPathStrings[] = + "path\0" + "text" +; + +static const SkMemberInfo gTextToPathInfo[] = { + {0, 4, 74, 1}, + {5, 8, 110, 1} +}; + +static const char gTranslateStrings[] = + "x\0" + "y" +; + +static const SkMemberInfo gTranslateInfo[] = { + {0, 8, 98, 1}, + {2, 12, 98, 1} +}; + +static const char gTypedArrayStrings[] = + "length\0" + "values" +; + +static const SkMemberInfo gTypedArrayInfo[] = { + {0, -1, 67, 96}, + {7, 4, 119, 0} +}; + +static const char gTypefaceStrings[] = + "fontName" +; + +static const SkMemberInfo gTypefaceInfo[] = { + {0, 8, 108, 1} +}; + +static const SkMemberInfo* const gInfoTables[] = { + gMathInfo, + gAddInfo, + gAddCircleInfo, + gUnknown1Info, + gAddOvalInfo, + gAddPathInfo, + gAddRectangleInfo, + gAddRoundRectInfo, + gUnknown2Info, + gAnimateFieldInfo, + gApplyInfo, + gUnknown3Info, + gDrawBitmapInfo, + gDrawBitmapShaderInfo, + gDrawBlurInfo, + gDisplayBoundsInfo, + gDrawClipInfo, + gDrawColorInfo, + gCubicToInfo, + gDashInfo, + gDataInfo, + gDiscreteInfo, + gDrawToInfo, + gDrawEmbossInfo, + gDisplayEventInfo, + gFromPathInfo, + gUnknown4Info, + gGInfo, + gHitClearInfo, + gHitTestInfo, + gImageInfo, + gIncludeInfo, + gInputInfo, + gLineInfo, + gLineToInfo, + gLinearGradientInfo, + gDrawMatrixInfo, + gMoveInfo, + gMoveToInfo, + gMovieInfo, + gOvalInfo, + gDrawPaintInfo, + gDrawPathInfo, + gUnknown5Info, + gDrawPointInfo, + gPolyToPolyInfo, + gPolygonInfo, + gPolylineInfo, + gPostInfo, + gQuadToInfo, + gRCubicToInfo, + gRLineToInfo, + gRMoveToInfo, + gRQuadToInfo, + gRadialGradientInfo, + gDisplayRandomInfo, + gRectToRectInfo, + gRectangleInfo, + gRemoveInfo, + gReplaceInfo, + gRotateInfo, + gRoundRectInfo, + gS32Info, + gScalarInfo, + gScaleInfo, + gSetInfo, + gShaderInfo, + gSkewInfo, + g3D_CameraInfo, + g3D_PatchInfo, + gUnknown6Info, + gSnapshotInfo, + gStringInfo, + gTextInfo, + gTextBoxInfo, + gTextOnPathInfo, + gTextToPathInfo, + gTranslateInfo, + gTypedArrayInfo, + gTypefaceInfo, +}; + +static const unsigned char gInfoCounts[] = { + 26,4,4,1,1,2,5,3,13,1,13,2,6,3,2,2,2,8,6, + 2,2,2,2,4,8,3,3,2,1,4,3,1,3,4,2,2,12,1,2, + 1,1,25,3,3,2,2,1,1,6,4,1,1,1,1,3,5,2,7,2, + 1,2,3,1,1,3,8,2,3,7,4,3,4,3,4,6,3,2,2,2, + 1 +}; + +static const unsigned char gTypeIDs[] = { + 1, // Math + 2, // Add + 3, // AddCircle + 4, // Unknown1 + 5, // AddOval + 6, // AddPath + 7, // AddRectangle + 8, // AddRoundRect + 10, // Unknown2 + 11, // AnimateField + 12, // Apply + 17, // Unknown3 + 19, // Bitmap + 22, // BitmapShader + 23, // Blur + 25, // Bounds + 29, // Clip + 31, // Color + 32, // CubicTo + 33, // Dash + 34, // Data + 35, // Discrete + 38, // DrawTo + 41, // Emboss + 42, // Event + 48, // FromPath + 51, // Unknown4 + 52, // G + 53, // HitClear + 54, // HitTest + 55, // Image + 56, // Include + 57, // Input + 59, // Line + 60, // LineTo + 61, // LinearGradient + 65, // Matrix + 68, // Move + 69, // MoveTo + 70, // Movie + 72, // Oval + 73, // Paint + 74, // Path + 77, // Unknown5 + 78, // Point + 79, // PolyToPoly + 80, // Polygon + 81, // Polyline + 82, // Post + 83, // QuadTo + 84, // RCubicTo + 85, // RLineTo + 86, // RMoveTo + 87, // RQuadTo + 88, // RadialGradient + 89, // Random + 90, // RectToRect + 91, // Rectangle + 92, // Remove + 93, // Replace + 94, // Rotate + 95, // RoundRect + 96, // S32 + 98, // Scalar + 99, // Scale + 101, // Set + 102, // Shader + 103, // Skew + 104, // 3D_Camera + 105, // 3D_Patch + 106, // Unknown6 + 107, // Snapshot + 108, // String + 110, // Text + 111, // TextBox + 114, // TextOnPath + 115, // TextToPath + 117, // Translate + 119, // TypedArray + 120, // Typeface + +}; + +static const int kTypeIDs = 80; + +static const char* const gInfoNames[] = { + gMathStrings, + gAddStrings, + gAddCircleStrings, + gUnknown1Strings, + gAddOvalStrings, + gAddPathStrings, + gAddRectangleStrings, + gAddRoundRectStrings, + gUnknown2Strings, + gAnimateFieldStrings, + gApplyStrings, + gUnknown3Strings, + gBitmapStrings, + gBitmapShaderStrings, + gBlurStrings, + gBoundsStrings, + gClipStrings, + gColorStrings, + gCubicToStrings, + gDashStrings, + gDataStrings, + gDiscreteStrings, + gDrawToStrings, + gEmbossStrings, + gEventStrings, + gFromPathStrings, + gUnknown4Strings, + gGStrings, + gHitClearStrings, + gHitTestStrings, + gImageStrings, + gIncludeStrings, + gInputStrings, + gLineStrings, + gLineToStrings, + gLinearGradientStrings, + gMatrixStrings, + gMoveStrings, + gMoveToStrings, + gMovieStrings, + gOvalStrings, + gPaintStrings, + gPathStrings, + gUnknown5Strings, + gPointStrings, + gPolyToPolyStrings, + gPolygonStrings, + gPolylineStrings, + gPostStrings, + gQuadToStrings, + gRCubicToStrings, + gRLineToStrings, + gRMoveToStrings, + gRQuadToStrings, + gRadialGradientStrings, + gRandomStrings, + gRectToRectStrings, + gRectangleStrings, + gRemoveStrings, + gReplaceStrings, + gRotateStrings, + gRoundRectStrings, + gS32Strings, + gScalarStrings, + gScaleStrings, + gSetStrings, + gShaderStrings, + gSkewStrings, + g3D_CameraStrings, + g3D_PatchStrings, + gUnknown6Strings, + gSnapshotStrings, + gStringStrings, + gTextStrings, + gTextBoxStrings, + gTextOnPathStrings, + gTextToPathStrings, + gTranslateStrings, + gTypedArrayStrings, + gTypefaceStrings +}; +#endif +#endif + diff --git a/libs/graphics/animator/SkDisplayAdd.cpp b/libs/graphics/animator/SkDisplayAdd.cpp new file mode 100644 index 0000000000..0264a5f9d6 --- /dev/null +++ b/libs/graphics/animator/SkDisplayAdd.cpp @@ -0,0 +1,237 @@ +#include "SkDisplayAdd.h" +#include "SkAnimateMaker.h" +#include "SkDisplayApply.h" +#include "SkDisplayList.h" +#include "SkDrawable.h" +#include "SkDrawGroup.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkAdd::fInfo[] = { + SK_MEMBER(mode, AddMode), + SK_MEMBER(offset, Int), + SK_MEMBER(use, Drawable), + SK_MEMBER(where, Drawable) +}; + +#endif + +// start here; +// add onEndElement to turn where string into f_Where +// probably need new SkAnimateMaker::resolve flavor that takes +// where="id", where="event-target" or not-specified +// offset="#" (implements before, after, and index if no 'where') + +DEFINE_GET_MEMBER(SkAdd); + +SkAdd::SkAdd() : mode(kMode_indirect), + offset(SK_MaxS32), use(nil), where(nil) { +} + +SkDisplayable* SkAdd::deepCopy(SkAnimateMaker* maker) { + SkDrawable* saveUse = use; + SkDrawable* saveWhere = where; + use = nil; + where = nil; + SkAdd* copy = (SkAdd*) INHERITED::deepCopy(maker); + copy->use = use = saveUse; + copy->where = where = saveWhere; + return copy; +} + +bool SkAdd::draw(SkAnimateMaker& maker) { + SkASSERT(use); + SkASSERT(use->isDrawable()); + if (mode == kMode_indirect) + use->draw(maker); + return false; +} + +#ifdef SK_DUMP_ENABLED +void SkAdd::dump(SkAnimateMaker* maker) { + dumpBase(maker); + dumpAttrs(maker); + if (where) + SkDebugf("where=\"%s\" ", where->id); + if (mode == kMode_immediate) + SkDebugf("mode=\"immediate\" "); + SkDebugf(">\n"); + SkDisplayList::fIndent += 4; + int save = SkDisplayList::fDumpIndex; + if (use) //just in case + use->dump(maker); + SkDisplayList::fIndent -= 4; + SkDisplayList::fDumpIndex = save; + dumpEnd(maker); +} +#endif + +bool SkAdd::enable(SkAnimateMaker& maker ) { + SkDisplayTypes type = getType(); + SkDisplayList& displayList = maker.fDisplayList; + SkTDDrawableArray* parentList = displayList.getDrawList(); + if (type == SkType_Add) { + if (use == nil) // not set in apply yet + return true; + } + bool skipAddToParent = true; + SkASSERT(type != SkType_Replace || where); + SkTDDrawableArray* grandList SK_INIT_TO_AVOID_WARNING; + SkGroup* parentGroup = nil; + SkGroup* thisGroup = nil; + int index = where ? displayList.findGroup(where, &parentList, &parentGroup, + &thisGroup, &grandList) : 0; + if (index < 0) + return true; + int max = parentList->count(); + if (where == nil && type == SkType_Move) + index = max; + if (offset != SK_MaxS32) { + index += offset; + if (index > max) { + maker.setErrorCode(SkDisplayXMLParserError::kIndexOutOfRange); + return true; // caller should not add + } + } + if (offset < 0 && where == nil) + index += max + 1; + switch (type) { + case SkType_Add: + if (offset == SK_MaxS32 && where == nil) { + if (use->isDrawable()) { + skipAddToParent = mode == kMode_immediate; + if (skipAddToParent) { + if (where == nil) { + SkTDDrawableArray* useParentList; + index = displayList.findGroup(this, &useParentList, &parentGroup, + &thisGroup, &grandList); + if (index >= 0) { + parentGroup->markCopySize(index); + parentGroup->markCopySet(index); + useParentList->begin()[index] = use; + break; + } + } + *parentList->append() = use; + } + } + break; + } else { + if (thisGroup) + thisGroup->markCopySize(index); + *parentList->insert(index) = use; + if (thisGroup) + thisGroup->markCopySet(index); + if (use->isApply()) + ((SkApply*) use)->setEmbedded(); + } + break; + case SkType_Move: { + int priorLocation = parentList->find(use); + if (priorLocation < 0) + break; + *parentList->insert(index) = use; + if (index < priorLocation) + priorLocation++; + parentList->remove(priorLocation); + } break; + case SkType_Remove: { + SkDisplayable* old = (*parentList)[index]; + if (((SkRemove*)(this))->fDelete) { + delete old; + goto noHelperNeeded; + } + for (int inner = 0; inner < maker.fChildren.count(); inner++) { + SkDisplayable* child = maker.fChildren[inner]; + if (child == old || child->contains(old)) + goto noHelperNeeded; + } + if (maker.fHelpers.find(old) < 0) + maker.helperAdd(old); +noHelperNeeded: + parentList->remove(index); + } break; + case SkType_Replace: + if (thisGroup) { + thisGroup->markCopySize(index); + if (thisGroup->markedForDelete(index)) { + SkDisplayable* old = (*parentList)[index]; + if (maker.fHelpers.find(old) < 0) + maker.helperAdd(old); + } + } + (*parentList)[index] = use; + if (thisGroup) + thisGroup->markCopySet(index); + break; + default: + SkASSERT(0); + } + if (type == SkType_Remove) + return true; + if (use->hasEnable()) + use->enable(maker); + return skipAddToParent; // append if indirect: *parentList->append() = this; +} + +bool SkAdd::hasEnable() const { + return true; +} + +void SkAdd::initialize() { + if (use) + use->initialize(); +} + +bool SkAdd::isDrawable() const { + return getType() == SkType_Add && mode == kMode_indirect && offset == SK_MaxS32 && + where == nil && use != nil && use->isDrawable(); +} + +//SkDisplayable* SkAdd::resolveTarget(SkAnimateMaker& maker) { +// return use; +//} + + +bool SkClear::enable(SkAnimateMaker& maker ) { + SkDisplayList& displayList = maker.fDisplayList; + displayList.clear(); + return true; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkMove::fInfo[] = { + SK_MEMBER_INHERITED +}; + +#endif + +DEFINE_GET_MEMBER(SkMove); + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkRemove::fInfo[] = { + SK_MEMBER_ALIAS(delete, fDelete, Boolean), // !!! experimental + SK_MEMBER(offset, Int), + SK_MEMBER(where, Drawable) +}; + +#endif + +DEFINE_GET_MEMBER(SkRemove); + +SkRemove::SkRemove() : fDelete(false) { +} + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkReplace::fInfo[] = { + SK_MEMBER_INHERITED +}; + +#endif + +DEFINE_GET_MEMBER(SkReplace); + diff --git a/libs/graphics/animator/SkDisplayAdd.h b/libs/graphics/animator/SkDisplayAdd.h new file mode 100644 index 0000000000..ed727307f7 --- /dev/null +++ b/libs/graphics/animator/SkDisplayAdd.h @@ -0,0 +1,64 @@ +#ifndef SkDisplayAdd_DEFINED +#define SkDisplayAdd_DEFINED + +#include "SkDrawable.h" +#include "SkMemberInfo.h" + +class SkAdd : public SkDrawable { + DECLARE_MEMBER_INFO(Add); + SkAdd(); + + enum Mode { + kMode_indirect, + kMode_immediate + }; + + virtual SkDisplayable* deepCopy(SkAnimateMaker* ); + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual bool enable(SkAnimateMaker& ); + virtual bool hasEnable() const; + virtual void initialize(); + virtual bool isDrawable() const; +protected: +// struct _A { + Mode mode; + S32 offset; + SkDrawable* use; + SkDrawable* where; // if nil, offset becomes index +// } A; +private: + typedef SkDrawable INHERITED; +}; + +class SkClear : public SkDisplayable { + virtual bool enable(SkAnimateMaker& ); +}; + +class SkMove : public SkAdd { + DECLARE_MEMBER_INFO(Move); +private: + typedef SkAdd INHERITED; +}; + +class SkRemove : public SkAdd { + DECLARE_MEMBER_INFO(Remove); + SkRemove(); +protected: + SkBool fDelete; +private: + friend class SkAdd; + typedef SkAdd INHERITED; +}; + +class SkReplace : public SkAdd { + DECLARE_MEMBER_INFO(Replace); +private: + typedef SkAdd INHERITED; +}; + +#endif // SkDisplayAdd_DEFINED + + diff --git a/libs/graphics/animator/SkDisplayApply.cpp b/libs/graphics/animator/SkDisplayApply.cpp new file mode 100644 index 0000000000..af886312f9 --- /dev/null +++ b/libs/graphics/animator/SkDisplayApply.cpp @@ -0,0 +1,797 @@ +#include "SkDisplayApply.h" +#include "SkAnimateActive.h" +#include "SkAnimateMaker.h" +#include "SkAnimateSet.h" +#include "SkAnimatorScript.h" +#include "SkDisplayType.h" +#include "SkDrawGroup.h" +#include "SkParse.h" +#include "SkScript.h" +#include "SkSystemEventTypes.h" +#ifdef SK_DEBUG +#include "SkTime.h" +#endif +#include <ctype.h> + +enum SkApply_Properties { + SK_PROPERTY(animator), + SK_PROPERTY(step), + SK_PROPERTY(steps), + SK_PROPERTY(time) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +// if no attibutes, enclosed displayable is both scope & target +// only if both scope & target are specified, or if target and enclosed displayable, are scope and target different +const SkMemberInfo SkApply::fInfo[] = { + SK_MEMBER_PROPERTY(animator, Animate), + SK_MEMBER(begin, MSec), + SK_MEMBER(dontDraw, Boolean), + SK_MEMBER(dynamicScope, String), + SK_MEMBER(interval, MSec), // recommended redraw interval + SK_MEMBER(mode, ApplyMode), +#if 0 + SK_MEMBER(pickup, Boolean), +#endif + SK_MEMBER(restore, Boolean), + SK_MEMBER(scope, Drawable), // thing that scopes animation (unnamed enclosed displayable goes here) + SK_MEMBER_PROPERTY(step, Int), + SK_MEMBER_PROPERTY(steps, Int), + SK_MEMBER_PROPERTY(time, MSec), + SK_MEMBER(transition, ApplyTransition) +}; + +#endif + +DEFINE_GET_MEMBER(SkApply); + +SkApply::SkApply() : begin(0), dontDraw(false), interval((SkMSec) -1), mode((Mode) -1), /*pickup(false), */ + restore(false), scope(nil), steps(-1), transition((Transition) -1), fActive(nil), /*fCurrentScope(nil),*/ + fLastTime(0), fAppended(false), fContainsScope(false), fDeleteScope(false), fEmbedded(false), + fEnabled(false), fEnabling(false) { +} + +SkApply::~SkApply() { + for (SkDrawable** curPtr = fScopes.begin(); curPtr < fScopes.end(); curPtr++) + delete *curPtr; + if (fDeleteScope) + delete scope; + // !!! caller must call maker.removeActive(fActive) + delete fActive; +} + +void SkApply::activate(SkAnimateMaker& maker) { + if (fActive != nil) { + if (fActive->fDrawIndex == 0 && fActive->fDrawMax == 0) + return; // if only one use, nothing more to do + if (restore == false) + return; // all share same state, regardless of instance number + bool save = fActive->initializeSave(); + fActive->fixInterpolator(save); + } else { + fActive = new SkActive(*this, maker); + fActive->init(); + maker.appendActive(fActive); + if (restore) { + fActive->initializeSave(); + int animators = fAnimators.count(); + for (int index = 0; index < animators; index++) + fActive->saveInterpolatorValues(index); + } + } +} + +void SkApply::append(SkApply* apply) { + if (fActive == nil) + return; + int oldCount = fActive->fAnimators.count(); + fActive->append(apply); + if (restore) { + fActive->appendSave(oldCount); + int newCount = fActive->fAnimators.count(); + for (int index = oldCount; index < newCount; index++) + fActive->saveInterpolatorValues(index); + } +} + +void SkApply::applyValues(int animatorIndex, SkOperand* values, int count, + SkDisplayTypes valuesType, SkMSec time) +{ + SkAnimateBase* animator = fActive->fAnimators[animatorIndex]; + const SkMemberInfo * info = animator->fFieldInfo; + SkASSERT(animator); + SkASSERT(info != nil); + SkDisplayTypes type = (SkDisplayTypes) info->fType; + SkDisplayable* target = getTarget(animator); + if (animator->hasExecute() || type == SkType_MemberFunction || type == SkType_MemberProperty) { + SkDisplayable* executor = animator->hasExecute() ? animator : target; + if (type != SkType_MemberProperty) { + SkTDArray<SkScriptValue> typedValues; + for (int index = 0; index < count; index++) { + SkScriptValue temp; + temp.fType = valuesType; + temp.fOperand = values[index]; + *typedValues.append() = temp; + } + executor->executeFunction(target, info->functionIndex(), typedValues, info->getType(), nil); + } else { + SkScriptValue scriptValue; + scriptValue.fOperand = values[0]; + scriptValue.fType = info->getType(); + target->setProperty(info->propertyIndex(), scriptValue); + } + } else { + SkTypedArray converted; + if (type == SkType_ARGB) { + if (count == 4) { + // !!! assert that it is SkType_Float ? + animator->packARGB(&values->fScalar, count, &converted); + values = converted.begin(); + count = converted.count(); + } else + SkASSERT(count == 1); + } +// SkASSERT(type == SkType_ARGB || type == SkType_String ||info->isSettable()); + if (type == SkType_String || type == SkType_DynamicString) + info->setString(target, values->fString); + else if (type == SkType_Drawable || type == SkType_Displayable) + target->setReference(info, values->fDisplayable); + else + info->setValue(target, values, count); + } +} + +bool SkApply::contains(SkDisplayable* child) { + for (SkDrawable** curPtr = fScopes.begin(); curPtr < fScopes.end(); curPtr++) { + if (*curPtr == child || (*curPtr)->contains(child)) + return true; + } + return fDeleteScope && scope == child; +} + +SkDisplayable* SkApply::deepCopy(SkAnimateMaker* maker) { + SkDrawable* saveScope = scope; + scope = nil; + SkApply* result = (SkApply*) INHERITED::deepCopy(maker); + result->scope = scope = saveScope; + SkAnimateBase** end = fAnimators.end(); + for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < end; animPtr++) { + SkAnimateBase* anim = (SkAnimateBase*) (*animPtr)->deepCopy(maker); + *result->fAnimators.append() = anim; + maker->helperAdd(anim); + } + return result; +} + +void SkApply::disable() { + //!!! this is the right thing to do, but has bad side effects because of other problems + // currently, if an apply is in a g and scopes a statement in another g, it ends up as members + // of both containers. The disabling here incorrectly disables both instances + // maybe the fEnabled flag needs to be moved to the fActive data so that both + // instances are not affected. +// fEnabled = false; +} + +bool SkApply::draw(SkAnimateMaker& maker) { + if (scope ==nil) + return false; + if (scope->isApply() || scope->isDrawable() == false) + return false; + if (fEnabled == false) + enable(maker); + SkASSERT(scope); + activate(maker); + if (mode == kMode_immediate) + return fActive->draw(); + bool result = interpolate(maker, maker.getInTime()); + if (dontDraw == false) { +// if (scope->isDrawable()) + result |= scope->draw(maker); + } + if (restore) { + for (int index = 0; index < fActive->fAnimators.count(); index++) + endSave(index); + fActive->advance(); + } + return result; +} + +#ifdef SK_DUMP_ENABLED +void SkApply::dump(SkAnimateMaker* maker) { + dumpBase(maker); + if (dynamicScope.isEmpty() == false) + SkDebugf("dynamicScope=\"%s\" ", dynamicScope.c_str()); + if (dontDraw) + SkDebugf("dontDraw=\"true\" "); + if (begin != 0) //perhaps we want this no matter what? + SkDebugf("begin=\"%g\" ", (float) begin/1000.0f); //is this correct? + if (interval != (SkMSec) -1) + SkDebugf("interval=\"%g\" ", (float) interval/1000.0f); + if (steps != -1) + SkDebugf("steps=\"%d\" ", steps); + if (restore) + SkDebugf("restore=\"true\" "); + if (transition == kTransition_reverse) + SkDebugf("transition=\"reverse\" "); + if (mode == kMode_immediate) { + SkDebugf("mode=\"immediate\" "); + } + else if (mode == kMode_create) { + SkDebugf("mode=\"create\" "); + } + bool closedYet = false; + SkDisplayList::fIndent += 4; + int save = SkDisplayList::fDumpIndex; + if (scope) { + if (closedYet == false) { + SkDebugf(">\n"); + closedYet = true; + } + scope->dump(maker); + } + int index; +// if (fActive) { + for (index = 0; index < fAnimators.count(); index++) { + if (closedYet == false) { + SkDebugf(">\n"); + closedYet = true; + } + SkAnimateBase* animator = fAnimators[index]; + animator->dump(maker); +// } + } + SkDisplayList::fIndent -= 4; + SkDisplayList::fDumpIndex = save; + if (closedYet) + dumpEnd(maker); + else + SkDebugf("/>\n"); +} +#endif + +bool SkApply::enable(SkAnimateMaker& maker) { + fEnabled = true; + bool initialized = fActive != nil; + if (dynamicScope.size() > 0) + enableDynamic(maker); + if (maker.fError.hasError()) + return false; + int animators = fAnimators.count(); + int index; + for (index = 0; index < animators; index++) { + SkAnimateBase* animator = fAnimators[index]; + animator->fStart = maker.fEnableTime; + animator->fResetPending = animator->fReset; + } + if (scope && scope->isApply()) + ((SkApply*) scope)->setEmbedded(); +/* if (mode == kMode_once) { + if (scope) { + activate(maker); + interpolate(maker, maker.fEnableTime); + inactivate(maker); + } + return true; + }*/ + if ((mode == kMode_immediate || mode == kMode_create) && scope == nil) + return false; // !!! error? + bool enableMe = scope && (scope->hasEnable() || scope->isApply() || scope->isDrawable() == false); + if (mode == kMode_immediate && enableMe || mode == kMode_create) + activate(maker); // for non-drawables like post, prime them here + if (mode == kMode_immediate && enableMe) + fActive->enable(); + if (mode == kMode_create && scope != nil) { + enableCreate(maker); + return true; + } + if (mode == kMode_immediate) { + return scope->isApply() || scope->isDrawable() == false; + } + refresh(maker); + SkDisplayList& displayList = maker.fDisplayList; + SkDrawable* drawable; +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + SkString debugOut; + SkMSec time = maker.getAppTime(); + debugOut.appendS32(time - maker.fDebugTimeBase); + debugOut.append(" apply enable id="); + debugOut.append(_id); + debugOut.append("; start="); + debugOut.appendS32(maker.fEnableTime - maker.fDebugTimeBase); + SkDebugf("%s\n", debugOut.c_str()); +#endif + if (scope == nil || scope->isApply() || scope->getType() == SkType_Movie || scope->isDrawable() == false) { + activate(maker); // for non-drawables like post, prime them here + if (initialized) { + append(this); + } + fEnabling = true; + interpolate(maker, maker.fEnableTime); + fEnabling = false; + if (scope != nil && dontDraw == false) + scope->enable(maker); + return true; + } else if (initialized && restore == false) + append(this); +#if 0 + bool wasActive = inactivate(maker); // start fresh + if (wasActive) { + activate(maker); + interpolate(maker, maker.fEnableTime); + return true; + } +#endif +// start here; + // now that one apply might embed another, only the parent apply should replace the scope + // or get appended to the display list + // similarly, an apply added by an add immediate has already been located in the display list + // and should not get moved or added again here + if (fEmbedded) { + return false; // already added to display list by embedder + } + drawable = (SkDrawable*) scope; + SkTDDrawableArray* parentList; + SkTDDrawableArray* grandList; + SkGroup* parentGroup; + SkGroup* thisGroup; + int old = displayList.findGroup(drawable, &parentList, &parentGroup, &thisGroup, &grandList); + if (old < 0) + goto append; + else if (fContainsScope) { + if ((*parentList)[old] != this || restore == true) { +append: + if (parentGroup) + parentGroup->markCopySize(old); + if (parentList->count() < 10000) { + fAppended = true; + *parentList->append() = this; + } else + maker.setErrorCode(SkDisplayXMLParserError::kDisplayTreeTooDeep); + old = -1; + } else + reset(); + } else { + SkASSERT(old < parentList->count()); + if ((*parentList)[old]->isApply()) { + SkApply* apply = (SkApply*) (*parentList)[old]; + if (apply != this && apply->fActive == nil) + apply->activate(maker); + apply->append(this); + parentGroup = nil; + } else { + if (parentGroup) + parentGroup->markCopySize(old); + SkDrawable** newApplyLocation = &(*parentList)[old]; + SkGroup* pGroup; + int oldApply = displayList.findGroup(this, &parentList, &pGroup, &thisGroup, &grandList); + if (oldApply >= 0) { + (*parentList)[oldApply] = (SkDrawable*) SkDisplayType::CreateInstance(&maker, SkType_Apply); + parentGroup = nil; + fDeleteScope = true; + } + *newApplyLocation = this; + } + } + if (parentGroup) { + parentGroup->markCopySet(old); + fDeleteScope = dynamicScope.size() == 0; + } + return true; +} + +void SkApply::enableCreate(SkAnimateMaker& maker) { + SkString newID; + for (int step = 0; step <= steps; step++) { + fLastTime = step * SK_MSec1; + bool success = maker.computeID(scope, this, &newID); + if (success == false) + return; + if (maker.find(newID.c_str(), nil)) + continue; + SkApply* copy = (SkApply*) deepCopy(&maker); // work on copy of animator state + if (mode == kMode_create) + copy->mode = (Mode) -1; + SkDrawable* copyScope = copy->scope = (SkDrawable*) scope->deepCopy(&maker); + *fScopes.append() = copyScope; + if (copyScope->resolveIDs(maker, scope, this)) { + step = steps; // quit + goto next; // resolveIDs failed + } + if (newID.size() > 0) + maker.setID(copyScope, newID); + if (copy->resolveIDs(maker, this, this)) { // fix up all fields, including target + step = steps; // quit + goto next; // resolveIDs failed + } + copy->activate(maker); + copy->interpolate(maker, step * SK_MSec1); + maker.removeActive(copy->fActive); + next: + delete copy; + } +} + +void SkApply::enableDynamic(SkAnimateMaker& maker) { + SkASSERT(mode != kMode_create); // create + dynamic are not currently compatible + SkDisplayable* newScope; + bool success = SkAnimatorScript::EvaluateDisplayable(maker, this, dynamicScope.c_str(), + &newScope); + if (success && scope != newScope) { + SkTDDrawableArray* pList, * gList; + SkGroup* pGroup = nil, * found = nil; + int old = maker.fDisplayList.findGroup(scope, &pList, &pGroup, &found, &gList); + if (pList && old >= 0 && (*pList)[old]->isApply() && (*pList)[old] != this) { + if (fAppended == false) { + if (found != nil) { + SkDisplayable* oldChild = (*pList)[old]; + if (oldChild->isApply() && found->copySet(old)) { + found->markCopyClear(old); + // delete oldChild; + } + } + (*pList)[old] = scope; + } else + pList->remove(old); + } + scope = (SkDrawable*) newScope; + onEndElement(maker); + } + maker.removeActive(fActive); + delete fActive; + fActive = nil; +} + +void SkApply::endSave(int index) { + SkAnimateBase* animate = fActive->fAnimators[index]; + const SkMemberInfo* info = animate->fFieldInfo; + SkDisplayTypes type = (SkDisplayTypes) info->fType; + if (type == SkType_MemberFunction) + return; + SkDisplayable* target = getTarget(animate); + size_t size = info->getSize(target); + int count = (int) (size / sizeof(SkScalar)); + int activeIndex = fActive->fDrawIndex + index; + SkOperand* last = new SkOperand[count]; + SkAutoTDelete<SkOperand> autoLast(last); + if (type != SkType_MemberProperty) { + info->getValue(target, last, count); + SkOperand* saveOperand = fActive->fSaveRestore[activeIndex]; + if (saveOperand) + info->setValue(target, fActive->fSaveRestore[activeIndex], count); + } else { + SkScriptValue scriptValue; + bool success = target->getProperty(info->propertyIndex(), &scriptValue); + SkASSERT(success = true); + last[0] = scriptValue.fOperand; + scriptValue.fOperand = fActive->fSaveRestore[activeIndex][0]; + target->setProperty(info->propertyIndex(), scriptValue); + } + SkOperand* save = fActive->fSaveRestore[activeIndex]; + if (save) + memcpy(save, last, count * sizeof(SkOperand)); +} + +bool SkApply::getProperty(int index, SkScriptValue* value) const { + switch (index) { + case SK_PROPERTY(step): + value->fType = SkType_Int; + value->fOperand.fS32 = fLastTime / SK_MSec1; + break; + case SK_PROPERTY(steps): + value->fType = SkType_Int; + value->fOperand.fS32 = steps; + break; + case SK_PROPERTY(time): + value->fType = SkType_MSec; + value->fOperand.fS32 = fLastTime; + break; + default: + // SkASSERT(0); + return false; + } + return true; +} + +void SkApply::getStep(SkScriptValue* value) { + getProperty(SK_PROPERTY(step), value); +} + +SkDrawable* SkApply::getTarget(SkAnimateBase* animate) { + if (animate->fTargetIsScope == false || mode != kMode_create) + return animate->fTarget; + return scope; +} + +bool SkApply::hasDelayedAnimator() const { + SkAnimateBase** animEnd = fAnimators.end(); + for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < animEnd; animPtr++) { + SkAnimateBase* animator = *animPtr; + if (animator->fDelayed) + return true; + } + return false; +} + +bool SkApply::hasEnable() const { + return true; +} + +bool SkApply::inactivate(SkAnimateMaker& maker) { + if (fActive == nil) + return false; + maker.removeActive(fActive); + delete fActive; + fActive = nil; + return true; +} + +#ifdef SK_DEBUG +SkMSec lastTime = (SkMSec) -1; +#endif + +bool SkApply::interpolate(SkAnimateMaker& maker, SkMSec rawTime) { + if (fActive == nil) + return false; + bool result = false; +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + SkMSec time = maker.getAppTime(); + if (lastTime == (SkMSec) -1) + lastTime = rawTime - 1; + if (fActive != nil && + strcmp(id, "a3") == 0 && rawTime > lastTime) { + lastTime += 1000; + SkString debugOut; + debugOut.appendS32(time - maker.fDebugTimeBase); + debugOut.append(" apply id="); + debugOut.append(_id); + debugOut.append("; "); + debugOut.append(fActive->fAnimators[0]->_id); + debugOut.append("="); + debugOut.appendS32(rawTime - fActive->fState[0].fStartTime); + debugOut.append(")"); + SkDebugf("%s\n", debugOut.c_str()); + } +#endif + fActive->start(); + if (restore) + fActive->initializeSave(); + int animators = fActive->fAnimators.count(); + for (int inner = 0; inner < animators; inner++) { + SkAnimateBase* animate = fActive->fAnimators[inner]; + if (animate->fChanged) { + animate->fChanged = false; + animate->fStart = rawTime; + // SkTypedArray values; + // int count = animate->fValues.count(); + // values.setCount(count); + // memcpy(values.begin(), animate->fValues.begin(), sizeof(SkOperand) * count); + animate->onEndElement(maker); + // if (memcmp(values.begin(), animate->fValues.begin(), sizeof(SkOperand) * count) != 0) { + fActive->append(this); + fActive->start(); + // } + } + SkMSec time = fActive->getTime(rawTime, inner); + SkActive::SkState& state = fActive->fState[inner]; + if (SkMSec_LT(rawTime, state.fStartTime)) { + if (fEnabling) { + animate->fDelayed = true; + maker.delayEnable(this, state.fStartTime); + } + continue; + } else + animate->fDelayed = false; + SkMSec innerTime = fLastTime = state.getRelativeTime(time); + if (restore) + fActive->restoreInterpolatorValues(inner); + if (animate->fReset) { + if (transition != SkApply::kTransition_reverse) { + if (SkMSec_LT(state.fBegin + state.fDuration, innerTime)) { + if (animate->fResetPending) { + innerTime = 0; + animate->fResetPending = false; + } else + continue; + } + } else if (innerTime == 0) { + if (animate->fResetPending) { + innerTime = state.fBegin + state.fDuration; + animate->fResetPending = false; + } else + continue; + } + } + int count = animate->components(); + SkAutoSTMalloc<16, SkOperand> values(count); + SkInterpolatorBase::Result interpResult = fActive->fInterpolators[inner]->timeToValues( + innerTime, values.get()); + result |= (interpResult != SkInterpolatorBase::kFreezeEnd_Result); + if ((transition != SkApply::kTransition_reverse && interpResult == SkInterpolatorBase::kFreezeEnd_Result || + transition == SkApply::kTransition_reverse && fLastTime == 0) && state.fUnpostedEndEvent) { +// SkDEBUGF(("interpolate: post on end\n")); + state.fUnpostedEndEvent = false; + maker.postOnEnd(animate, state.fBegin + state.fDuration); + maker.fAdjustedStart = 0; // !!! left over from synchronizing animation days, undoubtably out of date (and broken) + } + if (animate->formula.size() > 0) { + if (fLastTime > animate->dur) + fLastTime = animate->dur; + SkTypedArray formulaValues; + formulaValues.setCount(count); + bool success = animate->fFieldInfo->setValue(maker, &formulaValues, 0, 0, nil, + animate->getValuesType(), animate->formula); + SkASSERT(success); + if (restore) + save(inner); // save existing value + applyValues(inner, formulaValues.begin(), count, animate->getValuesType(), innerTime); + } else { + if (restore) + save(inner); // save existing value + applyValues(inner, values.get(), count, animate->getValuesType(), innerTime); + } + } + return result; +} + +void SkApply::initialize() { + if (scope == nil) + return; + if (scope->isApply() || scope->isDrawable() == false) + return; + scope->initialize(); +} + +void SkApply::onEndElement(SkAnimateMaker& maker) +{ + SkDrawable* scopePtr = scope; + while (scopePtr && scopePtr->isApply()) { + SkApply* scopedApply = (SkApply*) scopePtr; + if (scopedApply->scope == this) { + maker.setErrorCode(SkDisplayXMLParserError::kApplyScopesItself); + return; + } + scopePtr = scopedApply->scope; + } + if (mode == kMode_create) + return; + if (scope != nil && steps >= 0 && scope->isApply() == false && scope->isDrawable()) + scope->setSteps(steps); + for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < fAnimators.end(); animPtr++) { + SkAnimateBase* anim = *animPtr; + //for reusing apply statements with dynamic scope + if (anim->fTarget == nil || anim->fTargetIsScope) { + anim->fTargetIsScope = true; + if (scope) + anim->fTarget = scope; + else + anim->setTarget(maker); + anim->onEndElement(maker); // allows animate->fFieldInfo to be set + } + if (scope != nil && steps >= 0 && anim->fTarget != scope && anim->fTarget->isDrawable()) + anim->fTarget->setSteps(steps); + } +} + +const SkMemberInfo* SkApply::preferredChild(SkDisplayTypes type) { + SkASSERT(SkDisplayType::IsAnimate(type) == false); + fContainsScope = true; + return getMember("scope"); // !!! cwap! need to refer to member through enum like kScope instead +} + +void SkApply::refresh(SkAnimateMaker& maker) { + for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < fAnimators.end(); animPtr++) { + SkAnimateBase* animate = *animPtr; + animate->onEndElement(maker); + } + if (fActive) + fActive->resetInterpolators(); +} + +void SkApply::reset() { + if (fActive) + fActive->resetState(); +} + +bool SkApply::resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* apply) { // replace to/formula strings in animators of the form xxx.step with the step value, if xxx.step is in scope + if (resolveField(maker, apply, &dynamicScope) == false) + return true; // failed + SkAnimateBase** endPtr = fAnimators.end(); + SkAnimateBase** origPtr = ((SkApply*) original)->fAnimators.begin(); + for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < endPtr; ) { + SkAnimateBase* animator = *animPtr++; + maker.resolveID(animator, *origPtr++); + if (resolveField(maker, this, &animator->target) == false) + return true; + if (resolveField(maker, this, &animator->from) == false) + return true; + if (resolveField(maker, this, &animator->to) == false) + return true; + if (resolveField(maker, this, &animator->formula) == false) + return true; + } +// setEmbedded(); + onEndElement(maker); + return false; // succeeded +} + +bool SkApply::resolveField(SkAnimateMaker& maker, SkDisplayable* parent, SkString* str) { + const char* script = str->c_str(); + if (str->startsWith("#string:") == false) + return true; + script += sizeof("#string:") - 1; + return SkAnimatorScript::EvaluateString(maker, this, parent, script, str); +} + +void SkApply::save(int index) { + SkAnimateBase* animate = fActive->fAnimators[index]; + const SkMemberInfo * info = animate->fFieldInfo; + SkDisplayable* target = getTarget(animate); +// if (animate->hasExecute()) +// info = animate->getResolvedInfo(); + SkDisplayTypes type = (SkDisplayTypes) info->fType; + if (type == SkType_MemberFunction) + return; // nothing to save + size_t size = info->getSize(target); + int count = (int) (size / sizeof(SkScalar)); + bool useLast = true; +// !!! this all may be unneeded, at least in the dynamic case ?? + int activeIndex = fActive->fDrawIndex + index; + SkTDOperandArray last; + if (fActive->fSaveRestore[activeIndex] == nil) { + fActive->fSaveRestore[activeIndex] = new SkOperand[count]; + useLast = false; + } else { + last.setCount(count); + memcpy(last.begin(), fActive->fSaveRestore[activeIndex], count * sizeof(SkOperand)); + } + if (type != SkType_MemberProperty) { + info->getValue(target, fActive->fSaveRestore[activeIndex], count); + if (useLast) + info->setValue(target, last.begin(), count); + } else { + SkScriptValue scriptValue; + bool success = target->getProperty(info->propertyIndex(), &scriptValue); + SkASSERT(success == true); + SkASSERT(scriptValue.fType == SkType_Float); + fActive->fSaveRestore[activeIndex][0] = scriptValue.fOperand; + if (useLast) { + SkScriptValue scriptValue; + scriptValue.fType = type; + scriptValue.fOperand = last[0]; + target->setProperty(info->propertyIndex(), scriptValue); + } + } +// !!! end of unneeded +} + +bool SkApply::setProperty(int index, SkScriptValue& scriptValue) { + switch (index) { + case SK_PROPERTY(animator): { + SkAnimateBase* animate = (SkAnimateBase*) scriptValue.fOperand.fDisplayable; + SkASSERT(animate->isAnimate()); + *fAnimators.append() = animate; + return true; + } + case SK_PROPERTY(steps): + steps = scriptValue.fOperand.fS32; + if (fActive) + fActive->setSteps(steps); + return true; + } + return false; +} + +void SkApply::setSteps(int _steps) { + steps = _steps; +} + +#ifdef SK_DEBUG +void SkApply::validate() { + if (fActive) + fActive->validate(); +} +#endif + + + diff --git a/libs/graphics/animator/SkDisplayApply.h b/libs/graphics/animator/SkDisplayApply.h new file mode 100644 index 0000000000..883323af83 --- /dev/null +++ b/libs/graphics/animator/SkDisplayApply.h @@ -0,0 +1,99 @@ +#ifndef SkDisplayApply_DEFINED +#define SkDisplayApply_DEFINED + +#include "SkAnimateBase.h" +#include "SkDrawable.h" +#include "SkIntArray.h" + +class SkActive; + +class SkApply : public SkDrawable { + DECLARE_MEMBER_INFO(Apply); +public: + + SkApply(); + virtual ~SkApply(); + + enum Transition { + kTransition_normal, + kTransition_reverse + }; + + enum Mode { + kMode_create, + kMode_immediate, + //kMode_once + }; + void activate(SkAnimateMaker& ); + void append(SkApply* apply); + void appendActive(SkActive* ); + void applyValues(int animatorIndex, SkOperand* values, int count, + SkDisplayTypes , SkMSec time); + virtual bool contains(SkDisplayable*); +// void createActive(SkAnimateMaker& ); + virtual SkDisplayable* deepCopy(SkAnimateMaker* ); + void disable(); + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual bool enable(SkAnimateMaker& ); + void enableCreate(SkAnimateMaker& ); + void enableDynamic(SkAnimateMaker& ); + void endSave(int index); + Mode getMode() { return mode; } + virtual bool getProperty(int index, SkScriptValue* value) const; + SkDrawable* getScope() { return scope; } + void getStep(SkScriptValue* ); + SkDrawable* getTarget(SkAnimateBase* ); + bool hasDelayedAnimator() const; + virtual bool hasEnable() const; + bool inactivate(SkAnimateMaker& maker); + virtual void initialize(); + bool interpolate(SkAnimateMaker& , SkMSec time); + virtual void onEndElement(SkAnimateMaker& ); + virtual const SkMemberInfo* preferredChild(SkDisplayTypes type); + void refresh(SkAnimateMaker& ); + void reset(); + virtual bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* ); + bool resolveField(SkAnimateMaker& , SkDisplayable* parent, SkString* str); + void save(int index); + void setEmbedded() { fEmbedded = true; } + virtual bool setProperty(int index, SkScriptValue& ); + virtual void setSteps(int _steps); +// virtual void setTime(SkMSec time); +#ifdef SK_DEBUG + virtual void validate(); +#endif +private: + SkMSec begin; + SkBool dontDraw; + SkString dynamicScope; + SkMSec interval; + Mode mode; +#if 0 + SkBool pickup; +#endif + SkBool restore; + SkDrawable* scope; + S32 steps; + Transition transition; + SkActive* fActive; + SkTDAnimateArray fAnimators; +// SkDrawable* fCurrentScope; + SkMSec fLastTime; // used only to return script property time + SkTDDrawableArray fScopes; + SkBool fAppended : 1; + SkBool fContainsScope : 1; + SkBool fDeleteScope : 1; + SkBool fEmbedded : 1; + SkBool fEnabled : 1; + SkBool fEnabling : 1; // set if calling interpolate from enable + friend class SkActive; + friend class SkDisplayList; + typedef SkDrawable INHERITED; +}; + +#endif // SkDisplayApply_DEFINED + + diff --git a/libs/graphics/animator/SkDisplayBounds.cpp b/libs/graphics/animator/SkDisplayBounds.cpp new file mode 100644 index 0000000000..e6abcc31cd --- /dev/null +++ b/libs/graphics/animator/SkDisplayBounds.cpp @@ -0,0 +1,37 @@ +#include "SkDisplayBounds.h" +#include "SkAnimateMaker.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayBounds::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER(inval, Boolean) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayBounds); + +SkDisplayBounds::SkDisplayBounds() : inval(false) { +} + +bool SkDisplayBounds::draw(SkAnimateMaker& maker) { + maker.fDisplayList.fUnionBounds = SkToBool(inval); + maker.fDisplayList.fDrawBounds = false; + fBounds.setEmpty(); + bool result = INHERITED::draw(maker); + maker.fDisplayList.fUnionBounds = false; + maker.fDisplayList.fDrawBounds = true; + if (inval && fBounds.isEmpty() == false) { + SkRect16& rect = maker.fDisplayList.fInvalBounds; + maker.fDisplayList.fHasUnion = true; + if (rect.isEmpty()) + rect = fBounds; + else + rect.join(fBounds); + } + return result; +} + + + diff --git a/libs/graphics/animator/SkDisplayBounds.h b/libs/graphics/animator/SkDisplayBounds.h new file mode 100644 index 0000000000..077d4cc8f7 --- /dev/null +++ b/libs/graphics/animator/SkDisplayBounds.h @@ -0,0 +1,16 @@ +#ifndef SkDisplayBounds_DEFINED +#define SkDisplayBounds_DEFINED + +#include "SkDrawRectangle.h" + +class SkDisplayBounds : public SkDrawRect { + DECLARE_DISPLAY_MEMBER_INFO(Bounds); + SkDisplayBounds(); + virtual bool draw(SkAnimateMaker& ); +private: + SkBool inval; + typedef SkDrawRect INHERITED; +}; + +#endif // SkDisplayBounds_DEFINED + diff --git a/libs/graphics/animator/SkDisplayEvent.cpp b/libs/graphics/animator/SkDisplayEvent.cpp new file mode 100644 index 0000000000..46af81cffe --- /dev/null +++ b/libs/graphics/animator/SkDisplayEvent.cpp @@ -0,0 +1,248 @@ +#include "SkDisplayEvent.h" +#include "SkAnimateMaker.h" +#include "SkDisplayApply.h" +#include "SkDisplayInput.h" +#include "SkDisplayList.h" +#ifdef SK_DEBUG +#include "SkDump.h" +#endif +#include "SkEvent.h" +#include "SkDisplayInput.h" +#include "SkKey.h" +#include "SkMetaData.h" +#include "SkScript.h" +#include "SkUtils.h" + +enum SkDisplayEvent_Properties { + SK_PROPERTY(key), + SK_PROPERTY(keys) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayEvent::fInfo[] = { + SK_MEMBER(code, EventCode), + SK_MEMBER(disable, Boolean), + SK_MEMBER_PROPERTY(key, String), // a single key (also last key pressed) + SK_MEMBER_PROPERTY(keys, String), // a single key or dash-delimited range of keys + SK_MEMBER(kind, EventKind), + SK_MEMBER(target, String), + SK_MEMBER(x, Float), + SK_MEMBER(y, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayEvent); + +SkDisplayEvent::SkDisplayEvent() : code((SkKey) -1), disable(false), + kind(kUser), x(0), y(0), fLastCode((SkKey) -1), fMax((SkKey) -1), fTarget(nil) { +} + +SkDisplayEvent::~SkDisplayEvent() { + deleteMembers(); +} + +bool SkDisplayEvent::add(SkAnimateMaker& , SkDisplayable* child) { + *fChildren.append() = child; + return true; +} + +bool SkDisplayEvent::contains(SkDisplayable* match) { + for (int index = 0; index < fChildren.count(); index++) { + if (fChildren[index] == match || fChildren[index]->contains(match)) + return true; + } + return false; +} + +SkDisplayable* SkDisplayEvent::contains(const SkString& match) { + for (int index = 0; index < fChildren.count(); index++) { + SkDisplayable* child = fChildren[index]; + if (child->contains(match)) + return child; + } + return nil; +} + +void SkDisplayEvent::deleteMembers() { + for (int index = 0; index < fChildren.count(); index++) { + SkDisplayable* evt = fChildren[index]; + delete evt; + } +} + +#ifdef SK_DUMP_ENABLED +void SkDisplayEvent::dumpEvent(SkAnimateMaker* maker) { + dumpBase(maker); + SkString str; + SkDump::GetEnumString(SkType_EventKind, kind, &str); + SkDebugf("kind=\"%s\" ", str.c_str()); + if (kind == SkDisplayEvent::kKeyPress || kind == SkDisplayEvent::kKeyPressUp) { + if (code >= 0) + SkDump::GetEnumString(SkType_EventCode, code, &str); + else + str.set("none"); + SkDebugf("code=\"%s\" ", str.c_str()); + } + if (kind == SkDisplayEvent::kKeyChar) { + if (fMax != (SkKey) -1 && fMax != code) + SkDebugf("keys=\"%c - %c\" ", code, fMax); + else + SkDebugf("key=\"%c\" ", code); + } + if (fTarget != nil) { + SkDebugf("target=\"%s\" ", fTarget->id); + } + if (kind >= SkDisplayEvent::kMouseDown && kind <= SkDisplayEvent::kMouseUp) { +#ifdef SK_CAN_USE_FLOAT + SkDebugf("x=\"%g\" y=\"%g\" ", SkScalarToFloat(x), SkScalarToFloat(y)); +#else + SkDebugf("x=\"%x\" y=\"%x\" ", x, y); +#endif + } + if (disable) + SkDebugf("disable=\"true\" "); + SkDebugf("/>\n"); +} +#endif + +bool SkDisplayEvent::enableEvent(SkAnimateMaker& maker) +{ + maker.fActiveEvent = this; + if (fChildren.count() == 0) + return false; + if (disable) + return false; +#ifdef SK_DUMP_ENABLED + if (maker.fDumpEvents) { + SkDebugf("enable: "); + dumpEvent(&maker); + } +#endif + SkDisplayList& displayList = maker.fDisplayList; + for (int index = 0; index < fChildren.count(); index++) { + SkDisplayable* displayable = fChildren[index]; + if (displayable->isGroup()) { + SkTDDrawableArray* parentList = displayList.getDrawList(); + *parentList->append() = (SkDrawable*) displayable; // make it findable before children are enabled + } + if (displayable->enable(maker)) + continue; + if (maker.hasError()) + return true; + if (displayable->isDrawable() == false) + return true; // error + SkDrawable* drawable = (SkDrawable*) displayable; + SkTDDrawableArray* parentList = displayList.getDrawList(); + *parentList->append() = drawable; + } + return false; +} + +bool SkDisplayEvent::getProperty(int index, SkScriptValue* value) const { + switch (index) { + case SK_PROPERTY(key): + case SK_PROPERTY(keys): { + value->fType = SkType_String; + char scratch[8]; + SkKey convert = index == SK_PROPERTY(keys) ? code : fLastCode; + size_t size = convert > 0 ? SkUTF8_FromUnichar(convert, scratch) : 0; + fKeyString.set(scratch, size); + value->fOperand.fString = &fKeyString; + if (index != SK_PROPERTY(keys) || fMax == (SkKey) -1 || fMax == code) + break; + value->fOperand.fString->append("-"); + size = SkUTF8_FromUnichar(fMax, scratch); + value->fOperand.fString->append(scratch, size); + } break; + default: + SkASSERT(0); + return false; + } + return true; +} + +void SkDisplayEvent::onEndElement(SkAnimateMaker& maker) +{ + if (kind == kUser) + return; + maker.fEvents.addEvent(this); + if (kind == kOnEnd) { + bool found = maker.find(target.c_str(), &fTarget); + SkASSERT(found); + SkASSERT(fTarget && fTarget->isAnimate()); + SkAnimateBase* animate = (SkAnimateBase*) fTarget; + animate->setHasEndEvent(); + } +} + +void SkDisplayEvent::populateInput(SkAnimateMaker& maker, const SkEvent& fEvent) { + const SkMetaData& meta = fEvent.getMetaData(); + SkMetaData::Iter iter(meta); + SkMetaData::Type type; + int number; + const char* name; + while ((name = iter.next(&type, &number)) != nil) { + if (name[0] == '\0') + continue; + SkDisplayable* displayable; + SkInput* input; + for (int index = 0; index < fChildren.count(); index++) { + displayable = fChildren[index]; + if (displayable->getType() != SkType_Input) + continue; + input = (SkInput*) displayable; + if (input->name.equals(name)) + goto found; + } + if (!maker.find(name, &displayable) || displayable->getType() != SkType_Input) + continue; + input = (SkInput*) displayable; + found: + switch (type) { + case SkMetaData::kS32_Type: + meta.findS32(name, &input->fInt); + break; + case SkMetaData::kScalar_Type: + meta.findScalar(name, &input->fFloat); + break; + case SkMetaData::kPtr_Type: + SkASSERT(0); + break; // !!! not handled for now + case SkMetaData::kString_Type: + input->string.set(meta.findString(name)); + break; + default: + SkASSERT(0); + } + } + // re-evaluate all animators that may have built their values from input strings + for (SkDisplayable** childPtr = fChildren.begin(); childPtr < fChildren.end(); childPtr++) { + SkDisplayable* displayable = *childPtr; + if (displayable->isApply() == false) + continue; + SkApply* apply = (SkApply*) displayable; + apply->refresh(maker); + } +} + +bool SkDisplayEvent::setProperty(int index, SkScriptValue& value) { + SkASSERT(index == SK_PROPERTY(key) || index == SK_PROPERTY(keys)); + SkASSERT(value.fType == SkType_String); + SkString* string = value.fOperand.fString; + const char* chars = string->c_str(); + int count = SkUTF8_CountUnichars(chars); + SkASSERT(count >= 1); + code = (SkKey) SkUTF8_NextUnichar(&chars); + fMax = code; + SkASSERT(count == 1 || index == SK_PROPERTY(keys)); + if (--count > 0) { + SkASSERT(*chars == '-'); + chars++; + fMax = (SkKey) SkUTF8_NextUnichar(&chars); + SkASSERT(fMax >= code); + } + return true; +} + diff --git a/libs/graphics/animator/SkDisplayEvent.h b/libs/graphics/animator/SkDisplayEvent.h new file mode 100644 index 0000000000..4d5be0236f --- /dev/null +++ b/libs/graphics/animator/SkDisplayEvent.h @@ -0,0 +1,58 @@ +#ifndef SkDisplayEvent_DEFINED +#define SkDisplayEvent_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" +#include "SkIntArray.h" +#include "SkKey.h" + +class SkEvent; + +class SkDisplayEvent : public SkDisplayable { + DECLARE_DISPLAY_MEMBER_INFO(Event); + enum Kind { + kNo_kind, + kKeyChar, + kKeyPress, + kKeyPressUp, //i assume the order here is intended to match with skanimatorscript.cpp + kMouseDown, + kMouseDrag, + kMouseMove, + kMouseUp, + kOnEnd, + kOnload, + kUser + }; + SkDisplayEvent(); + virtual ~SkDisplayEvent(); + virtual bool add(SkAnimateMaker& , SkDisplayable* child); + virtual bool contains(SkDisplayable*); + virtual SkDisplayable* contains(const SkString& ); +#ifdef SK_DEBUG + void dumpEvent(SkAnimateMaker* ); +#endif + bool enableEvent(SkAnimateMaker& ); + virtual bool getProperty(int index, SkScriptValue* ) const; + virtual void onEndElement(SkAnimateMaker& maker); + void populateInput(SkAnimateMaker& , const SkEvent& fEvent); + virtual bool setProperty(int index, SkScriptValue& ); +protected: + SkKey code; + SkBool disable; + Kind kind; + SkString target; + SkScalar x; + SkScalar y; + SkTDDisplayableArray fChildren; + mutable SkString fKeyString; + SkKey fLastCode; // last key to trigger this event + SkKey fMax; // if the code expresses a range + SkDisplayable* fTarget; // used by onEnd +private: + void deleteMembers(); + friend class SkEvents; + typedef SkDisplayable INHERITED; +}; + +#endif // SkDisplayEvent_DEFINED + diff --git a/libs/graphics/animator/SkDisplayEvents.cpp b/libs/graphics/animator/SkDisplayEvents.cpp new file mode 100644 index 0000000000..405e1341bc --- /dev/null +++ b/libs/graphics/animator/SkDisplayEvents.cpp @@ -0,0 +1,104 @@ +#include "SkDisplayEvents.h" +#include "SkAnimateMaker.h" +#include "SkAnimator.h" +#include "SkDisplayEvent.h" +#include "SkDisplayMovie.h" +#include "SkDrawable.h" +#ifdef SK_DEBUG +#include "SkDump.h" +#endif + +SkEventState::SkEventState() : fCode(0), fDisable(false), fDisplayable(0), fX(0), fY(0) { +} + +SkEvents::SkEvents() { +} + +SkEvents::~SkEvents() { +} + +bool SkEvents::doEvent(SkAnimateMaker& maker, SkDisplayEvent::Kind kind, SkEventState* state) { +/*#ifdef SK_DUMP_ENABLED + if (maker.fDumpEvents) { + SkDebugf("doEvent: "); + SkString str; + SkDump::GetEnumString(SkType_EventKind, kind, &str); + SkDebugf("kind=%s ", str.c_str()); + if (state && state->fDisplayable) + state->fDisplayable->SkDisplayable::dump(&maker); + else + SkDebugf("\n"); + } +#endif*/ + bool handled = false; + SkDisplayable** firstMovie = maker.fMovies.begin(); + SkDisplayable** endMovie = maker.fMovies.end(); + for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) { + SkDisplayMovie* movie = (SkDisplayMovie*) *ptr; + if (kind != SkDisplayEvent::kOnload) + movie->doEvent(kind, state); + } + SkDisplayable* displayable = state ? state->fDisplayable : nil; + int keyCode = state ? state->fCode : 0; + int count = fEvents.count(); + for (int index = 0; index < count; index++) { + SkDisplayEvent* evt = fEvents[index]; + if (evt->disable) + continue; + if (evt->kind != kind) + continue; + if (evt->code != (SkKey) -1) { + if ((int) evt->code > keyCode || (int) (evt->fMax != (SkKey) -1 ? evt->fMax : evt->code) < keyCode) + continue; + evt->fLastCode = (SkKey) keyCode; + } + if (evt->fTarget != nil && evt->fTarget != displayable) + continue; + if (state == nil || state->fDisable == 0) { + if (kind >= SkDisplayEvent::kMouseDown && kind <= SkDisplayEvent::kMouseUp) { + evt->x = state->fX; + evt->y = state->fY; + } + if (evt->enableEvent(maker)) + fError = true; + } + handled = true; + } + return handled; +} + +#ifdef SK_DUMP_ENABLED +void SkEvents::dump(SkAnimateMaker& maker) { + int index; + SkTDDrawableArray& drawArray = maker.fDisplayList.fDrawList; + int count = drawArray.count(); + for (index = 0; index < count; index++) { + SkDrawable* drawable = drawArray[index]; + drawable->dumpEvents(); + } + count = fEvents.count(); + for (index = 0; index < count; index++) { + SkDisplayEvent* evt = fEvents[index]; + evt->dumpEvent(&maker); + } +} +#endif + +// currently this only removes onLoad events +void SkEvents::removeEvent(SkDisplayEvent::Kind kind, SkEventState* state) { + int keyCode = state ? state->fCode : 0; + SkDisplayable* displayable = state ? state->fDisplayable : nil; + for (SkDisplayEvent** evtPtr = fEvents.begin(); evtPtr < fEvents.end(); evtPtr++) { + SkDisplayEvent* evt = *evtPtr; + if (evt->kind != kind) + continue; + if (evt->code != (SkKey) -1) { + if ((int) evt->code > keyCode || (int) (evt->fMax != (SkKey) -1 ? evt->fMax : evt->code) < keyCode) + continue; + } + if (evt->fTarget != nil && evt->fTarget != displayable) + continue; + int index = fEvents.find(evt); + fEvents.remove(index); + } +} diff --git a/libs/graphics/animator/SkDisplayEvents.h b/libs/graphics/animator/SkDisplayEvents.h new file mode 100644 index 0000000000..7000b672f3 --- /dev/null +++ b/libs/graphics/animator/SkDisplayEvents.h @@ -0,0 +1,34 @@ +#ifndef SkDisplayEvents_DEFINED +#define SkDisplayEvents_DEFINED + +#include "SkEvent.h" +#include "SkDisplayEvent.h" + +struct SkEventState { + SkEventState(); + int fCode; + SkBool fDisable; + SkDisplayable* fDisplayable; + SkScalar fX; + SkScalar fY; +}; + +class SkEvents { +public: + SkEvents(); + ~SkEvents(); + void addEvent(SkDisplayEvent* evt) { *fEvents.append() = evt; } + bool doEvent(SkAnimateMaker& , SkDisplayEvent::Kind , SkEventState* ); +#ifdef SK_DUMP_ENABLED + void dump(SkAnimateMaker& ); +#endif + void reset() { fEvents.reset(); } + void removeEvent(SkDisplayEvent::Kind kind, SkEventState* ); +private: + SkTDDisplayEventArray fEvents; + SkBool fError; + friend class SkDisplayXMLParser; +}; + +#endif // SkDisplayEvents_DEFINED + diff --git a/libs/graphics/animator/SkDisplayInclude.cpp b/libs/graphics/animator/SkDisplayInclude.cpp new file mode 100644 index 0000000000..eee5f96677 --- /dev/null +++ b/libs/graphics/animator/SkDisplayInclude.cpp @@ -0,0 +1,50 @@ +#include "SkDisplayInclude.h" +#include "SkAnimateMaker.h" +#include "SkAnimator.h" + +#if 0 +#undef SK_MEMBER +#define SK_MEMBER(_member, _type) \ + { #_member, SK_OFFSETOF(BASE_CLASS::_A, _member), SkType_##_type, \ + sizeof(((BASE_CLASS::_A*) 0)->_member) / sizeof(SkScalar) } +#endif + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkInclude::fInfo[] = { + SK_MEMBER(src, String) +}; + +#endif + +DEFINE_GET_MEMBER(SkInclude); + +//SkInclude::SkInclude() { +// src.init(); +//} + +//SkInclude::~SkInclude() { +// src.unref(); +//} + +bool SkInclude::enable(SkAnimateMaker & ) { + return true; +} + +bool SkInclude::hasEnable() const { + return true; +} + +void SkInclude::onEndElement(SkAnimateMaker& maker) { + maker.fInInclude = true; + if (src.size() == 0 || maker.decodeURI(src.c_str()) == false) { + if (maker.getErrorCode() != SkXMLParserError::kNoError || maker.getNativeCode() != -1) { + maker.setInnerError(&maker, src); + maker.setErrorCode(SkDisplayXMLParserError::kInInclude); + } else { + maker.setErrorNoun(src); + maker.setErrorCode(SkDisplayXMLParserError::kIncludeNameUnknownOrMissing); + } + } + maker.fInInclude = false; +} diff --git a/libs/graphics/animator/SkDisplayInclude.h b/libs/graphics/animator/SkDisplayInclude.h new file mode 100644 index 0000000000..b842c69d21 --- /dev/null +++ b/libs/graphics/animator/SkDisplayInclude.h @@ -0,0 +1,17 @@ +#ifndef SkDisplayInclude_DEFINED +#define SkDisplayInclude_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" + +class SkInclude : public SkDisplayable { + DECLARE_MEMBER_INFO(Include); + virtual void onEndElement(SkAnimateMaker & ); + virtual bool enable(SkAnimateMaker & ); + virtual bool hasEnable() const; +protected: + SkString src; +}; + +#endif // SkDisplayInclude_DEFINED + diff --git a/libs/graphics/animator/SkDisplayInput.cpp b/libs/graphics/animator/SkDisplayInput.cpp new file mode 100644 index 0000000000..7eec8d3bf0 --- /dev/null +++ b/libs/graphics/animator/SkDisplayInput.cpp @@ -0,0 +1,46 @@ +#include "SkDisplayInput.h" + +enum SkInput_Properties { + SK_PROPERTY(initialized) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkInput::fInfo[] = { + SK_MEMBER_ALIAS(float, fFloat, Float), + SK_MEMBER_PROPERTY(initialized, Boolean), + SK_MEMBER_ALIAS(int, fInt, Int), + SK_MEMBER(name, String), + SK_MEMBER(string, String) +}; + +#endif + +DEFINE_GET_MEMBER(SkInput); + +SkInput::SkInput() : fInt((int) SK_NaN32), fFloat(SK_ScalarNaN) {} + +SkDisplayable* SkInput::contains(const SkString& string) { + return string.equals(name) ? this : nil; +} + +bool SkInput::enable(SkAnimateMaker & ) { + return true; +} + +bool SkInput::getProperty(int index, SkScriptValue* value) const { + switch (index) { + case SK_PROPERTY(initialized): + value->fType = SkType_Boolean; + value->fOperand.fS32 = fInt != (int) SK_NaN32 || + SkScalarIsNaN(fFloat) == false || string.size() > 0; + break; + default: + return false; + } + return true; +} + +bool SkInput::hasEnable() const { + return true; +} diff --git a/libs/graphics/animator/SkDisplayInput.h b/libs/graphics/animator/SkDisplayInput.h new file mode 100644 index 0000000000..b118b220f6 --- /dev/null +++ b/libs/graphics/animator/SkDisplayInput.h @@ -0,0 +1,25 @@ +#ifndef SkDisplayInput_DEFINED +#define SkDisplayInput_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" + +class SkInput : public SkDisplayable { + DECLARE_MEMBER_INFO(Input); + SkInput(); + virtual SkDisplayable* contains(const SkString& ); + virtual bool getProperty(int index, SkScriptValue* value) const; + virtual bool enable(SkAnimateMaker & ); + virtual bool hasEnable() const; +protected: + SkString name; + int32_t fInt; + SkScalar fFloat; + SkString string; +private: + friend class SkDisplayEvent; + friend class SkPost; +}; + +#endif // SkDisplayInput_DEFINED + diff --git a/libs/graphics/animator/SkDisplayList.cpp b/libs/graphics/animator/SkDisplayList.cpp new file mode 100644 index 0000000000..2e4d92841e --- /dev/null +++ b/libs/graphics/animator/SkDisplayList.cpp @@ -0,0 +1,151 @@ +#include "SkDisplayList.h" +#include "SkAnimateActive.h" +#include "SkAnimateBase.h" +#include "SkAnimateMaker.h" +#include "SkDisplayApply.h" +#include "SkDrawable.h" +#include "SkDrawGroup.h" +#include "SkDrawMatrix.h" +#include "SkInterpolator.h" +#include "SkTime.h" + +SkDisplayList::SkDisplayList() : fDrawBounds(true), fUnionBounds(false), fInTime(0) { +} + +SkDisplayList::~SkDisplayList() { +} + +void SkDisplayList::append(SkActive* active) { + *fActiveList.append() = active; +} + +bool SkDisplayList::draw(SkAnimateMaker& maker, SkMSec inTime) { + validate(); + fInTime = inTime; + bool result = false; + fInvalBounds.setEmpty(); + if (fDrawList.count()) { + for (SkActive** activePtr = fActiveList.begin(); activePtr < fActiveList.end(); activePtr++) { + SkActive* active = *activePtr; + active->reset(); + } + for (int index = 0; index < fDrawList.count(); index++) { + SkDrawable* draw = fDrawList[index]; + draw->initialize(); // allow matrices to reset themselves + SkASSERT(draw->isDrawable()); + validate(); + result |= draw->draw(maker); + } + } + validate(); + return result; +} + +int SkDisplayList::findGroup(SkDrawable* match, SkTDDrawableArray** list, + SkGroup** parent, SkGroup** found, SkTDDrawableArray**grandList) { + *parent = nil; + *list = &fDrawList; + *grandList = &fDrawList; + return SearchForMatch(match, list, parent, found, grandList); +} + +void SkDisplayList::hardReset() { + fDrawList.reset(); + fActiveList.reset(); +} + +bool SkDisplayList::onIRect(const SkRect16& r) { + fBounds = r; + return fDrawBounds; +} + +int SkDisplayList::SearchForMatch(SkDrawable* match, SkTDDrawableArray** list, + SkGroup** parent, SkGroup** found, SkTDDrawableArray**grandList) { + *found = nil; + for (int index = 0; index < (*list)->count(); index++) { + SkDrawable* draw = (**list)[index]; + if (draw == match) + return index; + if (draw->isApply()) { + SkApply* apply = (SkApply*) draw; + if (apply->scope == match) + return index; + if (apply->scope->isGroup() && SearchGroupForMatch(apply->scope, match, list, parent, found, grandList, index)) + return index; + if (apply->mode == SkApply::kMode_create) { + for (SkDrawable** ptr = apply->fScopes.begin(); ptr < apply->fScopes.end(); ptr++) { + SkDrawable* scope = *ptr; + if (scope == match) + return index; + //perhaps should call SearchGroupForMatch here as well (on scope) + } + } + } + if (draw->isGroup() && SearchGroupForMatch(draw, match, list, parent, found, grandList, index)) + return index; + + } + return -1; +} + +bool SkDisplayList::SearchGroupForMatch(SkDrawable* draw, SkDrawable* match, SkTDDrawableArray** list, + SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList, int &index) { + SkGroup* group = (SkGroup*) draw; + if (group->getOriginal() == match) + return true; + SkTDDrawableArray* saveList = *list; + int groupIndex = group->findGroup(match, list, parent, found, grandList); + if (groupIndex >= 0) { + *found = group; + index = groupIndex; + return true; + } + *list = saveList; + return false; + } + +void SkDisplayList::reset() { + for (int index = 0; index < fDrawList.count(); index++) { + SkDrawable* draw = fDrawList[index]; + if (draw->isApply() == false) + continue; + SkApply* apply = (SkApply*) draw; + apply->reset(); + } +} + +void SkDisplayList::remove(SkActive* active) { + int index = fActiveList.find(active); + SkASSERT(index >= 0); + fActiveList.remove(index); // !!! could use shuffle instead + SkASSERT(fActiveList.find(active) < 0); +} + +#ifdef SK_DUMP_ENABLED +int SkDisplayList::fDumpIndex; +int SkDisplayList::fIndent; + +void SkDisplayList::dump(SkAnimateMaker* maker) { + fIndent = 0; + dumpInner(maker); +} + +void SkDisplayList::dumpInner(SkAnimateMaker* maker) { + for (int index = 0; index < fDrawList.count(); index++) { + fDumpIndex = index; + fDrawList[fDumpIndex]->dump(maker); + } +} + +#endif + +#ifdef SK_DEBUG +void SkDisplayList::validate() { + for (int index = 0; index < fDrawList.count(); index++) { + SkDrawable* draw = fDrawList[index]; + draw->validate(); + } +} +#endif + + diff --git a/libs/graphics/animator/SkDisplayList.h b/libs/graphics/animator/SkDisplayList.h new file mode 100644 index 0000000000..30c21a646f --- /dev/null +++ b/libs/graphics/animator/SkDisplayList.h @@ -0,0 +1,62 @@ +#ifndef SkDisplayList_DEFINED +#define SkDisplayList_DEFINED + +#include "SkOperand.h" +#include "SkIntArray.h" +#include "SkBounder.h" +#include "SkRect.h" + +class SkAnimateMaker; +class SkActive; +class SkApply; +class SkDrawable; +class SkGroup; + +class SkDisplayList : public SkBounder { +public: + SkDisplayList(); + virtual ~SkDisplayList(); + void append(SkActive* ); + void clear() { fDrawList.reset(); } + int count() { return fDrawList.count(); } + bool draw(SkAnimateMaker& , SkMSec time); +#ifdef SK_DUMP_ENABLED + void dump(SkAnimateMaker* maker); + void dumpInner(SkAnimateMaker* maker); + static int fIndent; + static int fDumpIndex; +#endif + int findGroup(SkDrawable* match, SkTDDrawableArray** list, + SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList); + SkDrawable* get(int index) { return fDrawList[index]; } + SkMSec getTime() { return fInTime; } + SkTDDrawableArray* getDrawList() { return &fDrawList; } + void hardReset(); + virtual bool onIRect(const SkRect16& r); + void reset(); + void remove(SkActive* ); +#ifdef SK_DEBUG + void validate(); +#else + void validate() {} +#endif + static int SearchForMatch(SkDrawable* match, SkTDDrawableArray** list, + SkGroup** parent, SkGroup** found, SkTDDrawableArray**grandList); + static bool SearchGroupForMatch(SkDrawable* draw, SkDrawable* match, + SkTDDrawableArray** list, SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList, + int &index); +public: + SkRect16 fBounds; + SkRect16 fInvalBounds; + bool fDrawBounds; + bool fHasUnion; + bool fUnionBounds; +private: + SkTDDrawableArray fDrawList; + SkTDActiveArray fActiveList; + SkMSec fInTime; + friend class SkEvents; +}; + +#endif // SkDisplayList_DEFINED + diff --git a/libs/graphics/animator/SkDisplayMath.cpp b/libs/graphics/animator/SkDisplayMath.cpp new file mode 100644 index 0000000000..da757a35c2 --- /dev/null +++ b/libs/graphics/animator/SkDisplayMath.cpp @@ -0,0 +1,231 @@ +#include "SkDisplayMath.h" + +enum SkDisplayMath_Properties { + SK_PROPERTY(E), + SK_PROPERTY(LN10), + SK_PROPERTY(LN2), + SK_PROPERTY(LOG10E), + SK_PROPERTY(LOG2E), + SK_PROPERTY(PI), + SK_PROPERTY(SQRT1_2), + SK_PROPERTY(SQRT2) +}; + +const SkScalar SkDisplayMath::gConstants[] = { +#ifdef SK_SCALAR_IS_FLOAT + 2.718281828f, // E + 2.302585093f, // LN10 + 0.693147181f, // LN2 + 0.434294482f, // LOG10E + 1.442695041f, // LOG2E + 3.141592654f, // PI + 0.707106781f, // SQRT1_2 + 1.414213562f // SQRT2 +#else + 0x2B7E1, // E + 0x24D76, // LN10 + 0xB172, // LN2 + 0x6F2E, // LOG10E + 0x17154, // LOG2E + 0x3243F, // PI + 0xB505, // SQRT1_2 + 0x16A0A // SQRT2 +#endif +}; + +enum SkDisplayMath_Functions { + SK_FUNCTION(abs), + SK_FUNCTION(acos), + SK_FUNCTION(asin), + SK_FUNCTION(atan), + SK_FUNCTION(atan2), + SK_FUNCTION(ceil), + SK_FUNCTION(cos), + SK_FUNCTION(exp), + SK_FUNCTION(floor), + SK_FUNCTION(log), + SK_FUNCTION(max), + SK_FUNCTION(min), + SK_FUNCTION(pow), + SK_FUNCTION(random), + SK_FUNCTION(round), + SK_FUNCTION(sin), + SK_FUNCTION(sqrt), + SK_FUNCTION(tan) +}; + +const SkFunctionParamType SkDisplayMath::fFunctionParameters[] = { + (SkFunctionParamType) SkType_Float, // abs + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // acos + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // asin + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // atan + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // atan2 + (SkFunctionParamType) SkType_Float, + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // ceil + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // cos + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // exp + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // floor + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // log + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Array, // max + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Array, // min + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // pow + (SkFunctionParamType) SkType_Float, + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // random + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // round + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // sin + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // sqrt + (SkFunctionParamType) 0, + (SkFunctionParamType) SkType_Float, // tan + (SkFunctionParamType) 0 +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayMath::fInfo[] = { + SK_MEMBER_PROPERTY(E, Float), + SK_MEMBER_PROPERTY(LN10, Float), + SK_MEMBER_PROPERTY(LN2, Float), + SK_MEMBER_PROPERTY(LOG10E, Float), + SK_MEMBER_PROPERTY(LOG2E, Float), + SK_MEMBER_PROPERTY(PI, Float), + SK_MEMBER_PROPERTY(SQRT1_2, Float), + SK_MEMBER_PROPERTY(SQRT2, Float), + SK_MEMBER_FUNCTION(abs, Float), + SK_MEMBER_FUNCTION(acos, Float), + SK_MEMBER_FUNCTION(asin, Float), + SK_MEMBER_FUNCTION(atan, Float), + SK_MEMBER_FUNCTION(atan2, Float), + SK_MEMBER_FUNCTION(ceil, Float), + SK_MEMBER_FUNCTION(cos, Float), + SK_MEMBER_FUNCTION(exp, Float), + SK_MEMBER_FUNCTION(floor, Float), + SK_MEMBER_FUNCTION(log, Float), + SK_MEMBER_FUNCTION(max, Float), + SK_MEMBER_FUNCTION(min, Float), + SK_MEMBER_FUNCTION(pow, Float), + SK_MEMBER_FUNCTION(random, Float), + SK_MEMBER_FUNCTION(round, Float), + SK_MEMBER_FUNCTION(sin, Float), + SK_MEMBER_FUNCTION(sqrt, Float), + SK_MEMBER_FUNCTION(tan, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayMath); + +void SkDisplayMath::executeFunction(SkDisplayable* target, int index, + SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, + SkScriptValue* scriptValue) { + if (scriptValue == nil) + return; + SkASSERT(target == this); + SkScriptValue* array = parameters.begin(); + SkScriptValue* end = parameters.end(); + SkScalar input = parameters[0].fOperand.fScalar; + SkScalar scalarResult; + switch (index) { + case SK_FUNCTION(abs): + scalarResult = SkScalarAbs(input); + break; + case SK_FUNCTION(acos): + scalarResult = SkScalarACos(input); + break; + case SK_FUNCTION(asin): + scalarResult = SkScalarASin(input); + break; + case SK_FUNCTION(atan): + scalarResult = SkScalarATan2(input, SK_Scalar1); + break; + case SK_FUNCTION(atan2): + scalarResult = SkScalarATan2(input, parameters[1].fOperand.fScalar); + break; + case SK_FUNCTION(ceil): + scalarResult = SkIntToScalar(SkScalarCeil(input)); + break; + case SK_FUNCTION(cos): + scalarResult = SkScalarCos(input); + break; + case SK_FUNCTION(exp): + scalarResult = SkScalarExp(input); + break; + case SK_FUNCTION(floor): + scalarResult = SkIntToScalar(SkScalarFloor(input)); + break; + case SK_FUNCTION(log): + scalarResult = SkScalarLog(input); + break; + case SK_FUNCTION(max): + scalarResult = -SK_ScalarMax; + while (array < end) { + scalarResult = SkMaxScalar(scalarResult, array->fOperand.fScalar); + array++; + } + break; + case SK_FUNCTION(min): + scalarResult = SK_ScalarMax; + while (array < end) { + scalarResult = SkMinScalar(scalarResult, array->fOperand.fScalar); + array++; + } + break; + case SK_FUNCTION(pow): + // not the greatest -- but use x^y = e^(y * ln(x)) + scalarResult = SkScalarLog(input); + scalarResult = SkScalarMul(parameters[1].fOperand.fScalar, scalarResult); + scalarResult = SkScalarExp(scalarResult); + break; + case SK_FUNCTION(random): + scalarResult = fRandom.nextUScalar1(); + break; + case SK_FUNCTION(round): + scalarResult = SkIntToScalar(SkScalarRound(input)); + break; + case SK_FUNCTION(sin): + scalarResult = SkScalarSin(input); + break; + case SK_FUNCTION(sqrt): { + SkASSERT(parameters.count() == 1); + SkASSERT(type == SkType_Float); + scalarResult = SkScalarSqrt(input); + } break; + case SK_FUNCTION(tan): + scalarResult = SkScalarTan(input); + break; + default: + SkASSERT(0); + scalarResult = SK_ScalarNaN; + } + scriptValue->fOperand.fScalar = scalarResult; + scriptValue->fType = SkType_Float; +} + +const SkFunctionParamType* SkDisplayMath::getFunctionsParameters() { + return fFunctionParameters; +} + +bool SkDisplayMath::getProperty(int index, SkScriptValue* value) const { + if ((unsigned)index < SK_ARRAY_COUNT(gConstants)) { + value->fOperand.fScalar = gConstants[index]; + value->fType = SkType_Float; + return true; + } + SkASSERT(0); + return false; +} diff --git a/libs/graphics/animator/SkDisplayMath.h b/libs/graphics/animator/SkDisplayMath.h new file mode 100644 index 0000000000..ced6e42d7b --- /dev/null +++ b/libs/graphics/animator/SkDisplayMath.h @@ -0,0 +1,23 @@ +#ifndef SkDisplayMath_DEFINED +#define SkDisplayMath_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" +#include "SkRandom.h" + +class SkDisplayMath : public SkDisplayable { + DECLARE_DISPLAY_MEMBER_INFO(Math); + virtual void executeFunction(SkDisplayable* , int index, + SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, + SkScriptValue* ); + virtual const SkFunctionParamType* getFunctionsParameters(); + virtual bool getProperty(int index, SkScriptValue* value) const; +private: + mutable SkRandom fRandom; + static const SkScalar gConstants[]; + static const SkFunctionParamType fFunctionParameters[]; + +}; + +#endif // SkDisplayMath_DEFINED + diff --git a/libs/graphics/animator/SkDisplayMovie.cpp b/libs/graphics/animator/SkDisplayMovie.cpp new file mode 100644 index 0000000000..3727efec46 --- /dev/null +++ b/libs/graphics/animator/SkDisplayMovie.cpp @@ -0,0 +1,121 @@ +#include "SkDisplayMovie.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkPaint.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayMovie::fInfo[] = { + SK_MEMBER(src, String) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayMovie); + +SkDisplayMovie::SkDisplayMovie() : fDecodedSuccessfully(false), fLoaded(false), fMovieBuilt(false) { + fMovie.fMaker->fInMovie = true; +} + +SkDisplayMovie::~SkDisplayMovie() { +} + +void SkDisplayMovie::buildMovie() { + if (fMovieBuilt) + return; + SkAnimateMaker* movieMaker = fMovie.fMaker; + SkAnimateMaker* parentMaker = movieMaker->fParentMaker; + if (src.size() == 0 || parentMaker == nil) + return; + movieMaker->fPrefix.set(parentMaker->fPrefix); + fDecodedSuccessfully = fMovie.fMaker->decodeURI(src.c_str()); + if (fDecodedSuccessfully == false) { + + if (movieMaker->getErrorCode() != SkXMLParserError::kNoError || movieMaker->getNativeCode() != -1) { + movieMaker->setInnerError(parentMaker, src); + parentMaker->setErrorCode(SkDisplayXMLParserError::kInMovie); + } else { + parentMaker->setErrorNoun(src); + parentMaker->setErrorCode(SkDisplayXMLParserError::kMovieNameUnknownOrMissing); + } + } + fMovieBuilt = true; +} + +SkDisplayable* SkDisplayMovie::deepCopy(SkAnimateMaker* maker) { + SkDisplayMovie* copy = (SkDisplayMovie*) INHERITED::deepCopy(maker); + copy->fMovie.fMaker->fParentMaker = fMovie.fMaker->fParentMaker; + copy->fMovie.fMaker->fHostEventSinkID = fMovie.fMaker->fHostEventSinkID; + copy->fMovieBuilt = false; + *fMovie.fMaker->fParentMaker->fMovies.append() = copy; + return copy; +} + +void SkDisplayMovie::dirty() { + buildMovie(); +} + +bool SkDisplayMovie::doEvent(SkDisplayEvent::Kind kind, SkEventState* state) { + if (fLoaded == false) + return false; + fMovie.fMaker->fEnableTime = fMovie.fMaker->fParentMaker->fEnableTime; + return fMovie.fMaker->fEvents.doEvent(*fMovie.fMaker, kind, state); +} + +bool SkDisplayMovie::draw(SkAnimateMaker& maker) { + if (fDecodedSuccessfully == false) + return false; + if (fLoaded == false) + enable(maker); + maker.fCanvas->save(); + SkPaint local = SkPaint(*maker.fPaint); + bool result = fMovie.draw(maker.fCanvas, &local, + maker.fDisplayList.getTime()) != SkAnimator::kNotDifferent; + maker.fDisplayList.fInvalBounds.join(fMovie.fMaker->fDisplayList.fInvalBounds); + maker.fCanvas->restore(); + return result; +} + +#ifdef SK_DUMP_ENABLED +void SkDisplayMovie::dump(SkAnimateMaker* maker) { + dumpBase(maker); + SkDebugf("src=\"%s\"/>\n", src.c_str()); + SkAnimateMaker* movieMaker = fMovie.fMaker; + SkDisplayList::fIndent += 4; + movieMaker->fDisplayList.dumpInner(movieMaker); + SkDisplayList::fIndent -= 4; + dumpEnd(maker); +} + +void SkDisplayMovie::dumpEvents() { + fMovie.fMaker->fEvents.dump(*fMovie.fMaker); +} +#endif + +bool SkDisplayMovie::enable(SkAnimateMaker& maker) { + if (fDecodedSuccessfully == false) + return false; + SkAnimateMaker* movieMaker = fMovie.fMaker; + movieMaker->fEvents.doEvent(*movieMaker, SkDisplayEvent::kOnload, nil); + movieMaker->fEvents.removeEvent(SkDisplayEvent::kOnload, nil); + fLoaded = true; + movieMaker->fLoaded = true; + return false; +} + +bool SkDisplayMovie::hasEnable() const { + return true; +} + +void SkDisplayMovie::onEndElement(SkAnimateMaker& maker) { +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + fMovie.fMaker->fDebugTimeBase = maker.fDebugTimeBase; +#endif + fMovie.fMaker->fPrefix.set(maker.fPrefix); + fMovie.fMaker->fHostEventSinkID = maker.fHostEventSinkID; + fMovie.fMaker->fParentMaker = &maker; + buildMovie(); + *maker.fMovies.append() = this; +} + + diff --git a/libs/graphics/animator/SkDisplayMovie.h b/libs/graphics/animator/SkDisplayMovie.h new file mode 100644 index 0000000000..f81a740076 --- /dev/null +++ b/libs/graphics/animator/SkDisplayMovie.h @@ -0,0 +1,43 @@ +#ifndef SkDisplayMovie_DEFINED +#define SkDisplayMovie_DEFINED + +#include "SkAnimator.h" +#include "SkDrawable.h" +#include "SkMemberInfo.h" + +struct SkEventState; + +class SkDisplayMovie : public SkDrawable { + DECLARE_DISPLAY_MEMBER_INFO(Movie); + SkDisplayMovie(); + virtual ~SkDisplayMovie(); + void buildMovie(); + virtual SkDisplayable* deepCopy(SkAnimateMaker* ); + virtual void dirty(); + bool doEvent(const SkEvent& evt) { + return fLoaded && fMovie.doEvent(evt); + } + virtual bool doEvent(SkDisplayEvent::Kind , SkEventState* state ); + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); + virtual void dumpEvents(); +#endif + virtual bool enable(SkAnimateMaker& ); + const SkAnimator* getAnimator() const { return &fMovie; } + virtual bool hasEnable() const; + virtual void onEndElement(SkAnimateMaker& ); +protected: + SkString src; + SkAnimator fMovie; + SkBool8 fDecodedSuccessfully; + SkBool8 fLoaded; + SkBool8 fMovieBuilt; + friend class SkAnimateMaker; + friend class SkPost; +private: + typedef SkDrawable INHERITED; +}; + +#endif // SkDisplayMovie_DEFINED + diff --git a/libs/graphics/animator/SkDisplayNumber.cpp b/libs/graphics/animator/SkDisplayNumber.cpp new file mode 100644 index 0000000000..03de65cfb3 --- /dev/null +++ b/libs/graphics/animator/SkDisplayNumber.cpp @@ -0,0 +1,50 @@ +#include "SkDisplayNumber.h" + +enum SkDisplayNumber_Properties { + SK_PROPERTY(MAX_VALUE), + SK_PROPERTY(MIN_VALUE), + SK_PROPERTY(NEGATIVE_INFINITY), + SK_PROPERTY(NaN), + SK_PROPERTY(POSITIVE_INFINITY) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayNumber::fInfo[] = { + SK_MEMBER_PROPERTY(MAX_VALUE, Float), + SK_MEMBER_PROPERTY(MIN_VALUE, Float), + SK_MEMBER_PROPERTY(NEGATIVE_INFINITY, Float), + SK_MEMBER_PROPERTY(NaN, Float), + SK_MEMBER_PROPERTY(POSITIVE_INFINITY, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayNumber); + +bool SkDisplayNumber::getProperty(int index, SkScriptValue* value) const { + SkScalar constant; + switch (index) { + case SK_PROPERTY(MAX_VALUE): + constant = SK_ScalarMax; + break; + case SK_PROPERTY(MIN_VALUE): + constant = SK_ScalarMin; + break; + case SK_PROPERTY(NEGATIVE_INFINITY): + constant = -SK_ScalarInfinity; + break; + case SK_PROPERTY(NaN): + constant = SK_ScalarNaN; + break; + case SK_PROPERTY(POSITIVE_INFINITY): + constant = SK_ScalarInfinity; + break; + default: + SkASSERT(0); + return false; + } + value->fOperand.fScalar = constant; + value->fType = SkType_Float; + return true; +} diff --git a/libs/graphics/animator/SkDisplayNumber.h b/libs/graphics/animator/SkDisplayNumber.h new file mode 100644 index 0000000000..7b2ea58557 --- /dev/null +++ b/libs/graphics/animator/SkDisplayNumber.h @@ -0,0 +1,13 @@ +#ifndef SkDisplayNumber_DEFINED +#define SkDisplayNumber_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" + +class SkDisplayNumber : public SkDisplayable { + DECLARE_DISPLAY_MEMBER_INFO(Number); + virtual bool getProperty(int index, SkScriptValue* value) const; +private: +}; + +#endif // SkDisplayNumber_DEFINED diff --git a/libs/graphics/animator/SkDisplayPost.cpp b/libs/graphics/animator/SkDisplayPost.cpp new file mode 100644 index 0000000000..fad3aee528 --- /dev/null +++ b/libs/graphics/animator/SkDisplayPost.cpp @@ -0,0 +1,298 @@ +#include "SkDisplayPost.h" +#include "SkAnimateMaker.h" +#include "SkAnimator.h" +#include "SkDisplayMovie.h" +#include "SkPostParts.h" +#include "SkScript.h" +#ifdef SK_DEBUG +#include "SkDump.h" +#include "SkTime.h" +#endif + +enum SkPost_Properties { + SK_PROPERTY(target), + SK_PROPERTY(type) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkPost::fInfo[] = { + SK_MEMBER(delay, MSec), +// SK_MEMBER(initialized, Boolean), + SK_MEMBER(mode, EventMode), + SK_MEMBER(sink, String), + SK_MEMBER_PROPERTY(target, String), + SK_MEMBER_PROPERTY(type, String) +}; + +#endif + +DEFINE_GET_MEMBER(SkPost); + +SkPost::SkPost() : delay(0), /*initialized(SkBool(-1)), */ mode(kImmediate), fMaker(nil), + fSinkID(0), fTargetMaker(nil), fChildHasID(false), fDirty(false) { +} + +SkPost::~SkPost() { + for (SkData** part = fParts.begin(); part < fParts.end(); part++) + delete *part; +} + +bool SkPost::add(SkAnimateMaker& , SkDisplayable* child) { + SkASSERT(child && child->isData()); + SkData* part = (SkData*) child; + *fParts.append() = part; + return true; +} + +bool SkPost::childrenNeedDisposing() const { + return false; +} + +void SkPost::dirty() { + fDirty = true; +} + +#ifdef SK_DUMP_ENABLED +void SkPost::dump(SkAnimateMaker* maker) { + dumpBase(maker); + SkString* eventType = new SkString(); + fEvent.getType(eventType); + if (eventType->equals("user")) { + const char* target = fEvent.findString("id"); + SkDebugf("target=\"%s\" ", target); + } + else + SkDebugf("type=\"%s\" ", eventType->c_str()); + delete eventType; + + if (delay > 0) { +#ifdef SK_CAN_USE_FLOAT + SkDebugf("delay=\"%g\" ", SkScalarToFloat(SkScalarDiv(delay, 1000))); +#else + SkDebugf("delay=\"%x\" ", SkScalarDiv(delay, 1000)); +#endif + } +// if (initialized == false) +// SkDebugf("(uninitialized) "); + SkString string; + SkDump::GetEnumString(SkType_EventMode, mode, &string); + if (!string.equals("immediate")) + SkDebugf("mode=\"%s\" ", string.c_str()); + // !!! could enhance this to search through make hierarchy to show name of sink + if (sink.size() > 0) { + SkDebugf("sink=\"%s\" sinkID=\"%d\" ", sink.c_str(), fSinkID); + } else if (fSinkID != maker->getAnimator()->getSinkID() && fSinkID != 0) { + SkDebugf("sinkID=\"%d\" ", fSinkID); + } + const SkMetaData& meta = fEvent.getMetaData(); + SkMetaData::Iter iter(meta); + SkMetaData::Type type; + int number; + const char* name; + bool closedYet = false; + SkDisplayList::fIndent += 4; + //this seems to work, but kinda hacky + //for some reason the last part is id, which i don't want + //and the parts seem to be in the reverse order from the one in which we find the + //data itself + //SkData** ptr = fParts.end(); + //SkData* data; + //const char* ID; + while ((name = iter.next(&type, &number)) != nil) { + //ptr--; + if (strcmp(name, "id") == 0) + continue; + if (closedYet == false) { + SkDebugf(">\n"); + closedYet = true; + } + //data = *ptr; + //if (data->id) + // ID = data->id; + //else + // ID = ""; + SkDebugf("%*s<data name=\"%s\" ", SkDisplayList::fIndent, "", name); + switch (type) { + case SkMetaData::kS32_Type: { + int32_t s32; + meta.findS32(name, &s32); + SkDebugf("int=\"%d\" ", s32); + } break; + case SkMetaData::kScalar_Type: { + SkScalar scalar; + meta.findScalar(name, &scalar); +#ifdef SK_CAN_USE_FLOAT + SkDebugf("float=\"%g\" ", SkScalarToFloat(scalar)); +#else + SkDebugf("float=\"%x\" ", scalar); +#endif + } break; + case SkMetaData::kString_Type: + SkDebugf("string=\"%s\" ", meta.findString(name)); + break; + case SkMetaData::kPtr_Type: {//when do we have a pointer + void* ptr; + meta.findPtr(name, &ptr); + SkDebugf("0x%08x ", ptr); + } break; + case SkMetaData::kBool_Type: { + bool boolean; + meta.findBool(name, &boolean); + SkDebugf("boolean=\"%s\" ", boolean ? "true " : "false "); + } break; + default: + break; + } + SkDebugf("/>\n"); + //ptr++; +/* perhaps this should only be done in the case of a pointer? + SkDisplayable* displayable; + if (maker->find(name, &displayable)) + displayable->dump(maker); + else + SkDebugf("\n");*/ + } + SkDisplayList::fIndent -= 4; + if (closedYet) + dumpEnd(maker); + else + SkDebugf("/>\n"); + +} +#endif + +bool SkPost::enable(SkAnimateMaker& maker ) { + if (maker.hasError()) + return true; + if (fDirty) { + if (sink.size() > 0) + findSinkID(); + if (fChildHasID) { + SkString preserveID(fEvent.findString("id")); + fEvent.getMetaData().reset(); + if (preserveID.size() > 0) + fEvent.setString("id", preserveID); + for (SkData** part = fParts.begin(); part < fParts.end(); part++) { + if ((*part)->add()) + maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingDataToPost); + } + } + fDirty = false; + } +#ifdef SK_DUMP_ENABLED + if (maker.fDumpPosts) { + SkDebugf("post enable: "); + dump(&maker); + } +#if defined SK_DEBUG_ANIMATION_TIMING + SkString debugOut; + SkMSec time = maker.getAppTime(); + debugOut.appendS32(time - maker.fDebugTimeBase); + debugOut.append(" post id="); + debugOut.append(_id); + debugOut.append(" enable="); + debugOut.appendS32(maker.fEnableTime - maker.fDebugTimeBase); + debugOut.append(" delay="); + debugOut.appendS32(delay); +#endif +#endif +// SkMSec adjustedDelay = maker.adjustDelay(maker.fEnableTime, delay); + SkMSec futureTime = maker.fEnableTime + delay; + fEvent.setFast32(futureTime); +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + debugOut.append(" future="); + debugOut.appendS32(futureTime - maker.fDebugTimeBase); + SkDebugf("%s\n", debugOut.c_str()); +#endif + SkEventSinkID targetID = fSinkID; + bool isAnimatorEvent = true; + SkAnimator* anim = maker.getAnimator(); + if (targetID == 0) { + isAnimatorEvent = fEvent.findString("id") != nil; + if (isAnimatorEvent) + targetID = anim->getSinkID(); + else if (maker.fHostEventSinkID) + targetID = maker.fHostEventSinkID; + else + return true; + } else + anim = fTargetMaker->getAnimator(); + if (delay == 0) { + if (isAnimatorEvent && mode == kImmediate) + fTargetMaker->doEvent(fEvent); + else + anim->onEventPost(new SkEvent(fEvent), targetID); + } else + anim->onEventPostTime(new SkEvent(fEvent), targetID, futureTime); + return true; +} + +void SkPost::findSinkID() { + // get the next delimiter '.' if any + fTargetMaker = fMaker; + const char* ch = sink.c_str(); + do { + const char* end = strchr(ch, '.'); + size_t len = end ? end - ch : strlen(ch); + SkDisplayable* displayable = nil; + if (SK_LITERAL_STR_EQUAL("parent", ch, len)) { + if (fTargetMaker->fParentMaker) + fTargetMaker = fTargetMaker->fParentMaker; + else { + fTargetMaker->setErrorCode(SkDisplayXMLParserError::kNoParentAvailable); + return; + } + } else { + fTargetMaker->find(ch, len, &displayable); + if (displayable == nil || displayable->getType() != SkType_Movie) { + fTargetMaker->setErrorCode(SkDisplayXMLParserError::kExpectedMovie); + return; + } + SkDisplayMovie* movie = (SkDisplayMovie*) displayable; + fTargetMaker = movie->fMovie.fMaker; + } + if (end == nil) + break; + ch = ++end; + } while (true); + SkAnimator* anim = fTargetMaker->getAnimator(); + fSinkID = anim->getSinkID(); +} + +bool SkPost::hasEnable() const { + return true; +} + +void SkPost::onEndElement(SkAnimateMaker& maker) { + fTargetMaker = fMaker = &maker; + if (fChildHasID == false) { + for (SkData** part = fParts.begin(); part < fParts.end(); part++) + delete *part; + fParts.reset(); + } +} + +void SkPost::setChildHasID() { + fChildHasID = true; +} + +bool SkPost::setProperty(int index, SkScriptValue& value) { + SkASSERT(value.fType == SkType_String); + SkString* string = value.fOperand.fString; + switch(index) { + case SK_PROPERTY(target): { + fEvent.setType("user"); + fEvent.setString("id", *string); + mode = kImmediate; + } break; + case SK_PROPERTY(type): + fEvent.setType(*string); + break; + default: + SkASSERT(0); + return false; + } + return true; +} + diff --git a/libs/graphics/animator/SkDisplayPost.h b/libs/graphics/animator/SkDisplayPost.h new file mode 100644 index 0000000000..cfc2fabb66 --- /dev/null +++ b/libs/graphics/animator/SkDisplayPost.h @@ -0,0 +1,50 @@ +#ifndef SkDisplayPost_DEFINED +#define SkDisplayPost_DEFINED + +#include "SkDisplayable.h" +#include "SkEvent.h" +#include "SkEventSink.h" +#include "SkMemberInfo.h" +#include "SkIntArray.h" + +class SkData; +class SkAnimateMaker; + +class SkPost : public SkDisplayable { + DECLARE_MEMBER_INFO(Post); + enum Mode { + kDeferred, + kImmediate + }; + SkPost(); + virtual ~SkPost(); + virtual bool add(SkAnimateMaker& , SkDisplayable* child); + virtual bool childrenNeedDisposing() const; + virtual void dirty(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual bool enable(SkAnimateMaker& ); + virtual bool hasEnable() const; + virtual void onEndElement(SkAnimateMaker& ); + virtual void setChildHasID(); + virtual bool setProperty(int index, SkScriptValue& ); +protected: + SkMSec delay; + SkString sink; +// SkBool initialized; + Mode mode; + SkEvent fEvent; + SkAnimateMaker* fMaker; + SkTDDataArray fParts; + SkEventSinkID fSinkID; + SkAnimateMaker* fTargetMaker; + SkBool8 fChildHasID; + SkBool8 fDirty; +private: + void findSinkID(); + friend class SkData; + typedef SkDisplayable INHERITED; +}; + +#endif //SkDisplayPost_DEFINED diff --git a/libs/graphics/animator/SkDisplayRandom.cpp b/libs/graphics/animator/SkDisplayRandom.cpp new file mode 100644 index 0000000000..53775d30d8 --- /dev/null +++ b/libs/graphics/animator/SkDisplayRandom.cpp @@ -0,0 +1,63 @@ +#include "SkDisplayRandom.h" +#include "SkInterpolator.h" + +enum SkDisplayRandom_Properties { + SK_PROPERTY(random), + SK_PROPERTY(seed) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayRandom::fInfo[] = { + SK_MEMBER(blend, Float), + SK_MEMBER(max, Float), + SK_MEMBER(min, Float), + SK_MEMBER_DYNAMIC_PROPERTY(random, Float), + SK_MEMBER_PROPERTY(seed, Int) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayRandom); + +SkDisplayRandom::SkDisplayRandom() : blend(0), min(0), max(SK_Scalar1) { +} + +#ifdef SK_DUMP_ENABLED +void SkDisplayRandom::dump(SkAnimateMaker* maker) { + dumpBase(maker); +#ifdef SK_CAN_USE_FLOAT + SkDebugf("min=\"%g\" ", SkScalarToFloat(min)); + SkDebugf("max=\"%g\" ", SkScalarToFloat(max)); + SkDebugf("blend=\"%g\" ", SkScalarToFloat(blend)); +#else + SkDebugf("min=\"%x\" ", min); + SkDebugf("max=\"%x\" ", max); + SkDebugf("blend=\"%x\" ", blend); +#endif + SkDebugf("/>\n"); +} +#endif + +bool SkDisplayRandom::getProperty(int index, SkScriptValue* value) const { + switch(index) { + case SK_PROPERTY(random): { + SkScalar random = fRandom.nextUScalar1(); + SkScalar relativeT = SkInterpolatorBase::Blend(random, blend); + value->fOperand.fScalar = min + SkScalarMul(max - min, relativeT); + value->fType = SkType_Float; + return true; + } + default: + SkASSERT(0); + } + return false; +} + +bool SkDisplayRandom::setProperty(int index, SkScriptValue& value) { + SkASSERT(index == SK_PROPERTY(seed)); + SkASSERT(value.fType == SkType_Int); + fRandom.setSeed(value.fOperand.fS32); + return true; +} + diff --git a/libs/graphics/animator/SkDisplayRandom.h b/libs/graphics/animator/SkDisplayRandom.h new file mode 100644 index 0000000000..bcfc945cc5 --- /dev/null +++ b/libs/graphics/animator/SkDisplayRandom.h @@ -0,0 +1,32 @@ +#ifndef SkDisplayRandom_DEFINED +#define SkDisplayRandom_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" +#include "SkRandom.h" + +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif + +class SkDisplayRandom : public SkDisplayable { + DECLARE_DISPLAY_MEMBER_INFO(Random); + SkDisplayRandom(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual bool getProperty(int index, SkScriptValue* value) const; + virtual bool setProperty(int index, SkScriptValue& ); +private: + SkScalar blend; + SkScalar min; + SkScalar max; + mutable SkRandom fRandom; +}; + +#endif // SkDisplayRandom_DEFINED + diff --git a/libs/graphics/animator/SkDisplayScreenplay.cpp b/libs/graphics/animator/SkDisplayScreenplay.cpp new file mode 100644 index 0000000000..44c7a8954b --- /dev/null +++ b/libs/graphics/animator/SkDisplayScreenplay.cpp @@ -0,0 +1,13 @@ +#include "SkDisplayScreenplay.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayScreenplay::fInfo[] = { + SK_MEMBER(time, MSec) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayScreenplay); + + diff --git a/libs/graphics/animator/SkDisplayScreenplay.h b/libs/graphics/animator/SkDisplayScreenplay.h new file mode 100644 index 0000000000..6d11f7aced --- /dev/null +++ b/libs/graphics/animator/SkDisplayScreenplay.h @@ -0,0 +1,12 @@ +#ifndef SkDisplayScreenplay_DEFINED +#define SkDisplayScreenplay_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" + +class SkDisplayScreenplay : public SkDisplayable { + DECLARE_DISPLAY_MEMBER_INFO(Screenplay); + SkMSec time; +}; + +#endif // SkDisplayScreenplay_DEFINED diff --git a/libs/graphics/animator/SkDisplayType.cpp b/libs/graphics/animator/SkDisplayType.cpp new file mode 100644 index 0000000000..dfb536ff4a --- /dev/null +++ b/libs/graphics/animator/SkDisplayType.cpp @@ -0,0 +1,757 @@ +#include "SkDisplayType.h" +#include "SkAnimateMaker.h" +#include "SkAnimateSet.h" +#include "SkDisplayAdd.h" +#include "SkDisplayApply.h" +#include "SkDisplayBounds.h" +#include "SkDisplayEvent.h" +#include "SkDisplayInclude.h" +#ifdef SK_DEBUG +#include "SkDisplayList.h" +#endif +#include "SkDisplayMath.h" +#include "SkDisplayMovie.h" +#include "SkDisplayNumber.h" +#include "SkDisplayPost.h" +#include "SkDisplayRandom.h" +#include "SkDisplayTypes.h" +#include "SkDraw3D.h" +#include "SkDrawBitmap.h" +#include "SkDrawClip.h" +#include "SkDrawDash.h" +#include "SkDrawDiscrete.h" +#include "SkDrawEmboss.h" +#include "SkDrawFull.h" +#include "SkDrawGradient.h" +#include "SkDrawLine.h" +#include "SkDrawMatrix.h" +#include "SkDrawOval.h" +#include "SkDrawPaint.h" +#include "SkDrawPath.h" +#include "SkDrawPoint.h" +#include "SkDrawSaveLayer.h" +#include "SkDrawText.h" +#include "SkDrawTextBox.h" +#include "SkDrawTo.h" +#include "SkDrawTransparentShader.h" +#include "SkDump.h" +#include "SkExtras.h" +#include "SkHitClear.h" +#include "SkHitTest.h" +#include "SkMatrixParts.h" +#include "SkPathParts.h" +#include "SkPostParts.h" +#include "SkSnapshot.h" +#include "SkTextOnPath.h" +#include "SkTextToPath.h" +#include "SkTSearch.h" + +#define CASE_NEW(_class) \ + case SkType_##_class: result = new Sk##_class(); break +#define CASE_DRAW_NEW(_class) \ + case SkType_##_class: result = new SkDraw##_class(); break +#define CASE_DISPLAY_NEW(_class) \ + case SkType_##_class: result = new SkDisplay##_class(); break +#ifdef SK_DEBUG + #define CASE_DEBUG_RETURN_NIL(_class) \ + case SkType_##_class: return NULL +#else + #define CASE_DEBUG_RETURN_NIL(_class) +#endif + + +SkDisplayTypes SkDisplayType::gNewTypes = kNumberOfTypes; + +SkDisplayable* SkDisplayType::CreateInstance(SkAnimateMaker* maker, SkDisplayTypes type) { + SkDisplayable* result = NULL; + switch (type) { + // unknown + CASE_DISPLAY_NEW(Math); + CASE_DISPLAY_NEW(Number); + CASE_NEW(Add); + CASE_NEW(AddCircle); + // addgeom + CASE_DEBUG_RETURN_NIL(AddMode); + CASE_NEW(AddOval); + CASE_NEW(AddPath); + CASE_NEW(AddRect); + CASE_NEW(AddRoundRect); + CASE_DEBUG_RETURN_NIL(Align); + CASE_NEW(Animate); + // animatebase + CASE_NEW(Apply); + CASE_DEBUG_RETURN_NIL(ApplyMode); + CASE_DEBUG_RETURN_NIL(ApplyTransition); + CASE_DISPLAY_NEW(Array); + // argb + // base64 + // basebitmap + // baseclassinfo + CASE_DRAW_NEW(Bitmap); + // bitmapencoding + // bitmapformat + CASE_DRAW_NEW(BitmapShader); + CASE_DRAW_NEW(Blur); + CASE_DISPLAY_NEW(Boolean); + // boundable + CASE_DISPLAY_NEW(Bounds); + CASE_DEBUG_RETURN_NIL(Cap); + CASE_NEW(Clear); + CASE_DRAW_NEW(Clip); + CASE_NEW(Close); + CASE_DRAW_NEW(Color); + CASE_NEW(CubicTo); + CASE_NEW(Dash); + CASE_NEW(Data); + CASE_NEW(Discrete); + // displayable + // drawable + CASE_NEW(DrawTo); + CASE_NEW(Dump); + // dynamicstring + CASE_DRAW_NEW(Emboss); + CASE_DISPLAY_NEW(Event); + CASE_DEBUG_RETURN_NIL(EventCode); + CASE_DEBUG_RETURN_NIL(EventKind); + CASE_DEBUG_RETURN_NIL(EventMode); + // filltype + // filtertype + CASE_DISPLAY_NEW(Float); + CASE_NEW(FromPath); + CASE_DEBUG_RETURN_NIL(FromPathMode); + CASE_NEW(Full); + // gradient + CASE_NEW(Group); + CASE_NEW(HitClear); + CASE_NEW(HitTest); + CASE_NEW(Image); + CASE_NEW(Include); + CASE_NEW(Input); + CASE_DISPLAY_NEW(Int); + CASE_DEBUG_RETURN_NIL(Join); + CASE_NEW(Line); + CASE_NEW(LineTo); + CASE_NEW(LinearGradient); + CASE_DRAW_NEW(MaskFilter); + CASE_DEBUG_RETURN_NIL(MaskFilterBlurStyle); + // maskfilterlight + CASE_DRAW_NEW(Matrix); + // memberfunction + // memberproperty + CASE_NEW(Move); + CASE_NEW(MoveTo); + CASE_DISPLAY_NEW(Movie); + // msec + CASE_NEW(Oval); + CASE_DRAW_NEW(Paint); + CASE_DRAW_NEW(Path); + // pathdirection + CASE_DRAW_NEW(PathEffect); + // point + CASE_NEW(DrawPoint); + CASE_NEW(PolyToPoly); + CASE_NEW(Polygon); + CASE_NEW(Polyline); + CASE_NEW(Post); + CASE_NEW(QuadTo); + CASE_NEW(RCubicTo); + CASE_NEW(RLineTo); + CASE_NEW(RMoveTo); + CASE_NEW(RQuadTo); + CASE_NEW(RadialGradient); + CASE_DISPLAY_NEW(Random); + CASE_DRAW_NEW(Rect); + CASE_NEW(RectToRect); + CASE_NEW(Remove); + CASE_NEW(Replace); + CASE_NEW(Rotate); + CASE_NEW(RoundRect); + CASE_NEW(Save); + CASE_NEW(SaveLayer); + CASE_NEW(Scale); + // screenplay + CASE_NEW(Set); + CASE_DRAW_NEW(Shader); + CASE_NEW(Skew); + CASE_NEW(3D_Camera); + CASE_NEW(3D_Patch); + // 3dpoint + CASE_NEW(Snapshot); + CASE_DISPLAY_NEW(String); + // style + CASE_NEW(Text); + CASE_DRAW_NEW(TextBox); + // textboxalign + // textboxmode + CASE_NEW(TextOnPath); + CASE_NEW(TextToPath); + CASE_DEBUG_RETURN_NIL(TileMode); + CASE_NEW(Translate); + CASE_DRAW_NEW(TransparentShader); + CASE_DRAW_NEW(Typeface); + CASE_DEBUG_RETURN_NIL(Xfermode); + default: + SkExtras** end = maker->fExtras.end(); + for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) { + if ((result = (*extraPtr)->createInstance(type)) != NULL) + return result; + } + SkASSERT(0); + } + return result; +} + +#undef CASE_NEW +#undef CASE_DRAW_NEW +#undef CASE_DISPLAY_NEW + +#if SK_USE_CONDENSED_INFO == 0 + +#define CASE_GET_INFO(_class) case SkType_##_class: \ + info = Sk##_class::fInfo; infoCount = Sk##_class::fInfoCount; break +#define CASE_GET_DRAW_INFO(_class) case SkType_##_class: \ + info = SkDraw##_class::fInfo; infoCount = SkDraw##_class::fInfoCount; break +#define CASE_GET_DISPLAY_INFO(_class) case SkType_##_class: \ + info = SkDisplay##_class::fInfo; infoCount = SkDisplay##_class::fInfoCount; \ + break + +const SkMemberInfo* SkDisplayType::GetMembers(SkAnimateMaker* maker, + SkDisplayTypes type, int* infoCountPtr) { + const SkMemberInfo* info = NULL; + int infoCount = 0; + switch (type) { + // unknown + CASE_GET_DISPLAY_INFO(Math); + CASE_GET_DISPLAY_INFO(Number); + CASE_GET_INFO(Add); + CASE_GET_INFO(AddCircle); + CASE_GET_INFO(AddGeom); + // addmode + CASE_GET_INFO(AddOval); + CASE_GET_INFO(AddPath); + CASE_GET_INFO(AddRect); + CASE_GET_INFO(AddRoundRect); + // align + CASE_GET_INFO(Animate); + CASE_GET_INFO(AnimateBase); + CASE_GET_INFO(Apply); + // applymode + // applytransition + CASE_GET_DISPLAY_INFO(Array); + // argb + // base64 + CASE_GET_INFO(BaseBitmap); + // baseclassinfo + CASE_GET_DRAW_INFO(Bitmap); + // bitmapencoding + // bitmapformat + CASE_GET_DRAW_INFO(BitmapShader); + CASE_GET_DRAW_INFO(Blur); + CASE_GET_DISPLAY_INFO(Boolean); + // boundable + CASE_GET_DISPLAY_INFO(Bounds); + // cap + // clear + CASE_GET_DRAW_INFO(Clip); + // close + CASE_GET_DRAW_INFO(Color); + CASE_GET_INFO(CubicTo); + CASE_GET_INFO(Dash); + CASE_GET_INFO(Data); + CASE_GET_INFO(Discrete); + // displayable + // drawable + CASE_GET_INFO(DrawTo); + CASE_GET_INFO(Dump); + // dynamicstring + CASE_GET_DRAW_INFO(Emboss); + CASE_GET_DISPLAY_INFO(Event); + // eventcode + // eventkind + // eventmode + // filltype + // filtertype + CASE_GET_DISPLAY_INFO(Float); + CASE_GET_INFO(FromPath); + // frompathmode + // full + CASE_GET_INFO(Gradient); + CASE_GET_INFO(Group); + CASE_GET_INFO(HitClear); + CASE_GET_INFO(HitTest); + CASE_GET_INFO(Image); + CASE_GET_INFO(Include); + CASE_GET_INFO(Input); + CASE_GET_DISPLAY_INFO(Int); + // join + CASE_GET_INFO(Line); + CASE_GET_INFO(LineTo); + CASE_GET_INFO(LinearGradient); + // maskfilter + // maskfilterblurstyle + // maskfilterlight + CASE_GET_DRAW_INFO(Matrix); + // memberfunction + // memberproperty + CASE_GET_INFO(Move); + CASE_GET_INFO(MoveTo); + CASE_GET_DISPLAY_INFO(Movie); + // msec + CASE_GET_INFO(Oval); + CASE_GET_DRAW_INFO(Path); + CASE_GET_DRAW_INFO(Paint); + // pathdirection + // patheffect + case SkType_Point: info = Sk_Point::fInfo; infoCount = Sk_Point::fInfoCount; break; // no virtual flavor + CASE_GET_INFO(DrawPoint); // virtual flavor + CASE_GET_INFO(PolyToPoly); + CASE_GET_INFO(Polygon); + CASE_GET_INFO(Polyline); + CASE_GET_INFO(Post); + CASE_GET_INFO(QuadTo); + CASE_GET_INFO(RCubicTo); + CASE_GET_INFO(RLineTo); + CASE_GET_INFO(RMoveTo); + CASE_GET_INFO(RQuadTo); + CASE_GET_INFO(RadialGradient); + CASE_GET_DISPLAY_INFO(Random); + CASE_GET_DRAW_INFO(Rect); + CASE_GET_INFO(RectToRect); + CASE_GET_INFO(Remove); + CASE_GET_INFO(Replace); + CASE_GET_INFO(Rotate); + CASE_GET_INFO(RoundRect); + CASE_GET_INFO(Save); + CASE_GET_INFO(SaveLayer); + CASE_GET_INFO(Scale); + // screenplay + CASE_GET_INFO(Set); + CASE_GET_DRAW_INFO(Shader); + CASE_GET_INFO(Skew); + CASE_GET_INFO(3D_Camera); + CASE_GET_INFO(3D_Patch); + CASE_GET_INFO(3D_Point); + CASE_GET_INFO(Snapshot); + CASE_GET_DISPLAY_INFO(String); + // style + CASE_GET_INFO(Text); + CASE_GET_DRAW_INFO(TextBox); + // textboxalign + // textboxmode + CASE_GET_INFO(TextOnPath); + CASE_GET_INFO(TextToPath); + // tilemode + CASE_GET_INFO(Translate); + // transparentshader + CASE_GET_DRAW_INFO(Typeface); + // xfermode + // knumberoftypes + default: + if (maker) { + SkExtras** end = maker->fExtras.end(); + for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) { + if ((info = (*extraPtr)->getMembers(type, infoCountPtr)) != NULL) + return info; + } + } + return NULL; + } + if (infoCountPtr) + *infoCountPtr = infoCount; + return info; +} + +const SkMemberInfo* SkDisplayType::GetMember(SkAnimateMaker* maker, + SkDisplayTypes type, const char** matchPtr ) { + int infoCount; + const SkMemberInfo* info = GetMembers(maker, type, &infoCount); + info = SkMemberInfo::Find(info, infoCount, matchPtr); +// SkASSERT(info); + return info; +} + +#undef CASE_GET_INFO +#undef CASE_GET_DRAW_INFO +#undef CASE_GET_DISPLAY_INFO + +#endif // SK_USE_CONDENSED_INFO == 0 + +#if defined SK_DEBUG || defined SK_BUILD_CONDENSED + #define DRAW_NAME(_name, _type) {_name, _type, true, false } + #define DISPLAY_NAME(_name, _type) {_name, _type, false, true } + #define INIT_BOOL_FIELDS , false, false +#else + #define DRAW_NAME(_name, _type) {_name, _type } + #define DISPLAY_NAME(_name, _type) {_name, _type } + #define INIT_BOOL_FIELDS +#endif + +const TypeNames gTypeNames[] = { + // unknown + { "Math", SkType_Math INIT_BOOL_FIELDS }, + { "Number", SkType_Number INIT_BOOL_FIELDS }, + { "add", SkType_Add INIT_BOOL_FIELDS }, + { "addCircle", SkType_AddCircle INIT_BOOL_FIELDS }, + // addgeom + // addmode + { "addOval", SkType_AddOval INIT_BOOL_FIELDS }, + { "addPath", SkType_AddPath INIT_BOOL_FIELDS }, + { "addRect", SkType_AddRect INIT_BOOL_FIELDS }, + { "addRoundRect", SkType_AddRoundRect INIT_BOOL_FIELDS }, + // align + { "animate", SkType_Animate INIT_BOOL_FIELDS }, + // animateBase + { "apply", SkType_Apply INIT_BOOL_FIELDS }, + // applymode + // applytransition + { "array", SkType_Array INIT_BOOL_FIELDS }, + // argb + // base64 + // basebitmap + // baseclassinfo + DRAW_NAME("bitmap", SkType_Bitmap), + // bitmapencoding + // bitmapformat + DRAW_NAME("bitmapShader", SkType_BitmapShader), + DRAW_NAME("blur", SkType_Blur), + { "boolean", SkType_Boolean INIT_BOOL_FIELDS }, + // boundable + DISPLAY_NAME("bounds", SkType_Bounds), + // cap + { "clear", SkType_Clear INIT_BOOL_FIELDS }, + DRAW_NAME("clip", SkType_Clip), + { "close", SkType_Close INIT_BOOL_FIELDS }, + DRAW_NAME("color", SkType_Color), + { "cubicTo", SkType_CubicTo INIT_BOOL_FIELDS }, + { "dash", SkType_Dash INIT_BOOL_FIELDS }, + { "data", SkType_Data INIT_BOOL_FIELDS }, + { "discrete", SkType_Discrete INIT_BOOL_FIELDS }, + // displayable + // drawable + { "drawTo", SkType_DrawTo INIT_BOOL_FIELDS }, + { "dump", SkType_Dump INIT_BOOL_FIELDS }, + // dynamicstring + DRAW_NAME("emboss", SkType_Emboss), + DISPLAY_NAME("event", SkType_Event), + // eventcode + // eventkind + // eventmode + // filltype + // filtertype + { "float", SkType_Float INIT_BOOL_FIELDS }, + { "fromPath", SkType_FromPath INIT_BOOL_FIELDS }, + // frompathmode + { "full", SkType_Full INIT_BOOL_FIELDS }, + // gradient + { "group", SkType_Group INIT_BOOL_FIELDS }, + { "hitClear", SkType_HitClear INIT_BOOL_FIELDS }, + { "hitTest", SkType_HitTest INIT_BOOL_FIELDS }, + { "image", SkType_Image INIT_BOOL_FIELDS }, + { "include", SkType_Include INIT_BOOL_FIELDS }, + { "input", SkType_Input INIT_BOOL_FIELDS }, + { "int", SkType_Int INIT_BOOL_FIELDS }, + // join + { "line", SkType_Line INIT_BOOL_FIELDS }, + { "lineTo", SkType_LineTo INIT_BOOL_FIELDS }, + { "linearGradient", SkType_LinearGradient INIT_BOOL_FIELDS }, + { "maskFilter", SkType_MaskFilter INIT_BOOL_FIELDS }, + // maskfilterblurstyle + // maskfilterlight + DRAW_NAME("matrix", SkType_Matrix), + // memberfunction + // memberproperty + { "move", SkType_Move INIT_BOOL_FIELDS }, + { "moveTo", SkType_MoveTo INIT_BOOL_FIELDS }, + { "movie", SkType_Movie INIT_BOOL_FIELDS }, + // msec + { "oval", SkType_Oval INIT_BOOL_FIELDS }, + DRAW_NAME("paint", SkType_Paint), + DRAW_NAME("path", SkType_Path), + // pathdirection + { "pathEffect", SkType_PathEffect INIT_BOOL_FIELDS }, + // point + DRAW_NAME("point", SkType_DrawPoint), + { "polyToPoly", SkType_PolyToPoly INIT_BOOL_FIELDS }, + { "polygon", SkType_Polygon INIT_BOOL_FIELDS }, + { "polyline", SkType_Polyline INIT_BOOL_FIELDS }, + { "post", SkType_Post INIT_BOOL_FIELDS }, + { "quadTo", SkType_QuadTo INIT_BOOL_FIELDS }, + { "rCubicTo", SkType_RCubicTo INIT_BOOL_FIELDS }, + { "rLineTo", SkType_RLineTo INIT_BOOL_FIELDS }, + { "rMoveTo", SkType_RMoveTo INIT_BOOL_FIELDS }, + { "rQuadTo", SkType_RQuadTo INIT_BOOL_FIELDS }, + { "radialGradient", SkType_RadialGradient INIT_BOOL_FIELDS }, + DISPLAY_NAME("random", SkType_Random), + { "rect", SkType_Rect INIT_BOOL_FIELDS }, + { "rectToRect", SkType_RectToRect INIT_BOOL_FIELDS }, + { "remove", SkType_Remove INIT_BOOL_FIELDS }, + { "replace", SkType_Replace INIT_BOOL_FIELDS }, + { "rotate", SkType_Rotate INIT_BOOL_FIELDS }, + { "roundRect", SkType_RoundRect INIT_BOOL_FIELDS }, + { "save", SkType_Save INIT_BOOL_FIELDS }, + { "saveLayer", SkType_SaveLayer INIT_BOOL_FIELDS }, + { "scale", SkType_Scale INIT_BOOL_FIELDS }, + // screenplay + { "set", SkType_Set INIT_BOOL_FIELDS }, + { "shader", SkType_Shader INIT_BOOL_FIELDS }, + { "skew", SkType_Skew INIT_BOOL_FIELDS }, + { "skia3d:camera", SkType_3D_Camera INIT_BOOL_FIELDS }, + { "skia3d:patch", SkType_3D_Patch INIT_BOOL_FIELDS }, + // point + { "snapshot", SkType_Snapshot INIT_BOOL_FIELDS }, + { "string", SkType_String INIT_BOOL_FIELDS }, + // style + { "text", SkType_Text INIT_BOOL_FIELDS }, + { "textBox", SkType_TextBox INIT_BOOL_FIELDS }, + // textboxalign + // textboxmode + { "textOnPath", SkType_TextOnPath INIT_BOOL_FIELDS }, + { "textToPath", SkType_TextToPath INIT_BOOL_FIELDS }, + // tilemode + { "translate", SkType_Translate INIT_BOOL_FIELDS }, + DRAW_NAME("transparentShader", SkType_TransparentShader), + { "typeface", SkType_Typeface INIT_BOOL_FIELDS } + // xfermode + // knumberoftypes +}; + +const int kTypeNamesSize = SK_ARRAY_COUNT(gTypeNames); + +SkDisplayTypes SkDisplayType::Find(SkAnimateMaker* maker, const SkMemberInfo* match) { + for (int index = 0; index < kTypeNamesSize; index++) { + SkDisplayTypes type = gTypeNames[index].fType; + const SkMemberInfo* info = SkDisplayType::GetMembers(maker, type, NULL); + if (info == match) + return type; + } + return (SkDisplayTypes) -1; +} + +// !!! optimize this by replacing function with a byte-sized lookup table +SkDisplayTypes SkDisplayType::GetParent(SkAnimateMaker* maker, SkDisplayTypes base) { + if (base == SkType_Group || base == SkType_Save || base == SkType_SaveLayer) //!!! cheat a little until we have a lookup table + return SkType_Displayable; + if (base == SkType_Set) + return SkType_Animate; // another cheat until we have a lookup table + const SkMemberInfo* info = GetMembers(maker, base, NULL); // get info for this type + SkASSERT(info); + if (info->fType != SkType_BaseClassInfo) + return SkType_Unknown; // if no base, done + // !!! could change SK_MEMBER_INHERITED macro to take type, stuff in offset, so that + // this (and table builder) could know type without the following steps: + const SkMemberInfo* inherited = info->getInherited(); + SkDisplayTypes result = (SkDisplayTypes) (SkType_Unknown + 1); + for (; result <= SkType_Xfermode; result = (SkDisplayTypes) (result + 1)) { + const SkMemberInfo* match = GetMembers(maker, result, NULL); + if (match == inherited) + break; + } + SkASSERT(result <= SkType_Xfermode); + return result; +} + +SkDisplayTypes SkDisplayType::GetType(SkAnimateMaker* maker, const char match[], size_t len ) { + int index = SkStrSearch(&gTypeNames[0].fName, kTypeNamesSize, match, + len, sizeof(gTypeNames[0])); + if (index >= 0 && index < kTypeNamesSize) + return gTypeNames[index].fType; + SkExtras** end = maker->fExtras.end(); + for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) { + SkDisplayTypes result = (*extraPtr)->getType(match, len); + if (result != SkType_Unknown) + return result; + } + return (SkDisplayTypes) -1; +} + +bool SkDisplayType::IsEnum(SkAnimateMaker* , SkDisplayTypes type) { + switch (type) { + case SkType_AddMode: + case SkType_Align: + case SkType_ApplyMode: + case SkType_ApplyTransition: + case SkType_BitmapEncoding: + case SkType_BitmapFormat: + case SkType_Boolean: + case SkType_Cap: + case SkType_EventCode: + case SkType_EventKind: + case SkType_EventMode: + case SkType_FillType: + case SkType_FilterType: + case SkType_FontStyle: + case SkType_FromPathMode: + case SkType_Join: + case SkType_MaskFilterBlurStyle: + case SkType_PathDirection: + case SkType_Style: + case SkType_TextBoxAlign: + case SkType_TextBoxMode: + case SkType_TileMode: + case SkType_Xfermode: + return true; + default: // to avoid warnings + break; + } + return false; +} + +bool SkDisplayType::IsDisplayable(SkAnimateMaker* , SkDisplayTypes type) { + switch (type) { + case SkType_Add: + case SkType_AddCircle: + case SkType_AddOval: + case SkType_AddPath: + case SkType_AddRect: + case SkType_AddRoundRect: + case SkType_Animate: + case SkType_AnimateBase: + case SkType_Apply: + case SkType_BaseBitmap: + case SkType_Bitmap: + case SkType_BitmapShader: + case SkType_Blur: + case SkType_Clear: + case SkType_Clip: + case SkType_Close: + case SkType_Color: + case SkType_CubicTo: + case SkType_Dash: + case SkType_Data: + case SkType_Discrete: + case SkType_Displayable: + case SkType_Drawable: + case SkType_DrawTo: + case SkType_Emboss: + case SkType_Event: + case SkType_FromPath: + case SkType_Full: + case SkType_Group: + case SkType_Image: + case SkType_Input: + case SkType_Line: + case SkType_LineTo: + case SkType_LinearGradient: + case SkType_Matrix: + case SkType_Move: + case SkType_MoveTo: + case SkType_Movie: + case SkType_Oval: + case SkType_Paint: + case SkType_Path: + case SkType_PolyToPoly: + case SkType_Polygon: + case SkType_Polyline: + case SkType_Post: + case SkType_QuadTo: + case SkType_RCubicTo: + case SkType_RLineTo: + case SkType_RMoveTo: + case SkType_RQuadTo: + case SkType_RadialGradient: + case SkType_Random: + case SkType_Rect: + case SkType_RectToRect: + case SkType_Remove: + case SkType_Replace: + case SkType_Rotate: + case SkType_RoundRect: + case SkType_Save: + case SkType_SaveLayer: + case SkType_Scale: + case SkType_Set: + case SkType_Shader: + case SkType_Skew: + case SkType_3D_Camera: + case SkType_3D_Patch: + case SkType_Snapshot: + case SkType_Text: + case SkType_TextBox: + case SkType_TextOnPath: + case SkType_TextToPath: + case SkType_Translate: + case SkType_TransparentShader: + return true; + default: // to avoid warnings + break; + } + return false; +} + +bool SkDisplayType::IsStruct(SkAnimateMaker* , SkDisplayTypes type) { + switch (type) { + case SkType_Point: + case SkType_3D_Point: + return true; + default: // to avoid warnings + break; + } + return false; +} + + +SkDisplayTypes SkDisplayType::RegisterNewType() { + gNewTypes = (SkDisplayTypes) (gNewTypes + 1); + return gNewTypes; +} + + + +#ifdef SK_DEBUG +const char* SkDisplayType::GetName(SkAnimateMaker* maker, SkDisplayTypes type) { + for (int index = 0; index < kTypeNamesSize - 1; index++) { + if (gTypeNames[index].fType == type) + return gTypeNames[index].fName; + } + SkExtras** end = maker->fExtras.end(); + for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) { + const char* result = (*extraPtr)->getName(type); + if (result != NULL) + return result; + } + return NULL; +} +#endif + +#ifdef SK_SUPPORT_UNITTEST +void SkDisplayType::UnitTest() { + SkAnimator animator; + SkAnimateMaker* maker = animator.fMaker; + int index; + for (index = 0; index < kTypeNamesSize - 1; index++) { + SkASSERT(strcmp(gTypeNames[index].fName, gTypeNames[index + 1].fName) < 0); + SkASSERT(gTypeNames[index].fType < gTypeNames[index + 1].fType); + } + for (index = 0; index < kTypeNamesSize; index++) { + SkDisplayable* test = CreateInstance(maker, gTypeNames[index].fType); + if (test == NULL) + continue; +#if defined _WIN32 && _MSC_VER >= 1300 && defined _INC_CRTDBG // only on windows, only if using "crtdbg.h" + // we know that crtdbg puts 0xfdfdfdfd at the end of the block + // look for unitialized memory, signature 0xcdcdcdcd prior to that + int* start = (int*) test; + while (*start != 0xfdfdfdfd) { + SkASSERT(*start != 0xcdcdcdcd); + start++; + } +#endif + delete test; + } + for (index = 0; index < kTypeNamesSize; index++) { + int infoCount; + const SkMemberInfo* info = GetMembers(maker, gTypeNames[index].fType, &infoCount); + if (info == NULL) + continue; +#if SK_USE_CONDENSED_INFO == 0 + for (int inner = 0; inner < infoCount - 1; inner++) { + if (info[inner].fType == SkType_BaseClassInfo) + continue; + SkASSERT(strcmp(info[inner].fName, info[inner + 1].fName) < 0); + } +#endif + } +#if defined SK_DEBUG || defined SK_BUILD_CONDENSED + BuildCondensedInfo(maker); +#endif +} +#endif diff --git a/libs/graphics/animator/SkDisplayType.h b/libs/graphics/animator/SkDisplayType.h new file mode 100644 index 0000000000..d6c4a931e2 --- /dev/null +++ b/libs/graphics/animator/SkDisplayType.h @@ -0,0 +1,198 @@ +#ifndef SkDisplayType_DEFINED +#define SkDisplayType_DEFINED + +#include "SkMath.h" + +#ifdef SK_DEBUG + #ifdef SK_CAN_USE_FLOAT + #define SK_DUMP_ENABLED + #endif + #ifdef SK_BUILD_FOR_MAC + #define SK_FIND_LEAKS + #endif +#endif + +#define SK_LITERAL_STR_EQUAL(str, token, len) (sizeof(str) - 1 == len \ + && strncmp(str, token, sizeof(str) - 1) == 0) + +class SkAnimateMaker; +class SkDisplayable; +struct SkMemberInfo; + +enum SkDisplayTypes { + SkType_Unknown, + SkType_Math, // for ecmascript compatible Math functions and constants + SkType_Number, // for for ecmascript compatible Number functions and constants + SkType_Add, + SkType_AddCircle, + SkType_AddGeom, + SkType_AddMode, + SkType_AddOval, + SkType_AddPath, + SkType_AddRect, // path part + SkType_AddRoundRect, + SkType_Align, + SkType_Animate, + SkType_AnimateBase, // base type for animate, set + SkType_Apply, + SkType_ApplyMode, + SkType_ApplyTransition, + SkType_Array, + SkType_ARGB, + SkType_Base64, + SkType_BaseBitmap, + SkType_BaseClassInfo, + SkType_Bitmap, + SkType_BitmapEncoding, + SkType_BitmapFormat, + SkType_BitmapShader, + SkType_Blur, + SkType_Boolean, // can have values -1 (uninitialized), 0, 1 + SkType_Boundable, + SkType_Bounds, + SkType_Cap, + SkType_Clear, + SkType_Clip, + SkType_Close, + SkType_Color, + SkType_CubicTo, + SkType_Dash, + SkType_Data, + SkType_Discrete, + SkType_Displayable, + SkType_Drawable, + SkType_DrawTo, + SkType_Dump, + SkType_DynamicString, // evaluate at draw time + SkType_Emboss, + SkType_Event, + SkType_EventCode, + SkType_EventKind, + SkType_EventMode, + SkType_FillType, + SkType_FilterType, + SkType_Float, + SkType_FontStyle, + SkType_FromPath, + SkType_FromPathMode, + SkType_Full, + SkType_Gradient, + SkType_Group, + SkType_HitClear, + SkType_HitTest, + SkType_Image, + SkType_Include, + SkType_Input, + SkType_Int, + SkType_Join, + SkType_Line, // simple line primitive + SkType_LineTo, // used as part of path construction + SkType_LinearGradient, + SkType_MaskFilter, + SkType_MaskFilterBlurStyle, + SkType_MaskFilterLight, + SkType_Matrix, + SkType_MemberFunction, + SkType_MemberProperty, + SkType_Move, + SkType_MoveTo, + SkType_Movie, + SkType_MSec, + SkType_Oval, + SkType_Paint, + SkType_Path, + SkType_PathDirection, + SkType_PathEffect, + SkType_Point, // used inside other structures, no vtable + SkType_DrawPoint, // used to draw points, has a vtable + SkType_PolyToPoly, + SkType_Polygon, + SkType_Polyline, + SkType_Post, + SkType_QuadTo, + SkType_RCubicTo, + SkType_RLineTo, + SkType_RMoveTo, + SkType_RQuadTo, + SkType_RadialGradient, + SkType_Random, + SkType_Rect, + SkType_RectToRect, + SkType_Remove, + SkType_Replace, + SkType_Rotate, + SkType_RoundRect, + SkType_Save, + SkType_SaveLayer, + SkType_Scale, + SkType_Screenplay, + SkType_Set, + SkType_Shader, + SkType_Skew, + SkType_3D_Camera, + SkType_3D_Patch, + SkType_3D_Point, + SkType_Snapshot, + SkType_String, // pointer to SkString + SkType_Style, + SkType_Text, + SkType_TextBox, + SkType_TextBoxAlign, + SkType_TextBoxMode, + SkType_TextOnPath, + SkType_TextToPath, + SkType_TileMode, + SkType_Translate, + SkType_TransparentShader, + SkType_Typeface, + SkType_Xfermode, + kNumberOfTypes +}; + +struct TypeNames { + const char* fName; + SkDisplayTypes fType; +#if defined SK_DEBUG || defined SK_BUILD_CONDENSED + bool fDrawPrefix; + bool fDisplayPrefix; +#endif +}; + +#ifdef SK_DEBUG +typedef SkDisplayTypes SkFunctionParamType; +#else +typedef unsigned char SkFunctionParamType; +#endif + +extern const TypeNames gTypeNames[]; +extern const int kTypeNamesSize; + +class SkDisplayType { +public: + static SkDisplayTypes Find(SkAnimateMaker* , const SkMemberInfo* ); + static const SkMemberInfo* GetMember(SkAnimateMaker* , SkDisplayTypes , const char** ); + static const SkMemberInfo* GetMembers(SkAnimateMaker* , SkDisplayTypes , int* infoCountPtr); + static SkDisplayTypes GetParent(SkAnimateMaker* , SkDisplayTypes ); + static bool IsDisplayable(SkAnimateMaker* , SkDisplayTypes ); + static bool IsEnum(SkAnimateMaker* , SkDisplayTypes ); + static bool IsStruct(SkAnimateMaker* , SkDisplayTypes ); + static SkDisplayTypes RegisterNewType(); + static SkDisplayTypes Resolve(const char[] , const SkMemberInfo** ); +#ifdef SK_DEBUG + static bool IsAnimate(SkDisplayTypes type ) { return type == SkType_Animate || + type == SkType_Set; } + static const char* GetName(SkAnimateMaker* , SkDisplayTypes ); +#endif +#ifdef SK_SUPPORT_UNITTEST + static void UnitTest(); +#endif +#if defined SK_DEBUG || defined SK_BUILD_CONDENSED + static void BuildCondensedInfo(SkAnimateMaker* ); +#endif + static SkDisplayTypes GetType(SkAnimateMaker* , const char[] , size_t len); + static SkDisplayable* CreateInstance(SkAnimateMaker* , SkDisplayTypes ); +private: + static SkDisplayTypes gNewTypes; +}; + +#endif // SkDisplayType_DEFINED diff --git a/libs/graphics/animator/SkDisplayTypes.cpp b/libs/graphics/animator/SkDisplayTypes.cpp new file mode 100644 index 0000000000..b38a04cc29 --- /dev/null +++ b/libs/graphics/animator/SkDisplayTypes.cpp @@ -0,0 +1,212 @@ +#include "SkDisplayTypes.h" +#include "SkAnimateBase.h" + +bool SkDisplayDepend::canContainDependents() const { + return true; +} + +void SkDisplayDepend::dirty() { + SkDisplayable** last = fDependents.end(); + for (SkDisplayable** depPtr = fDependents.begin(); depPtr < last; depPtr++) { + SkAnimateBase* animate = (SkAnimateBase* ) *depPtr; + animate->setChanged(true); + } +} + +// Boolean +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayBoolean::fInfo[] = { + SK_MEMBER(value, Boolean) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayBoolean); + +SkDisplayBoolean::SkDisplayBoolean() : value(false) { +} + +#ifdef SK_DUMP_ENABLED +void SkDisplayBoolean::dump(SkAnimateMaker* maker){ + dumpBase(maker); + SkDebugf("value=\"%s\" />\n", value ? "true" : "false"); +} +#endif + +// S32 +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayInt::fInfo[] = { + SK_MEMBER(value, Int) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayInt); + +SkDisplayInt::SkDisplayInt() : value(0) { +} + +#ifdef SK_DUMP_ENABLED +void SkDisplayInt::dump(SkAnimateMaker* maker){ + dumpBase(maker); + SkDebugf("value=\"%d\" />\n", value); +} +#endif + +// SkScalar +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayFloat::fInfo[] = { + SK_MEMBER(value, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayFloat); + +SkDisplayFloat::SkDisplayFloat() : value(0) { +} + +#ifdef SK_DUMP_ENABLED +void SkDisplayFloat::dump(SkAnimateMaker* maker) { + dumpBase(maker); +#ifdef SK_CAN_USE_FLOAT + SkDebugf("value=\"%g\" />\n", SkScalarToFloat(value)); +#else + SkDebugf("value=\"%x\" />\n", value); +#endif +} +#endif + +// SkString +enum SkDisplayString_Functions { + SK_FUNCTION(slice) +}; + +enum SkDisplayString_Properties { + SK_PROPERTY(length) +}; + +const SkFunctionParamType SkDisplayString::fFunctionParameters[] = { + (SkFunctionParamType) SkType_Int, // slice + (SkFunctionParamType) SkType_Int, + (SkFunctionParamType) 0 +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayString::fInfo[] = { + SK_MEMBER_PROPERTY(length, Int), + SK_MEMBER_FUNCTION(slice, String), + SK_MEMBER(value, String) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayString); + +SkDisplayString::SkDisplayString() { +} + +SkDisplayString::SkDisplayString(SkString& copyFrom) : value(copyFrom) { +} + +void SkDisplayString::executeFunction(SkDisplayable* target, int index, + SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, + SkScriptValue* scriptValue) { + if (scriptValue == nil) + return; + SkASSERT(target == this); + switch (index) { + case SK_FUNCTION(slice): + scriptValue->fType = SkType_String; + SkASSERT(parameters[0].fType == SkType_Int); + int start = parameters[0].fOperand.fS32; + if (start < 0) + start = (int) (value.size() - start); + int end = (int) value.size(); + if (parameters.count() > 1) { + SkASSERT(parameters[1].fType == SkType_Int); + end = parameters[1].fOperand.fS32; + } + //if (end >= 0 && end < (int) value.size()) + if (end >= 0 && end <= (int) value.size()) + scriptValue->fOperand.fString = new SkString(&value.c_str()[start], end - start); + else + scriptValue->fOperand.fString = new SkString(value); + break; + } +} + +const SkFunctionParamType* SkDisplayString::getFunctionsParameters() { + return fFunctionParameters; +} + +bool SkDisplayString::getProperty(int index, SkScriptValue* scriptValue) const { + switch (index) { + case SK_PROPERTY(length): + scriptValue->fType = SkType_Int; + scriptValue->fOperand.fS32 = (S32) value.size(); + break; + default: + SkASSERT(0); + return false; + } + return true; +} + + +// SkArray +#if 0 // !!! reason enough to qualify enum with class name or move typedArray into its own file +enum SkDisplayArray_Properties { + SK_PROPERTY(length) +}; +#endif + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDisplayArray::fInfo[] = { + SK_MEMBER_PROPERTY(length, Int), + SK_MEMBER_ARRAY(values, Unknown) +}; + +#endif + +DEFINE_GET_MEMBER(SkDisplayArray); + +SkDisplayArray::SkDisplayArray() { +} + +SkDisplayArray::SkDisplayArray(SkTypedArray& copyFrom) : values(copyFrom) { + +} + +SkDisplayArray::~SkDisplayArray() { + if (values.getType() == SkType_String) { + for (int index = 0; index < values.count(); index++) + delete values[index].fString; + return; + } + if (values.getType() == SkType_Array) { + for (int index = 0; index < values.count(); index++) + delete values[index].fArray; + } +} + +bool SkDisplayArray::getProperty(int index, SkScriptValue* value) const { + switch (index) { + case SK_PROPERTY(length): + value->fType = SkType_Int; + value->fOperand.fS32 = values.count(); + break; + default: + SkASSERT(0); + return false; + } + return true; +} + + + diff --git a/libs/graphics/animator/SkDisplayTypes.h b/libs/graphics/animator/SkDisplayTypes.h new file mode 100644 index 0000000000..ce654ab081 --- /dev/null +++ b/libs/graphics/animator/SkDisplayTypes.h @@ -0,0 +1,98 @@ +#ifndef SkDisplayTypes_DEFINED +#define SkDisplayTypes_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" +#include "SkTypedArray.h" + +class SkOpArray; // compiled script experiment + + +class SkDisplayDepend : public SkDisplayable { +public: + virtual bool canContainDependents() const; + void addDependent(SkDisplayable* displayable) { + if (fDependents.find(displayable) < 0) + *fDependents.append() = displayable; + } + virtual void dirty(); +private: + SkTDDisplayableArray fDependents; + typedef SkDisplayable INHERITED; +}; + +class SkDisplayBoolean : public SkDisplayDepend { + DECLARE_DISPLAY_MEMBER_INFO(Boolean); + SkDisplayBoolean(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + SkBool value; + friend class SkAnimatorScript; + friend class SkAnimatorScript_Box; + friend class SkAnimatorScript_Unbox; + typedef SkDisplayDepend INHERITED; +}; + +class SkDisplayInt : public SkDisplayDepend { + DECLARE_DISPLAY_MEMBER_INFO(Int); + SkDisplayInt(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif +private: + S32 value; + friend class SkAnimatorScript; + friend class SkAnimatorScript_Box; + friend class SkAnimatorScript_Unbox; + typedef SkDisplayDepend INHERITED; +}; + +class SkDisplayFloat : public SkDisplayDepend { + DECLARE_DISPLAY_MEMBER_INFO(Float); + SkDisplayFloat(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif +private: + SkScalar value; + friend class SkAnimatorScript; + friend class SkAnimatorScript_Box; + friend class SkAnimatorScript_Unbox; + typedef SkDisplayDepend INHERITED; +}; + +class SkDisplayString : public SkDisplayDepend { + DECLARE_DISPLAY_MEMBER_INFO(String); + SkDisplayString(); + SkDisplayString(SkString& ); + virtual void executeFunction(SkDisplayable* , int index, + SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, + SkScriptValue* ); + virtual const SkFunctionParamType* getFunctionsParameters(); + virtual bool getProperty(int index, SkScriptValue* ) const; + SkString value; +private: + static const SkFunctionParamType fFunctionParameters[]; +}; + +class SkDisplayArray : public SkDisplayDepend { + DECLARE_DISPLAY_MEMBER_INFO(Array); + SkDisplayArray(); + SkDisplayArray(SkTypedArray& ); + SkDisplayArray(SkOpArray& ); // compiled script experiment + virtual ~SkDisplayArray(); + virtual bool getProperty(int index, SkScriptValue* ) const; +private: + SkTypedArray values; + friend class SkAnimator; + friend class SkAnimatorScript; + friend class SkAnimatorScript2; + friend class SkAnimatorScript_Unbox; + friend class SkDisplayable; + friend struct SkMemberInfo; + friend class SkScriptEngine; +}; + +#endif // SkDisplayTypes_DEFINED + diff --git a/libs/graphics/animator/SkDisplayXMLParser.cpp b/libs/graphics/animator/SkDisplayXMLParser.cpp new file mode 100644 index 0000000000..fd4840a085 --- /dev/null +++ b/libs/graphics/animator/SkDisplayXMLParser.cpp @@ -0,0 +1,301 @@ +#include "SkDisplayXMLParser.h" +#include "SkAnimateMaker.h" +#include "SkDisplayApply.h" +#include "SkUtils.h" +#ifdef SK_DEBUG +#include "SkTime.h" +#endif + +static char const* const gErrorStrings[] = { + "unknown error ", + "apply scopes itself", + "display tree too deep (circular reference?) ", + "element missing parent ", + "element type not allowed in parent ", + "error adding <data> to <post> ", + "error adding to <matrix> ", + "error adding to <paint> ", + "error adding to <path> ", + "error in attribute value ", + "error in script ", + "expected movie in sink attribute ", + "field not in target ", + "number of offsets in gradient must match number of colors", + "no offset in gradient may be greater than one", + "last offset in gradient must be one", + "offsets in gradient must be increasing", + "first offset in gradient must be zero", + "gradient attribute \"points\" must have length of four", + "in include ", + "in movie ", + "include name unknown or missing ", + "index out of range ", + "movie name unknown or missing ", + "no parent available to resolve sink attribute ", + "parent element can't contain ", + "saveLayer must specify a bounds", + "target id not found ", + "unexpected type " +}; + +SkDisplayXMLParserError::~SkDisplayXMLParserError() { +} + +void SkDisplayXMLParserError::getErrorString(SkString* str) const { + if (fCode > kUnknownError) + str->set(gErrorStrings[fCode - kUnknownError]); + else + str->reset(); + INHERITED::getErrorString(str); +} + +void SkDisplayXMLParserError::setInnerError(SkAnimateMaker* parent, const SkString& src) { + SkString inner; + getErrorString(&inner); + inner.prepend(": "); + inner.prependS32(getLineNumber()); + inner.prepend(", line "); + inner.prepend(src); + parent->setErrorNoun(inner); +} + + +SkDisplayXMLParser::SkDisplayXMLParser(SkAnimateMaker& maker) + : INHERITED(&maker.fError), fMaker(maker), fInInclude(maker.fInInclude), + fInSkia(maker.fInInclude), fCurrDisplayable(nil) +{ +} + +SkDisplayXMLParser::~SkDisplayXMLParser() { + if (fCurrDisplayable && fMaker.fChildren.find(fCurrDisplayable) < 0) + delete fCurrDisplayable; + for (Parent* parPtr = fParents.begin() + 1; parPtr < fParents.end(); parPtr++) { + SkDisplayable* displayable = parPtr->fDisplayable; + if (displayable == fCurrDisplayable) + continue; + SkASSERT(fMaker.fChildren.find(displayable) < 0); + if (fMaker.fHelpers.find(displayable) < 0) + delete displayable; + } +} + + + +bool SkDisplayXMLParser::onAddAttribute(const char name[], const char value[]) { + return onAddAttributeLen(name, value, strlen(value)); +} + +bool SkDisplayXMLParser::onAddAttributeLen(const char attrName[], const char attrValue[], + size_t attrValueLen) +{ + if (fCurrDisplayable == nil) // this signals we should ignore attributes for this element + return strncmp(attrName, "xmlns", sizeof("xmlns") - 1) != 0; + SkDisplayable* displayable = fCurrDisplayable; + SkDisplayTypes type = fCurrType; + + if (strcmp(attrName, "id") == 0) { + if (fMaker.find(attrValue, attrValueLen, nil)) { + fError->setNoun(attrValue, attrValueLen); + fError->setCode(SkXMLParserError::kDuplicateIDs); + return true; + } +#ifdef SK_DEBUG + displayable->_id.set(attrValue, attrValueLen); + displayable->id = displayable->_id.c_str(); +#endif + fMaker.idsSet(attrValue, attrValueLen, displayable); + int parentIndex = fParents.count() - 1; + if (parentIndex > 0) { + SkDisplayable* parent = fParents[parentIndex - 1].fDisplayable; + parent->setChildHasID(); + } + return false; + } + const char* name = attrName; + const SkMemberInfo* info = SkDisplayType::GetMember(&fMaker, type, &name); + if (info == nil) { + fError->setNoun(name); + fError->setCode(SkXMLParserError::kUnknownAttributeName); + return true; + } + if (info->setValue(fMaker, nil, 0, info->getCount(), displayable, info->getType(), attrValue, + attrValueLen)) + return false; + if (fMaker.fError.hasError()) { + fError->setNoun(attrValue, attrValueLen); + return true; + } + SkDisplayable* ref = nil; + if (fMaker.find(attrValue, attrValueLen, &ref) == false) { + ref = fMaker.createInstance(attrValue, attrValueLen); + if (ref == nil) { + fError->setNoun(attrValue, attrValueLen); + fError->setCode(SkXMLParserError::kErrorInAttributeValue); + return true; + } else + fMaker.helperAdd(ref); + } + if (info->fType != SkType_MemberProperty) { + fError->setNoun(name); + fError->setCode(SkXMLParserError::kUnknownAttributeName); + return true; + } + SkScriptValue scriptValue; + scriptValue.fOperand.fDisplayable = ref; + scriptValue.fType = ref->getType(); + displayable->setProperty(info->propertyIndex(), scriptValue); + return false; +} + +bool SkDisplayXMLParser::onEndElement(const char elem[]) +{ + int parentIndex = fParents.count() - 1; + if (parentIndex >= 0) { + Parent& container = fParents[parentIndex]; + SkDisplayable* displayable = container.fDisplayable; + fMaker.fEndDepth = parentIndex; + displayable->onEndElement(fMaker); + if (fMaker.fError.hasError()) + return true; + if (parentIndex > 0) { + SkDisplayable* parent = fParents[parentIndex - 1].fDisplayable; + bool result = parent->add(fMaker, displayable); + if (fMaker.hasError()) + return true; + if (result == false) { + int infoCount; + const SkMemberInfo* info = + SkDisplayType::GetMembers(&fMaker, fParents[parentIndex - 1].fType, &infoCount); + const SkMemberInfo* foundInfo; + if ((foundInfo = searchContainer(info, infoCount)) != nil) { + parent->setReference(foundInfo, displayable); + // if (displayable->isHelper() == false) + fMaker.helperAdd(displayable); + } else { + fMaker.setErrorCode(SkDisplayXMLParserError::kElementTypeNotAllowedInParent); + return true; + } + } + if (parent->childrenNeedDisposing()) + delete displayable; + } + fParents.remove(parentIndex); + } + fCurrDisplayable = nil; + if (fInInclude == false && strcasecmp(elem, "screenplay") == 0) { + if (fMaker.fInMovie == false) { + fMaker.fEnableTime = fMaker.getAppTime(); +#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING + if (fMaker.fDebugTimeBase == (SkMSec) -1) + fMaker.fDebugTimeBase = fMaker.fEnableTime; + SkString debugOut; + SkMSec time = fMaker.getAppTime(); + debugOut.appendS32(time - fMaker.fDebugTimeBase); + debugOut.append(" onLoad enable="); + debugOut.appendS32(fMaker.fEnableTime - fMaker.fDebugTimeBase); + SkDebugf("%s\n", debugOut.c_str()); +#endif + fMaker.fEvents.doEvent(fMaker, SkDisplayEvent::kOnload, nil); + if (fMaker.fError.hasError()) + return true; + fMaker.fEvents.removeEvent(SkDisplayEvent::kOnload, nil); + + } + fInSkia = false; + } + return false; +} + +bool SkDisplayXMLParser::onStartElement(const char name[]) +{ + return onStartElementLen(name, strlen(name)); +} + +bool SkDisplayXMLParser::onStartElementLen(const char name[], size_t len) { + fCurrDisplayable = nil; // init so we'll ignore attributes if we exit early + + if (strncasecmp(name, "screenplay", len) == 0) { + fInSkia = true; + if (fInInclude == false) + fMaker.idsSet(name, len, &fMaker.fScreenplay); + return false; + } + if (fInSkia == false) + return false; + + SkDisplayable* displayable = fMaker.createInstance(name, len); + if (displayable == nil) { + fError->setNoun(name, len); + fError->setCode(SkXMLParserError::kUnknownElement); + return true; + } + SkDisplayTypes type = displayable->getType(); + Parent record = { displayable, type }; + *fParents.append() = record; + if (fParents.count() == 1) + fMaker.childrenAdd(displayable); + else { + Parent* parent = fParents.end() - 2; + if (displayable->setParent(parent->fDisplayable)) { + fError->setNoun(name, len); + getError()->setCode(SkDisplayXMLParserError::kParentElementCantContain); + return true; + } + } + + // set these for subsequent calls to addAttribute() + fCurrDisplayable = displayable; + fCurrType = type; + return false; +} + +const SkMemberInfo* SkDisplayXMLParser::searchContainer(const SkMemberInfo* infoBase, + int infoCount) { + const SkMemberInfo* bestDisplayable = nil; + const SkMemberInfo* lastResort = nil; + for (int index = 0; index < infoCount; index++) { + const SkMemberInfo* info = &infoBase[index]; + if (info->fType == SkType_BaseClassInfo) { + const SkMemberInfo* inherited = info->getInherited(); + const SkMemberInfo* result = searchContainer(inherited, info->fCount); + if (result != nil) + return result; + continue; + } + Parent* container = fParents.end() - 1; + SkDisplayTypes type = (SkDisplayTypes) info->fType; + if (type == SkType_MemberProperty) + type = info->propertyType(); + SkDisplayTypes containerType = container->fType; + if (type == containerType && (type == SkType_Rect || type == SkType_Polygon || + type == SkType_Array || type == SkType_Int || type == SkType_Bitmap)) + goto rectNext; + while (type != containerType) { + if (containerType == SkType_Displayable) + goto next; + containerType = SkDisplayType::GetParent(&fMaker, containerType); + if (containerType == SkType_Unknown) + goto next; + } + return info; +next: + if (type == SkType_Drawable || type == SkType_Displayable && + container->fDisplayable->isDrawable()) { +rectNext: + if (fParents.count() > 1) { + Parent* parent = fParents.end() - 2; + if (info == parent->fDisplayable->preferredChild(type)) + bestDisplayable = info; + else + lastResort = info; + } + } + } + if (bestDisplayable) + return bestDisplayable; + if (lastResort) + return lastResort; + return nil; +} + + diff --git a/libs/graphics/animator/SkDisplayXMLParser.h b/libs/graphics/animator/SkDisplayXMLParser.h new file mode 100644 index 0000000000..3aa42cfc51 --- /dev/null +++ b/libs/graphics/animator/SkDisplayXMLParser.h @@ -0,0 +1,84 @@ +#ifndef SkDisplayXMLParser_DEFINED +#define SkDisplayXMLParser_DEFINED + +#include "SkIntArray.h" +#include "SkTDict.h" +#include "SkDisplayType.h" +#include "SkXMLParser.h" + +class SkAnimateMaker; +class SkDisplayable; + +class SkDisplayXMLParserError : public SkXMLParserError { +public: + enum ErrorCode { + kApplyScopesItself = kUnknownError + 1, + kDisplayTreeTooDeep, + kElementMissingParent, + kElementTypeNotAllowedInParent, + kErrorAddingDataToPost, + kErrorAddingToMatrix, + kErrorAddingToPaint, + kErrorAddingToPath, + kErrorInAttributeValue, + kErrorInScript, + kExpectedMovie, + kFieldNotInTarget, + kGradientOffsetsDontMatchColors, + kGradientOffsetsMustBeNoMoreThanOne, + kGradientOffsetsMustEndWithOne, + kGradientOffsetsMustIncrease, + kGradientOffsetsMustStartWithZero, + kGradientPointsLengthMustBeFour, + kInInclude, + kInMovie, + kIncludeNameUnknownOrMissing, + kIndexOutOfRange, + kMovieNameUnknownOrMissing, + kNoParentAvailable, + kParentElementCantContain, + kSaveLayerNeedsBounds, + kTargetIDNotFound, + kUnexpectedType + }; + virtual ~SkDisplayXMLParserError(); + virtual void getErrorString(SkString* str) const; + void setCode(ErrorCode code) { INHERITED::setCode((INHERITED::ErrorCode) code); } + void setInnerError(SkAnimateMaker* maker, const SkString& str); + typedef SkXMLParserError INHERITED; + friend class SkDisplayXMLParser; +}; + +class SkDisplayXMLParser : public SkXMLParser { +public: + SkDisplayXMLParser(SkAnimateMaker& maker); + virtual ~SkDisplayXMLParser(); +protected: + virtual bool onAddAttribute(const char name[], const char value[]); + bool onAddAttributeLen(const char name[], const char value[], size_t len); + virtual bool onEndElement(const char elem[]); + virtual bool onStartElement(const char elem[]); + bool onStartElementLen(const char elem[], size_t len); +private: + struct Parent { + SkDisplayable* fDisplayable; + SkDisplayTypes fType; + }; + SkTDArray<Parent> fParents; + SkDisplayXMLParser& operator= (const SkDisplayXMLParser& ); + SkDisplayXMLParserError* getError() { return (SkDisplayXMLParserError*) fError; } + const SkMemberInfo* searchContainer(const SkMemberInfo* , + int infoCount); + SkAnimateMaker& fMaker; + SkBool fInInclude; + SkBool fInSkia; + // local state between onStartElement and onAddAttribute + SkDisplayable* fCurrDisplayable; + SkDisplayTypes fCurrType; + friend class SkXMLAnimatorWriter; + typedef SkXMLParser INHERITED; +}; + +#endif // SkDisplayXMLParser_DEFINED + + diff --git a/libs/graphics/animator/SkDisplayable.cpp b/libs/graphics/animator/SkDisplayable.cpp new file mode 100644 index 0000000000..41c4b47933 --- /dev/null +++ b/libs/graphics/animator/SkDisplayable.cpp @@ -0,0 +1,549 @@ +#include "SkDisplayable.h" +#include "SkDisplayApply.h" +#include "SkParse.h" +#ifdef SK_DEBUG +#include "SkDisplayList.h" +#endif +#include "SkDisplayTypes.h" + +#ifdef SK_FIND_LEAKS +// int SkDisplayable::fAllocationCount; +SkTDDisplayableArray SkDisplayable::fAllocations; +#endif + +#ifdef SK_DEBUG +SkDisplayable::SkDisplayable() { + id = _id.c_str(); +#ifdef SK_FIND_LEAKS + // fAllocationCount++; + *fAllocations.append() = this; +#endif +} +#endif + +SkDisplayable::~SkDisplayable() { +#ifdef SK_FIND_LEAKS + // fAllocationCount--; + int index = fAllocations.find(this); + SkASSERT(index >= 0); + fAllocations.remove(index); +#endif +} + +bool SkDisplayable::add(SkAnimateMaker& , SkDisplayable* child) { + return false; +} + +//void SkDisplayable::apply(SkAnimateMaker& , const SkMemberInfo* , +// SkDisplayable* , SkScalar [], int count) { +// SkASSERT(0); +//} + +bool SkDisplayable::canContainDependents() const { + return false; +} + +bool SkDisplayable::childrenNeedDisposing() const { + return false; +} + +void SkDisplayable::clearBounder() { +} + +bool SkDisplayable::contains(SkDisplayable* ) { + return false; +} + +SkDisplayable* SkDisplayable::contains(const SkString& ) { + return nil; +} + +SkDisplayable* SkDisplayable::deepCopy(SkAnimateMaker* maker) { + SkDisplayTypes type = getType(); + if (type == SkType_Unknown) { + SkASSERT(0); + return nil; + } + SkDisplayable* copy = SkDisplayType::CreateInstance(maker, type); + int index = -1; + int propIndex = 0; + const SkMemberInfo* info; + do { + info = copy->getMember(++index); + if (info == nil) + break; + if (info->fType == SkType_MemberProperty) { + SkScriptValue value; + if (getProperty(propIndex, &value)) + copy->setProperty(propIndex, value); + propIndex++; + continue; + } + if (info->fType == SkType_MemberFunction) + continue; + if (info->fType == SkType_Array) { + SkTDOperandArray* array = (SkTDOperandArray*) info->memberData(this); + int arrayCount; + if (array == nil || (arrayCount = array->count()) == 0) + continue; + SkTDOperandArray* copyArray = (SkTDOperandArray*) info->memberData(copy); + copyArray->setCount(arrayCount); + SkDisplayTypes elementType; + if (type == SkType_Array) { + SkDisplayArray* dispArray = (SkDisplayArray*) this; + elementType = dispArray->values.getType(); + } else + elementType = info->arrayType(); + size_t elementSize = SkMemberInfo::GetSize(elementType); + size_t byteSize = elementSize * arrayCount; + memcpy(copyArray->begin(), array->begin(), byteSize); + continue; + } + if (SkDisplayType::IsDisplayable(maker, info->fType)) { + SkDisplayable** displayable = (SkDisplayable**) info->memberData(this); + if (*displayable == nil || *displayable == (SkDisplayable*) -1) + continue; + SkDisplayable* deeper = (*displayable)->deepCopy(maker); + info->setMemberData(copy, deeper, sizeof(deeper)); + continue; + } + if (info->fType == SkType_String || info->fType == SkType_DynamicString) { + SkString* string; + info->getString(this, &string); + info->setString(copy, string); + continue; + } + void* data = info->memberData(this); + size_t size = SkMemberInfo::GetSize(info->fType); + info->setMemberData(copy, data, size); + } while (true); + copy->dirty(); + return copy; +} + +void SkDisplayable::dirty() { +} + +#ifdef SK_DUMP_ENABLED +void SkDisplayable::dump(SkAnimateMaker* maker) { + dumpBase(maker); +#if SK_USE_CONDENSED_INFO == 0 + this->dumpAttrs(maker); + this->dumpChildren(maker); +#endif +} + +void SkDisplayable::dumpAttrs(SkAnimateMaker* maker) { + SkDisplayTypes type = getType(); + if (type == SkType_Unknown) { + //SkDebugf("/>\n"); + return; + } + SkDisplayable* blankCopy = SkDisplayType::CreateInstance(maker, type); + + int index = -1; + int propIndex = 0; + const SkMemberInfo* info; + const SkMemberInfo* blankInfo; + SkScriptValue value; + SkScriptValue blankValue; + SkOperand values[2]; + SkOperand blankValues[2]; + do { + info = this->getMember(++index); + if (nil == info) { + //SkDebugf("\n"); + break; + } + if (SkType_MemberProperty == info->fType) { + if (getProperty(propIndex, &value)) { + blankCopy->getProperty(propIndex, &blankValue); + //last two are dummies + dumpValues(info, value.fType, value.fOperand, blankValue.fOperand, value.fOperand, blankValue.fOperand); + } + + propIndex++; + continue; + } + if (SkDisplayType::IsDisplayable(maker, info->fType)) { + continue; + } + + if (info->fType == SkType_MemberFunction) + continue; + + + if (info->fType == SkType_Array) { + SkTDOperandArray* array = (SkTDOperandArray*) info->memberData(this); + int arrayCount; + if (array == nil || (arrayCount = array->count()) == 0) + continue; + SkDisplayTypes elementType; + if (type == SkType_Array) { + SkDisplayArray* dispArray = (SkDisplayArray*) this; + elementType = dispArray->values.getType(); + } else + elementType = info->arrayType(); + bool firstElem = true; + SkDebugf("%s=\"[", info->fName); + for (SkOperand* op = array->begin(); op < array->end(); op++) { + if (!firstElem) SkDebugf(","); + switch (elementType) { + case SkType_Displayable: + SkDebugf("%s", op->fDisplayable->id); + break; + case SkType_Int: + SkDebugf("%d", op->fS32); + break; + case SkType_Float: +#ifdef SK_CAN_USE_FLOAT + SkDebugf("%g", SkScalarToFloat(op->fScalar)); +#else + SkDebugf("%x", op->fScalar); +#endif + break; + case SkType_String: + case SkType_DynamicString: + SkDebugf("%s", op->fString->c_str()); + break; + default: + break; + } + firstElem = false; + } + SkDebugf("]\" "); + continue; + } + + if (info->fType == SkType_String || info->fType == SkType_DynamicString) { + SkString* string; + info->getString(this, &string); + if (string->isEmpty() == false) + SkDebugf("%s=\"%s\"\t", info->fName, string->c_str()); + continue; + } + + + blankInfo = blankCopy->getMember(index); + int i = info->fCount; + info->getValue(this, values, i); + blankInfo->getValue(blankCopy, blankValues, i); + dumpValues(info, info->fType, values[0], blankValues[0], values[1], blankValues[1]); + } while (true); + delete blankCopy; +} + +void SkDisplayable::dumpBase(SkAnimateMaker* maker) { + SkDisplayTypes type = getType(); + const char* elementName = "(unknown)"; + if (type != SkType_Unknown && type != SkType_Screenplay) + elementName = SkDisplayType::GetName(maker, type); + SkDebugf("%*s", SkDisplayList::fIndent, ""); + if (SkDisplayList::fDumpIndex != 0 && SkDisplayList::fIndent == 0) + SkDebugf("%d: ", SkDisplayList::fDumpIndex); + SkDebugf("<%s ", elementName); + if (strcmp(id,"") != 0) + SkDebugf("id=\"%s\" ", id); +} + +void SkDisplayable::dumpChildren(SkAnimateMaker* maker, bool closedAngle) { + + int index = -1; + const SkMemberInfo* info; + index = -1; + SkDisplayList::fIndent += 4; + do { + info = this->getMember(++index); + if (nil == info) { + break; + } + if (SkDisplayType::IsDisplayable(maker, info->fType)) { + SkDisplayable** displayable = (SkDisplayable**) info->memberData(this); + if (*displayable == nil || *displayable == (SkDisplayable*) -1) + continue; + if (closedAngle == false) { + SkDebugf(">\n"); + closedAngle = true; + } + (*displayable)->dump(maker); + } + } while (true); + SkDisplayList::fIndent -= 4; + if (closedAngle) + dumpEnd(maker); + else + SkDebugf("/>\n"); +} + +void SkDisplayable::dumpEnd(SkAnimateMaker* maker) { + SkDisplayTypes type = getType(); + const char* elementName = "(unknown)"; + if (type != SkType_Unknown && type != SkType_Screenplay) + elementName = SkDisplayType::GetName(maker, type); + SkDebugf("%*s", SkDisplayList::fIndent, ""); + SkDebugf("</%s>\n", elementName); +} + +void SkDisplayable::dumpEvents() { +} + +void SkDisplayable::dumpValues(const SkMemberInfo* info, SkDisplayTypes type, SkOperand op, SkOperand blankOp, + SkOperand op2, SkOperand blankOp2) { + switch (type) { + case SkType_BitmapEncoding: + switch (op.fS32) { + case 0 : SkDebugf("type=\"jpeg\" "); + break; + case 1 : SkDebugf("type=\"png\" "); + break; + default: SkDebugf("type=\"UNDEFINED\" "); + } + break; + //should make this a separate case in dump attrs, rather than make dump values have a larger signature + case SkType_Point: + if (op.fScalar != blankOp.fScalar || op2.fScalar != blankOp.fScalar) { +#ifdef SK_CAN_USE_FLOAT + SkDebugf("%s=\"[%g,%g]\" ", info->fName, SkScalarToFloat(op.fScalar), SkScalarToFloat(op2.fScalar)); +#else + SkDebugf("%s=\"[%x,%x]\" ", info->fName, op.fScalar, op2.fScalar); +#endif + } + break; + case SkType_FromPathMode: + switch (op.fS32) { + case 0: + //don't want to print anything for 0, just adding it to remove it from default: + break; + case 1: + SkDebugf("%s=\"%s\" ", info->fName, "angle"); + break; + case 2: + SkDebugf("%s=\"%s\" ", info->fName, "position"); + break; + default: + SkDebugf("%s=\"INVALID\" ", info->fName); + } + break; + case SkType_MaskFilterBlurStyle: + switch (op.fS32) { + case 0: + break; + case 1: + SkDebugf("%s=\"%s\" ", info->fName, "solid"); + break; + case 2: + SkDebugf("%s=\"%s\" ", info->fName, "outer"); + break; + case 3: + SkDebugf("%s=\"%s\" ", info->fName, "inner"); + break; + default: + SkDebugf("%s=\"INVALID\" ", info->fName); + } + break; + case SkType_FilterType: + if (op.fS32 == 1) + SkDebugf("%s=\"%s\" ", info->fName, "bilinear"); + break; + case SkType_PathDirection: + SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "cw" : "ccw"); + break; + case SkType_FillType: + SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "winding" : "evenOdd"); + break; + case SkType_TileMode: + //correct to look at the S32? + if (op.fS32 != blankOp.fS32) + SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "clamp" : op.fS32 == 1 ? "repeat" : "mirror"); + break; + case SkType_Boolean: + if (op.fS32 != blankOp.fS32) + SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "false" : "true"); + break; + case SkType_Int: + if (op.fS32 != blankOp.fS32) + SkDebugf(" %s=\"%d\" ", info->fName, op.fS32); + break; + case SkType_Float: + if (op.fScalar != blankOp.fScalar) { //or /65536? +#ifdef SK_CAN_USE_FLOAT + SkDebugf("%s=\"%g\" ", info->fName, SkScalarToFloat(op.fScalar)); +#else + SkDebugf("%s=\"%x\" ", info->fName, op.fScalar); +#endif + } + break; + case SkType_String: + case SkType_DynamicString: + if (op.fString->size() > 0) + SkDebugf("%s=\"%s\" ", info->fName, op.fString->c_str()); + break; + case SkType_MSec: + if (op.fS32 != blankOp.fS32) { +#ifdef SK_CAN_USE_FLOAT + SkDebugf(" %s=\"%g\" ", info->fName, SkScalarToFloat(SkScalarDiv(op.fS32, 1000))); +#else + SkDebugf(" %s=\"%x\" ", info->fName, SkScalarDiv(op.fS32, 1000)); +#endif + } + default: + SkDebugf(""); + } +} + +#endif + +bool SkDisplayable::enable( SkAnimateMaker& ) { + return false; +} + +void SkDisplayable::enableBounder() { +} + +void SkDisplayable::executeFunction(SkDisplayable* , int index, + SkTDArray<SkScriptValue>& , SkDisplayTypes, SkScriptValue* ) { + SkASSERT(0); +} + +void SkDisplayable::executeFunction(SkDisplayable* target, + const SkMemberInfo* info, SkTypedArray* values, SkScriptValue* value) { + SkTDArray<SkScriptValue> typedValues; + for (SkOperand* op = values->begin(); op < values->end(); op++) { + SkScriptValue temp; + temp.fType = values->getType(); + temp.fOperand = *op; + *typedValues.append() = temp; + } + executeFunction(target, info->functionIndex(), typedValues, info->getType(), value); +} + +void SkDisplayable::executeFunction2(SkDisplayable* , int index, + SkOpArray* params, SkDisplayTypes, SkOperand2* ) { + SkASSERT(0); +} + +void SkDisplayable::getBounds(SkRect* rect) { + SkASSERT(rect); + rect->fLeft = rect->fTop = SK_ScalarMax; + rect->fRight= rect->fBottom = -SK_ScalarMax; +} + +const SkFunctionParamType* SkDisplayable::getFunctionsParameters() { + return nil; +} + +const SkMemberInfo* SkDisplayable::getMember(int index) { + return nil; +} + +const SkMemberInfo* SkDisplayable::getMember(const char name[]) { + return nil; +} + +const SkFunctionParamType* SkDisplayable::getParameters(const SkMemberInfo* info, + int* paramCount) { + const SkFunctionParamType* params = getFunctionsParameters(); + SkASSERT(params != nil); + int funcIndex = info->functionIndex(); + // !!! eventually break traversing params into an external function (maybe this whole function) + int index = funcIndex; + int offset = 0; + while (--index >= 0) { + while (params[offset] != 0) + offset++; + offset++; + } + int count = 0; + while (params[offset] != 0) { + count++; + offset++; + } + *paramCount = count; + return ¶ms[offset - count]; +} + +SkDisplayable* SkDisplayable::getParent() const { + return nil; +} + +bool SkDisplayable::getProperty(int index, SkScriptValue* ) const { +// SkASSERT(0); + return false; +} + +bool SkDisplayable::getProperty2(int index, SkOperand2* value) const { + SkASSERT(0); + return false; +} + +SkDisplayTypes SkDisplayable::getType() const { + return SkType_Unknown; +} + +bool SkDisplayable::hasEnable() const { + return false; +} + +bool SkDisplayable::isDrawable() const { + return false; +} + +void SkDisplayable::onEndElement(SkAnimateMaker& ) {} + +const SkMemberInfo* SkDisplayable::preferredChild(SkDisplayTypes type) { + return nil; +} + +bool SkDisplayable::resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* apply) { + return false; +} + +//SkDisplayable* SkDisplayable::resolveTarget(SkAnimateMaker& ) { +// return this; +//} + +void SkDisplayable::setChildHasID() { +} + +bool SkDisplayable::setParent(SkDisplayable* ) { + return false; +} + +bool SkDisplayable::setProperty(int index, SkScriptValue& ) { + //SkASSERT(0); + return false; +} + +void SkDisplayable::setReference(const SkMemberInfo* info, SkDisplayable* displayable) { + if (info->fType == SkType_MemberProperty) { + SkScriptValue scriptValue; + scriptValue.fOperand.fDisplayable = displayable; + scriptValue.fType = displayable->getType(); + setProperty(info->propertyIndex(), scriptValue); + } else if (info->fType == SkType_Array) { + SkASSERT(displayable->getType() == SkType_Array); + SkDisplayArray* dispArray = (SkDisplayArray*) displayable; + SkTDScalarArray* array = (SkTDScalarArray* ) info->memberData(this); + array->setCount(dispArray->values.count()); + memcpy(array->begin(), dispArray->values.begin(), dispArray->values.count() * sizeof(int)); + // + + // !!! need a way for interpreter engine to own array + // !!! probably need to replace all scriptable arrays with single bigger array + // that has operand and type on every element -- or + // when array is dirtied, need to get parent to reparse to local array + } else { + void* storage = info->memberData(this); + memcpy(storage, &displayable, sizeof(SkDisplayable*)); + } +// !!! unclear why displayable is dirtied here +// if this is called, this breaks fromPath.xml +// displayable->dirty(); +} + +#ifdef SK_DEBUG +void SkDisplayable::validate() { +} +#endif + + diff --git a/libs/graphics/animator/SkDisplayable.h b/libs/graphics/animator/SkDisplayable.h new file mode 100644 index 0000000000..aea64b516e --- /dev/null +++ b/libs/graphics/animator/SkDisplayable.h @@ -0,0 +1,103 @@ +#ifndef SkDisplayable_DEFINED +#define SkDisplayable_DEFINED + +#include "SkOperand.h" +#ifdef SK_DEBUG +#include "SkString.h" +#endif +#include "SkIntArray.h" +#include "SkRect.h" +#include "SkTDArray.h" + +class SkAnimateMaker; +class SkApply; +class SkEvents; +struct SkMemberInfo; +struct SkScriptValue; +class SkOpArray; // compiled scripting experiment +union SkOperand2; // compiled scripting experiment + +class SkDisplayable { +public: +#ifdef SK_DEBUG + SkDisplayable(); +#endif + virtual ~SkDisplayable(); + virtual bool add(SkAnimateMaker& , SkDisplayable* child); + virtual bool canContainDependents() const; + virtual bool childrenNeedDisposing() const; + virtual void clearBounder(); + virtual bool contains(SkDisplayable* ); + virtual SkDisplayable* contains(const SkString& ); + virtual SkDisplayable* deepCopy(SkAnimateMaker* ); + virtual void dirty(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); + void dumpAttrs(SkAnimateMaker* ); + void dumpBase(SkAnimateMaker* ); + void dumpChildren(SkAnimateMaker* maker, bool closedAngle = false ); + void dumpEnd(SkAnimateMaker* ); + virtual void dumpEvents(); +#endif + virtual bool enable( SkAnimateMaker& ); + virtual void enableBounder(); + virtual void executeFunction(SkDisplayable* , int functionIndex, + SkTDArray<SkScriptValue>& , SkDisplayTypes , SkScriptValue* ); + void executeFunction(SkDisplayable* , const SkMemberInfo* , + SkTypedArray* , SkScriptValue* ); + virtual void executeFunction2(SkDisplayable* , int functionIndex, + SkOpArray* params , SkDisplayTypes , SkOperand2* ); // compiled scripting experiment + virtual void getBounds(SkRect* ); + virtual const SkFunctionParamType* getFunctionsParameters(); + virtual const SkMemberInfo* getMember(int index); + virtual const SkMemberInfo* getMember(const char name[]); + const SkFunctionParamType* getParameters(const SkMemberInfo* info, + int* paramCount); + virtual SkDisplayable* getParent() const; + virtual bool getProperty(int index, SkScriptValue* value) const; + virtual bool getProperty2(int index, SkOperand2* value) const; // compiled scripting experiment + virtual SkDisplayTypes getType() const; + virtual bool hasEnable() const; + bool isAnimate() const { + SkDisplayTypes type = getType(); + return type == SkType_Animate || type == SkType_Set; } + bool isApply() const { return getType() == SkType_Apply; } + bool isColor() const { return getType() == SkType_Color; } + virtual bool isDrawable() const; + bool isGroup() const { return getType() == SkType_Group || + getType() == SkType_Save || getType() == SkType_DrawTo || + getType() == SkType_SaveLayer; } + bool isMatrix() const { return getType() == SkType_Matrix; } + virtual bool isPaint() const { return getType() == SkType_Paint; } + virtual bool isPath() const { return false; } + bool isPost() const { return getType() == SkType_Post; } + virtual void onEndElement(SkAnimateMaker& ); + virtual const SkMemberInfo* preferredChild(SkDisplayTypes type); + virtual bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* ); + virtual void setChildHasID(); + virtual bool setParent(SkDisplayable* ); + virtual bool setProperty(int index, SkScriptValue& ); + void setReference(const SkMemberInfo* info, SkDisplayable* ref); +#ifdef SK_DEBUG + bool isData() const { return getType() == SkType_Data; }; + bool isEvent() const { return getType() == SkType_Event; } + virtual bool isMatrixPart() const { return false; } + bool isPatch() const { return getType() == SkType_3D_Patch; } + virtual bool isPaintPart() const { return false; } + virtual bool isPathPart() const { return false; } + virtual void validate(); + SkString _id; + const char* id; +// static int fAllocationCount; + static SkTDDisplayableArray fAllocations; +#else + void validate() {} +#endif +#ifdef SK_DUMP_ENABLED +private: + void dumpValues(const SkMemberInfo* info, SkDisplayTypes type, SkOperand op, SkOperand blankOp, + SkOperand op2, SkOperand blankOp2); +#endif +}; + +#endif // SkDisplayable_DEFINED diff --git a/libs/graphics/animator/SkDraw3D.cpp b/libs/graphics/animator/SkDraw3D.cpp new file mode 100644 index 0000000000..8a69445212 --- /dev/null +++ b/libs/graphics/animator/SkDraw3D.cpp @@ -0,0 +1,100 @@ +#include "SkDraw3D.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkTypedArray.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo Sk3D_Point::fInfo[] = { + SK_MEMBER_ALIAS(x, fPoint.fX, Float), + SK_MEMBER_ALIAS(y, fPoint.fY, Float), + SK_MEMBER_ALIAS(z, fPoint.fZ, Float) +}; + +#endif + +DEFINE_NO_VIRTUALS_GET_MEMBER(Sk3D_Point); + +Sk3D_Point::Sk3D_Point() { + fPoint.set(0, 0, 0); +} + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo Sk3D_Camera::fInfo[] = { + SK_MEMBER_ALIAS(axis, fCamera.fAxis, 3D_Point), + SK_MEMBER(hackHeight, Float), + SK_MEMBER(hackWidth, Float), + SK_MEMBER_ALIAS(location, fCamera.fLocation, 3D_Point), + SK_MEMBER_ALIAS(observer, fCamera.fObserver, 3D_Point), + SK_MEMBER(patch, 3D_Patch), + SK_MEMBER_ALIAS(zenith, fCamera.fZenith, 3D_Point), +}; + +#endif + +DEFINE_GET_MEMBER(Sk3D_Camera); + +Sk3D_Camera::Sk3D_Camera() : hackWidth(0), hackHeight(0), patch(nil) { +} + +Sk3D_Camera::~Sk3D_Camera() { +} + +bool Sk3D_Camera::draw(SkAnimateMaker& maker) { + fCamera.update(); + SkMatrix matrix; + fCamera.computeMatrix(patch->fPatch, &matrix); + matrix.preTranslate(hackWidth / 2, -hackHeight / 2); + matrix.postTranslate(hackWidth / 2, hackHeight / 2); + maker.fCanvas->concat(matrix); + return false; +} + + +enum Sk3D_Patch_Functions { + SK_FUNCTION(rotateDegrees) +}; + +const SkFunctionParamType Sk3D_Patch::fFunctionParameters[] = { + (SkFunctionParamType) SkType_Float, + (SkFunctionParamType) SkType_Float, + (SkFunctionParamType) SkType_Float, + (SkFunctionParamType) 0 // terminator for parameter list (there may be multiple parameter lists) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo Sk3D_Patch::fInfo[] = { + SK_MEMBER_ALIAS(origin, fPatch.fOrigin, 3D_Point), + SK_MEMBER_FUNCTION(rotateDegrees, Float), + SK_MEMBER_ALIAS(u, fPatch.fU, 3D_Point), + SK_MEMBER_ALIAS(v, fPatch.fV, 3D_Point) +}; + +#endif + +DEFINE_GET_MEMBER(Sk3D_Patch); + +void Sk3D_Patch::executeFunction(SkDisplayable* target, int index, + SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, + SkScriptValue* ) { + SkASSERT(target == this); + switch (index) { + case SK_FUNCTION(rotateDegrees): + SkASSERT(parameters.count() == 3); + SkASSERT(type == SkType_Float); + fPatch.rotateDegrees(parameters[0].fOperand.fScalar, + parameters[1].fOperand.fScalar, parameters[2].fOperand.fScalar); + break; + default: + SkASSERT(0); + } +} + +const SkFunctionParamType* Sk3D_Patch::getFunctionsParameters() { + return fFunctionParameters; +} + + + diff --git a/libs/graphics/animator/SkDraw3D.h b/libs/graphics/animator/SkDraw3D.h new file mode 100644 index 0000000000..55f76645e8 --- /dev/null +++ b/libs/graphics/animator/SkDraw3D.h @@ -0,0 +1,42 @@ +#ifndef SkDraw3D_DEFINED +#define SkDraw3D_DEFINED + +#include "SkCamera.h" +#include "SkDrawable.h" +#include "SkMemberInfo.h" + +class Sk3D_Patch; + +struct Sk3D_Point { + DECLARE_NO_VIRTUALS_MEMBER_INFO(3D_Point); + Sk3D_Point(); +private: + SkPoint3D fPoint; +}; + +class Sk3D_Camera : public SkDrawable { + DECLARE_MEMBER_INFO(3D_Camera); + Sk3D_Camera(); + virtual ~Sk3D_Camera(); + virtual bool draw(SkAnimateMaker& ); +private: + SkScalar hackWidth; + SkScalar hackHeight; + SkCamera3D fCamera; + Sk3D_Patch* patch; +}; + +class Sk3D_Patch : public SkDisplayable { + DECLARE_MEMBER_INFO(3D_Patch); +private: + virtual void executeFunction(SkDisplayable* , int index, + SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, + SkScriptValue* ); + virtual const SkFunctionParamType* getFunctionsParameters(); + SkPatch3D fPatch; + static const SkFunctionParamType fFunctionParameters[]; + friend class Sk3D_Camera; +}; + +#endif // SkDraw3D_DEFINED + diff --git a/libs/graphics/animator/SkDrawBitmap.cpp b/libs/graphics/animator/SkDrawBitmap.cpp new file mode 100644 index 0000000000..3ad4e007d8 --- /dev/null +++ b/libs/graphics/animator/SkDrawBitmap.cpp @@ -0,0 +1,186 @@ +#include "SkDrawBitmap.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkImageDecoder.h" +#include "SkPaint.h" +#include "SkStream.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkBaseBitmap::fInfo[] = { + SK_MEMBER(x, Float), + SK_MEMBER(y, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkBaseBitmap); + +SkBaseBitmap::SkBaseBitmap() : x(0), y(0) { +} + +SkBaseBitmap::~SkBaseBitmap() { +} + +bool SkBaseBitmap::draw(SkAnimateMaker& maker) { + SkBoundableAuto boundable(this, maker); + maker.fCanvas->drawBitmap(fBitmap, x, y, *maker.fPaint); + return false; +} + +enum SkDrawBitmap_Properties { + SK_PROPERTY(erase) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawBitmap::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER_PROPERTY(erase, ARGB), + SK_MEMBER(format, BitmapFormat), + SK_MEMBER(height, Int), + SK_MEMBER(rowBytes, Int), + SK_MEMBER(width, Int), +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawBitmap); + +SkDrawBitmap::SkDrawBitmap() : format((SkBitmap::Config) -1), height(-1), + rowBytes(0), width(-1), fColor(0), fColorSet(false) { +} + +SkDrawBitmap::~SkDrawBitmap() { +} + +#ifdef SK_DUMP_ENABLED +void SkDrawBitmap::dump(SkAnimateMaker* maker) { + dumpBase(maker); + dumpAttrs(maker); + if (fColorSet) + SkDebugf("erase=\"argb(%d,%d,%d,%d)\" ", SkColorGetA(fColor)/255, SkColorGetR(fColor), + SkColorGetG(fColor), SkColorGetB(fColor)); + if (rowBytes > 0) + SkDebugf("rowBytes=\"%d\" ", rowBytes); + const char* formatName; + switch (format) { + case 0: formatName = "none"; break; + case 1: formatName = "A1"; break; + case 2: formatName = "A8"; break; + case 3: formatName = "Index8"; break; + case 4: formatName = "RGB16"; break; + case 5: formatName = "RGB32"; break; + } + SkDebugf("format=\"%s\" />\n", formatName); +} +#endif + +void SkDrawBitmap::onEndElement(SkAnimateMaker& maker) { + SkASSERT(format != (SkBitmap::Config) -1); + SkASSERT(width != -1); + SkASSERT(height != -1); + SkASSERT(rowBytes >= 0); + fBitmap.setConfig((SkBitmap::Config) format, width, height, rowBytes); + fBitmap.allocPixels(); + if (fColorSet) + fBitmap.eraseColor(fColor); +} + +bool SkDrawBitmap::setProperty(int index, SkScriptValue& value) +{ + switch (index) { + case SK_PROPERTY(erase): + SkASSERT(value.fType == SkType_ARGB); + fColor = value.fOperand.fS32; + fColorSet = true; + break; + default: + SkASSERT(0); + return false; + } + return true; +} + + +enum SkImage_Properties { + SK_PROPERTY(height), + SK_PROPERTY(width) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkImage::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER(base64, Base64), + SK_MEMBER_PROPERTY(height, Int), + SK_MEMBER(src, String), + SK_MEMBER_PROPERTY(width, Int) +}; + +#endif + +DEFINE_GET_MEMBER(SkImage); + +SkImage::SkImage() : fDirty(true), fUriBase(nil) { + base64.fData = nil; + base64.fLength = 0; +} + +SkImage::~SkImage() { + delete[] base64.fData; +} + +SkDisplayable* SkImage::deepCopy(SkAnimateMaker* maker) { + SkDisplayable* copy = INHERITED::deepCopy(maker); + ((SkImage*) copy)->fUriBase = ((SkImage*) this)->fUriBase; + return copy; +} + +void SkImage::dirty() { + fDirty = true; +} + +bool SkImage::draw(SkAnimateMaker& maker) { + if (fDirty) + resolve(); + return INHERITED::draw(maker); +} + +bool SkImage::getProperty(int index, SkScriptValue* value) const { + if (fDirty) + resolve(); + switch (index) { + case SK_PROPERTY(height): + value->fOperand.fS32 = fBitmap.height(); + break; + case SK_PROPERTY(width): + value->fOperand.fS32 = fBitmap.width(); + break; + default: + SkASSERT(0); + return false; + } + value->fType = SkType_Int; + return true; +} + +void SkImage::onEndElement(SkAnimateMaker& maker) { + fUriBase = maker.fPrefix.c_str(); +} + +void SkImage::resolve() { + fDirty = false; + if (base64.fData) { + fBitmap.reset(); + SkImageDecoder::DecodeMemory(base64.fData, base64.fLength, &fBitmap); + } else if (src.size()) { + if (fLast.equals(src)) + return; + fLast.set(src); + fBitmap.reset(); + SkStream* stream = SkStream::GetURIStream(fUriBase, src.c_str()); + SkAutoTDelete<SkStream> autoDel(stream); + SkImageDecoder::DecodeStream(stream, &fBitmap); + } +} diff --git a/libs/graphics/animator/SkDrawBitmap.h b/libs/graphics/animator/SkDrawBitmap.h new file mode 100644 index 0000000000..f5ef3303cd --- /dev/null +++ b/libs/graphics/animator/SkDrawBitmap.h @@ -0,0 +1,65 @@ +#ifndef SkDrawBitmap_DEFINED +#define SkDrawBitmap_DEFINED + +#include "SkBoundable.h" +#include "SkBase64.h" +#include "SkBitmap.h" +// #include "SkImageDecoder.h" +#include "SkMemberInfo.h" + +class SkBaseBitmap : public SkBoundable { + DECLARE_MEMBER_INFO(BaseBitmap); + SkBaseBitmap(); + virtual ~SkBaseBitmap(); + virtual bool draw(SkAnimateMaker& ); +protected: + SkBitmap fBitmap; + SkScalar x; + SkScalar y; +private: + friend class SkDrawTo; + friend class SkDrawBitmapShader; + typedef SkBoundable INHERITED; +}; + +class SkDrawBitmap : public SkBaseBitmap { + DECLARE_DRAW_MEMBER_INFO(Bitmap); + SkDrawBitmap(); + virtual ~SkDrawBitmap(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual void onEndElement(SkAnimateMaker& ); + virtual bool setProperty(int index, SkScriptValue& value); +protected: + int /*SkBitmap::Config*/ format; + S32 height; + S32 rowBytes; + S32 width; + SkColor fColor; + SkBool fColorSet; + typedef SkBaseBitmap INHERITED; +}; + +class SkImage : public SkBaseBitmap { + DECLARE_MEMBER_INFO(Image); + SkImage(); + virtual ~SkImage(); + virtual SkDisplayable* deepCopy(SkAnimateMaker* ); + virtual void dirty(); + virtual bool draw(SkAnimateMaker& ); + virtual bool getProperty(int index, SkScriptValue* value) const; + virtual void onEndElement(SkAnimateMaker& maker); +private: + void resolve() const { (const_cast<SkImage*>(this))->resolve(); } + void resolve(); +protected: + SkBase64 base64; + SkString src; + SkString fLast; // cache of src so that stream isn't unnecessarily decoded + SkBool fDirty; + const char* fUriBase; + typedef SkBaseBitmap INHERITED; +}; + +#endif // SkDrawBitmap_DEFINED diff --git a/libs/graphics/animator/SkDrawBlur.cpp b/libs/graphics/animator/SkDrawBlur.cpp new file mode 100644 index 0000000000..170a770ba7 --- /dev/null +++ b/libs/graphics/animator/SkDrawBlur.cpp @@ -0,0 +1,23 @@ +#include "SkDrawBlur.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawBlur::fInfo[] = { + SK_MEMBER(blurStyle, MaskFilterBlurStyle), + SK_MEMBER(radius, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawBlur); + +SkDrawBlur::SkDrawBlur() : radius(-1), + blurStyle(SkBlurMaskFilter::kNormal_BlurStyle) { +} + +SkMaskFilter* SkDrawBlur::getMaskFilter() { + if (radius < 0) + return nil; + return SkBlurMaskFilter::Create(radius, (SkBlurMaskFilter::BlurStyle) blurStyle); +} + diff --git a/libs/graphics/animator/SkDrawBlur.h b/libs/graphics/animator/SkDrawBlur.h new file mode 100644 index 0000000000..4bfb2689d0 --- /dev/null +++ b/libs/graphics/animator/SkDrawBlur.h @@ -0,0 +1,17 @@ +#ifndef SkDrawBlur_DEFINED +#define SkDrawBlur_DEFINED + +#include "SkPaintParts.h" +#include "SkBlurMaskFilter.h" + +class SkDrawBlur : public SkDrawMaskFilter { + DECLARE_DRAW_MEMBER_INFO(Blur); + SkDrawBlur(); + virtual SkMaskFilter* getMaskFilter(); +protected: + SkScalar radius; + int /*SkBlurMaskFilter::BlurStyle*/ blurStyle; +}; + +#endif // SkDrawBlur_DEFINED + diff --git a/libs/graphics/animator/SkDrawClip.cpp b/libs/graphics/animator/SkDrawClip.cpp new file mode 100644 index 0000000000..471750101e --- /dev/null +++ b/libs/graphics/animator/SkDrawClip.cpp @@ -0,0 +1,31 @@ +#include "SkDrawClip.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkDrawRectangle.h" +#include "SkDrawPath.h" + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawClip::fInfo[] = { + SK_MEMBER(path, Path), + SK_MEMBER(rect, Rect) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawClip); + +SkDrawClip::SkDrawClip() : rect(nil), path(nil) { +} + +bool SkDrawClip::draw(SkAnimateMaker& maker ) { + if (rect != nil) + maker.fCanvas->clipRect(rect->fRect); + else { + SkASSERT(path != nil); + maker.fCanvas->clipPath(path->fPath); + } + return false; +} + diff --git a/libs/graphics/animator/SkDrawClip.h b/libs/graphics/animator/SkDrawClip.h new file mode 100644 index 0000000000..6c896660a4 --- /dev/null +++ b/libs/graphics/animator/SkDrawClip.h @@ -0,0 +1,20 @@ +#ifndef SkDrawClip_DEFINED +#define SkDrawClip_DEFINED + +#include "SkDrawable.h" +#include "SkMemberInfo.h" +#include "SkRegion.h" + +class SkDrawPath; +class SkDrawRect; + +class SkDrawClip : public SkDrawable { + DECLARE_DRAW_MEMBER_INFO(Clip); + SkDrawClip(); + virtual bool draw(SkAnimateMaker& ); +private: + SkDrawRect* rect; + SkDrawPath* path; +}; + +#endif // SkDrawClip_DEFINED diff --git a/libs/graphics/animator/SkDrawColor.cpp b/libs/graphics/animator/SkDrawColor.cpp new file mode 100644 index 0000000000..a21bde4e75 --- /dev/null +++ b/libs/graphics/animator/SkDrawColor.cpp @@ -0,0 +1,261 @@ +#include "SkDrawColor.h" +#ifdef SK_DEBUG +#include "SkDisplayList.h" +#endif +#include "SkDrawPaint.h" +#include "SkParse.h" +#include "SkScript.h" + +enum HSV_Choice { + kGetHue, + kGetSaturation, + kGetValue +}; + +static SkScalar RGB_to_HSV(SkColor color, HSV_Choice choice) { + SkScalar red = SkIntToScalar(SkColorGetR(color)); + SkScalar green = SkIntToScalar(SkColorGetG(color)); + SkScalar blue = SkIntToScalar(SkColorGetB(color)); + SkScalar min = SkMinScalar(SkMinScalar(red, green), blue); + SkScalar value = SkMaxScalar(SkMaxScalar(red, green), blue); + if (choice == kGetValue) + return value/255; + SkScalar delta = value - min; + SkScalar saturation = value == 0 ? 0 : SkScalarDiv(delta, value); + if (choice == kGetSaturation) + return saturation; + SkScalar hue; + if (saturation == 0) + hue = 0; + else { + SkScalar part60 = SkScalarDiv(60 * SK_Scalar1, delta); + if (red == value) { + hue = SkScalarMul(green - blue, part60); + if (hue < 0) + hue += 360 * SK_Scalar1; + } + else if (green == value) + hue = 120 * SK_Scalar1 + SkScalarMul(blue - red, part60); + else // blue == value + hue = 240 * SK_Scalar1 + SkScalarMul(red - green, part60); + } + SkASSERT(choice == kGetHue); + return hue; +} + +#if defined _WIN32 && _MSC_VER >= 1300 // disable 'red', etc. may be used without having been initialized +#pragma warning ( push ) +#pragma warning ( disable : 4701 ) +#endif + +static SkColor HSV_to_RGB(SkColor color, HSV_Choice choice, SkScalar hsv) { + SkScalar hue = choice == kGetHue ? hsv : RGB_to_HSV(color, kGetHue); + SkScalar saturation = choice == kGetSaturation ? hsv : RGB_to_HSV(color, kGetSaturation); + SkScalar value = choice == kGetValue ? hsv : RGB_to_HSV(color, kGetValue); + value *= 255; + SkScalar red SK_INIT_TO_AVOID_WARNING; + SkScalar green SK_INIT_TO_AVOID_WARNING; + SkScalar blue SK_INIT_TO_AVOID_WARNING; + if (saturation == 0) // color is on black-and-white center line + red = green = blue = value; + else { + //SkScalar fraction = SkScalarMod(hue, 60 * SK_Scalar1); + int sextant = SkScalarFloor(hue / 60); + SkScalar fraction = hue / 60 - SkIntToScalar(sextant); + SkScalar p = SkScalarMul(value , SK_Scalar1 - saturation); + SkScalar q = SkScalarMul(value, SK_Scalar1 - SkScalarMul(saturation, fraction)); + SkScalar t = SkScalarMul(value, SK_Scalar1 - + SkScalarMul(saturation, SK_Scalar1 - fraction)); + switch (sextant % 6) { + case 0: red = value; green = t; blue = p; break; + case 1: red = q; green = value; blue = p; break; + case 2: red = p; green = value; blue = t; break; + case 3: red = p; green = q; blue = value; break; + case 4: red = t; green = p; blue = value; break; + case 5: red = value; green = p; blue = q; break; + } + } + //used to say SkToU8((U8CPU) red) etc + return SkColorSetARGB(SkColorGetA(color), SkScalarRound(red), + SkScalarRound(green), SkScalarRound(blue)); +} + +#if defined _WIN32 && _MSC_VER >= 1300 +#pragma warning ( pop ) +#endif + +enum SkDrawColor_Properties { + SK_PROPERTY(alpha), + SK_PROPERTY(blue), + SK_PROPERTY(green), + SK_PROPERTY(hue), + SK_PROPERTY(red), + SK_PROPERTY(saturation), + SK_PROPERTY(value) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawColor::fInfo[] = { + SK_MEMBER_PROPERTY(alpha, Float), + SK_MEMBER_PROPERTY(blue, Float), + SK_MEMBER(color, ARGB), + SK_MEMBER_PROPERTY(green, Float), + SK_MEMBER_PROPERTY(hue, Float), + SK_MEMBER_PROPERTY(red, Float), + SK_MEMBER_PROPERTY(saturation, Float), + SK_MEMBER_PROPERTY(value, Float), +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawColor); + +SkDrawColor::SkDrawColor() : fDirty(false) { + color = SK_ColorBLACK; + fHue = fSaturation = fValue = SK_ScalarNaN; +} + +bool SkDrawColor::add() { + if (fPaint->color != nil) + return true; // error (probably color in paint as attribute as well) + fPaint->color = this; + fPaint->fOwnsColor = true; + return false; +} + +SkDisplayable* SkDrawColor::deepCopy(SkAnimateMaker* maker) { + SkDrawColor* copy = new SkDrawColor(); + copy->color = color; + copy->fHue = fHue; + copy->fSaturation = fSaturation; + copy->fValue = fValue; + copy->fDirty = fDirty; + return copy; +} + +void SkDrawColor::dirty(){ + fDirty = true; +} + +#ifdef SK_DUMP_ENABLED +void SkDrawColor::dump(SkAnimateMaker* maker) { + dumpBase(maker); + SkDebugf("alpha=\"%d\" red=\"%d\" green=\"%d\" blue=\"%d\" />\n", + SkColorGetA(color)/255, SkColorGetR(color), + SkColorGetG(color), SkColorGetB(color)); +} +#endif + +SkColor SkDrawColor::getColor() { + if (fDirty) { + if (SkScalarIsNaN(fValue) == false) + color = HSV_to_RGB(color, kGetValue, fValue); + if (SkScalarIsNaN(fSaturation) == false) + color = HSV_to_RGB(color, kGetSaturation, fSaturation); + if (SkScalarIsNaN(fHue) == false) + color = HSV_to_RGB(color, kGetHue, fHue); + fDirty = false; + } + return color; +} + +SkDisplayable* SkDrawColor::getParent() const { + return fPaint; +} + +bool SkDrawColor::getProperty(int index, SkScriptValue* value) const { + value->fType = SkType_Float; + SkScalar result; + switch(index) { + case SK_PROPERTY(alpha): + result = SkIntToScalar(SkColorGetA(color)) / 255; + break; + case SK_PROPERTY(blue): + result = SkIntToScalar(SkColorGetB(color)); + break; + case SK_PROPERTY(green): + result = SkIntToScalar(SkColorGetG(color)); + break; + case SK_PROPERTY(hue): + result = RGB_to_HSV(color, kGetHue); + break; + case SK_PROPERTY(red): + result = SkIntToScalar(SkColorGetR(color)); + break; + case SK_PROPERTY(saturation): + result = RGB_to_HSV(color, kGetSaturation); + break; + case SK_PROPERTY(value): + result = RGB_to_HSV(color, kGetValue); + break; + default: + SkASSERT(0); + return false; + } + value->fOperand.fScalar = result; + return true; +} + +void SkDrawColor::onEndElement(SkAnimateMaker& maker){ + fDirty = true; +} + +bool SkDrawColor::setParent(SkDisplayable* parent) { + SkASSERT(parent != nil); + if (parent->getType() == SkType_LinearGradient || parent->getType() == SkType_RadialGradient) + return false; + if (parent->isPaint() == false) + return true; + fPaint = (SkDrawPaint*) parent; + return false; +} + +bool SkDrawColor::setProperty(int index, SkScriptValue& value) { + SkASSERT(value.fType == SkType_Float); + SkScalar scalar = value.fOperand.fScalar; + switch (index) { + case SK_PROPERTY(alpha): + U8 alpha; + #ifdef SK_SCALAR_IS_FLOAT + alpha = scalar == SK_Scalar1 ? 255 : SkToU8((U8CPU) (scalar * 256)); + #else + alpha = SkToU8((scalar - (scalar >= SK_ScalarHalf)) >> 8); + #endif + color = SkColorSetARGB(alpha, SkColorGetR(color), + SkColorGetG(color), SkColorGetB(color)); + break; + case SK_PROPERTY(blue): + scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1); + color = SkColorSetARGB(SkColorGetA(color), SkColorGetR(color), + SkColorGetG(color), SkToU8((U8CPU) scalar)); + break; + case SK_PROPERTY(green): + scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1); + color = SkColorSetARGB(SkColorGetA(color), SkColorGetR(color), + SkToU8((U8CPU) scalar), SkColorGetB(color)); + break; + case SK_PROPERTY(hue): + fHue = scalar;//RGB_to_HSV(color, kGetHue); + fDirty = true; + break; + case SK_PROPERTY(red): + scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1); + color = SkColorSetARGB(SkColorGetA(color), SkToU8((U8CPU) scalar), + SkColorGetG(color), SkColorGetB(color)); + break; + case SK_PROPERTY(saturation): + fSaturation = scalar;//RGB_to_HSV(color, kGetSaturation); + fDirty = true; + break; + case SK_PROPERTY(value): + fValue = scalar;//RGB_to_HSV(color, kGetValue); + fDirty = true; + break; + default: + SkASSERT(0); + return false; + } + return true; +} + diff --git a/libs/graphics/animator/SkDrawColor.h b/libs/graphics/animator/SkDrawColor.h new file mode 100644 index 0000000000..ad7c3f8c24 --- /dev/null +++ b/libs/graphics/animator/SkDrawColor.h @@ -0,0 +1,33 @@ +#ifndef SkDrawColor_DEFINED +#define SkDrawColor_DEFINED + +#include "SkPaintParts.h" +#include "SkColor.h" + +class SkDrawColor : public SkPaintPart { + DECLARE_DRAW_MEMBER_INFO(Color); + SkDrawColor(); + virtual bool add(); + virtual void dirty(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + SkColor getColor(); + virtual SkDisplayable* deepCopy(SkAnimateMaker* ); + virtual SkDisplayable* getParent() const; + virtual bool getProperty(int index, SkScriptValue* value) const; + virtual void onEndElement(SkAnimateMaker& ); + virtual bool setParent(SkDisplayable* parent); + virtual bool setProperty(int index, SkScriptValue&); +protected: + SkColor color; + SkScalar fHue; + SkScalar fSaturation; + SkScalar fValue; + SkBool fDirty; +private: + friend class SkGradient; + typedef SkPaintPart INHERITED; +}; + +#endif // SkDrawColor_DEFINED diff --git a/libs/graphics/animator/SkDrawDash.cpp b/libs/graphics/animator/SkDrawDash.cpp new file mode 100644 index 0000000000..78e2d66db8 --- /dev/null +++ b/libs/graphics/animator/SkDrawDash.cpp @@ -0,0 +1,27 @@ +#include "SkDrawDash.h" +#include "SkDashPathEffect.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDash::fInfo[] = { + SK_MEMBER_ARRAY(intervals, Float), + SK_MEMBER(phase, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDash); + +SkDash::SkDash() : phase(0) { +} + +SkDash::~SkDash() { +} + +SkPathEffect* SkDash::getPathEffect() { + int count = intervals.count(); + if (count == 0) + return nil; + return new SkDashPathEffect(intervals.begin(), count, phase); +} + diff --git a/libs/graphics/animator/SkDrawDash.h b/libs/graphics/animator/SkDrawDash.h new file mode 100644 index 0000000000..ff89f50c24 --- /dev/null +++ b/libs/graphics/animator/SkDrawDash.h @@ -0,0 +1,18 @@ +#ifndef SkDrawDash_DEFINED +#define SkDrawDash_DEFINED + +#include "SkPaintParts.h" +#include "SkIntArray.h" + +class SkDash : public SkDrawPathEffect { + DECLARE_MEMBER_INFO(Dash); + SkDash(); + virtual ~SkDash(); + virtual SkPathEffect* getPathEffect(); +private: + SkTDScalarArray intervals; + SkScalar phase; +}; + +#endif // SkDrawDash_DEFINED + diff --git a/libs/graphics/animator/SkDrawDiscrete.cpp b/libs/graphics/animator/SkDrawDiscrete.cpp new file mode 100644 index 0000000000..9e32772e34 --- /dev/null +++ b/libs/graphics/animator/SkDrawDiscrete.cpp @@ -0,0 +1,26 @@ +#include "SkDrawDiscrete.h" +#include "SkAnimateMaker.h" +#include "SkPaint.h" +#include "SkDiscretePathEffect.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDiscrete::fInfo[] = { + SK_MEMBER(deviation, Float), + SK_MEMBER(segLength, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDiscrete); + +SkDiscrete::SkDiscrete() : deviation(0), segLength(0) { +} + +SkPathEffect* SkDiscrete::getPathEffect() { + if (deviation <= 0 || segLength <= 0) + return nil; + else + return new SkDiscretePathEffect(segLength, deviation); +} + diff --git a/libs/graphics/animator/SkDrawDiscrete.h b/libs/graphics/animator/SkDrawDiscrete.h new file mode 100644 index 0000000000..61aeac039f --- /dev/null +++ b/libs/graphics/animator/SkDrawDiscrete.h @@ -0,0 +1,15 @@ +#ifndef SkDrawDiscrete_DEFINED +#define SkDrawDiscrete_DEFINED + +#include "SkPaintParts.h" + +class SkDiscrete : public SkDrawPathEffect { + DECLARE_MEMBER_INFO(Discrete); + SkDiscrete(); + virtual SkPathEffect* getPathEffect(); +private: + SkScalar deviation; + SkScalar segLength; +}; + +#endif //SkDrawDiscrete_DEFINED diff --git a/libs/graphics/animator/SkDrawEmboss.cpp b/libs/graphics/animator/SkDrawEmboss.cpp new file mode 100644 index 0000000000..f0aee87623 --- /dev/null +++ b/libs/graphics/animator/SkDrawEmboss.cpp @@ -0,0 +1,25 @@ +#include "SkDrawEmboss.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawEmboss::fInfo[] = { + SK_MEMBER(ambient, Float), + SK_MEMBER_ARRAY(direction, Float), + SK_MEMBER(radius, Float), + SK_MEMBER(specular, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawEmboss); + +SkDrawEmboss::SkDrawEmboss() : radius(-1) { + direction.setCount(3); +} + +SkMaskFilter* SkDrawEmboss::getMaskFilter() { + if (radius < 0 || direction.count() !=3) + return nil; + return SkBlurMaskFilter::CreateEmboss(direction.begin(), ambient, specular, radius); +} + diff --git a/libs/graphics/animator/SkDrawEmboss.h b/libs/graphics/animator/SkDrawEmboss.h new file mode 100644 index 0000000000..8014f45c8a --- /dev/null +++ b/libs/graphics/animator/SkDrawEmboss.h @@ -0,0 +1,16 @@ +#ifndef SkDrawEmboss_DEFINED +#define SkDrawEmboss_DEFINED + +#include "SkDrawBlur.h" + +class SkDrawEmboss : public SkDrawMaskFilter { + DECLARE_DRAW_MEMBER_INFO(Emboss); + SkDrawEmboss(); + virtual SkMaskFilter* getMaskFilter(); +protected: + SkTDScalarArray direction; + SkScalar radius, ambient, specular; +}; + +#endif // SkDrawEmboss_DEFINED + diff --git a/libs/graphics/animator/SkDrawExtraPathEffect.cpp b/libs/graphics/animator/SkDrawExtraPathEffect.cpp new file mode 100644 index 0000000000..b008643ffb --- /dev/null +++ b/libs/graphics/animator/SkDrawExtraPathEffect.cpp @@ -0,0 +1,499 @@ +#include "SkDrawExtraPathEffect.h" +#include "SkDrawPath.h" +#include "Sk1DPathEffect.h" +#include "Sk2DPathEffect.h" +#include "SkMemberInfo.h" +#include "SkPaintParts.h" +#include "SkPathEffect.h" +#include "SkCornerPathEffect.h" + +#include "SkDashPathEffect.h" + +class SkDrawShapePathEffect : public SkDrawPathEffect { + DECLARE_PRIVATE_MEMBER_INFO(DrawShapePathEffect); + SkDrawShapePathEffect(); + virtual ~SkDrawShapePathEffect(); + virtual bool add(SkAnimateMaker& , SkDisplayable* ); + virtual SkPathEffect* getPathEffect(); +protected: + SkDrawable* addPath; + SkDrawable* addMatrix; + SkDrawPath* path; + SkPathEffect* fPathEffect; + friend class SkShape1DPathEffect; + friend class SkShape2DPathEffect; +}; + +class SkDrawShape1DPathEffect : public SkDrawShapePathEffect { + DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape1DPathEffect); + SkDrawShape1DPathEffect(SkDisplayTypes ); + virtual ~SkDrawShape1DPathEffect(); + virtual void onEndElement(SkAnimateMaker& ); +private: + SkString phase; + SkString spacing; + friend class SkShape1DPathEffect; + typedef SkDrawShapePathEffect INHERITED; +}; + +class SkDrawShape2DPathEffect : public SkDrawShapePathEffect { + DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape2DPathEffect); + SkDrawShape2DPathEffect(SkDisplayTypes ); + virtual ~SkDrawShape2DPathEffect(); + virtual void onEndElement(SkAnimateMaker& ); +private: + SkDrawMatrix* matrix; + friend class SkShape2DPathEffect; + typedef SkDrawShapePathEffect INHERITED; +}; + +class SkDrawComposePathEffect : public SkDrawPathEffect { + DECLARE_EXTRAS_MEMBER_INFO(SkDrawComposePathEffect); + SkDrawComposePathEffect(SkDisplayTypes ); + virtual ~SkDrawComposePathEffect(); + virtual bool add(SkAnimateMaker& , SkDisplayable* ); + virtual SkPathEffect* getPathEffect(); + virtual bool isPaint() const; +private: + SkDrawPathEffect* effect1; + SkDrawPathEffect* effect2; +}; + +class SkDrawCornerPathEffect : public SkDrawPathEffect { + DECLARE_EXTRAS_MEMBER_INFO(SkDrawCornerPathEffect); + SkDrawCornerPathEffect(SkDisplayTypes ); + virtual ~SkDrawCornerPathEffect(); + virtual SkPathEffect* getPathEffect(); +private: + SkScalar radius; +}; + +//////////// SkShape1DPathEffect + +#include "SkAnimateMaker.h" +#include "SkAnimatorScript.h" +#include "SkDisplayApply.h" +#include "SkDrawMatrix.h" +#include "SkPaint.h" + +class SkShape1DPathEffect : public Sk1DPathEffect { +public: + SkShape1DPathEffect(SkDrawShape1DPathEffect* draw, SkAnimateMaker* maker) : + fDraw(draw), fMaker(maker) { + } + +protected: + virtual SkScalar begin(SkScalar contourLength) + { + SkScriptValue value; + SkAnimatorScript engine(*fMaker, nil, SkType_Float); + engine.propertyCallBack(GetContourLength, &contourLength); + value.fOperand.fScalar = 0; + engine.evaluate(fDraw->phase.c_str(), &value, SkType_Float); + return value.fOperand.fScalar; + } + + virtual SkScalar next(SkScalar distance, const SkMatrix& mat, SkPath* dst) + { + fMaker->setExtraPropertyCallBack(fDraw->fType, GetDistance, &distance); + SkDrawPath* drawPath = nil; + if (fDraw->addPath->isPath()) { + drawPath = (SkDrawPath*) fDraw->addPath; + } else { + SkApply* apply = (SkApply*) fDraw->addPath; + apply->refresh(*fMaker); + apply->activate(*fMaker); + apply->interpolate(*fMaker, SkScalarMulRound(distance, 1000)); + drawPath = (SkDrawPath*) apply->getScope(); + } + SkMatrix m(mat); + if (fDraw->addMatrix) { + SkDrawMatrix* matrix; + if (fDraw->addMatrix->getType() == SkType_Matrix) + matrix = (SkDrawMatrix*) fDraw->addMatrix; + else { + SkApply* apply = (SkApply*) fDraw->addMatrix; + apply->refresh(*fMaker); + apply->activate(*fMaker); + apply->interpolate(*fMaker, SkScalarMulRound(distance, 1000)); + matrix = (SkDrawMatrix*) apply->getScope(); + } + } + SkScalar result = 0; + SkAnimatorScript::EvaluateFloat(*fMaker, nil, fDraw->spacing.c_str(), &result); + if (drawPath) + dst->addPath(drawPath->getPath(), m); + fMaker->clearExtraPropertyCallBack(fDraw->fType); + return result; + } + +private: + + static bool GetContourLength(const char* token, size_t len, void* clen, SkScriptValue* value) { + if (SK_LITERAL_STR_EQUAL("contourLength", token, len)) { + value->fOperand.fScalar = *(SkScalar*) clen; + value->fType = SkType_Float; + return true; + } + return false; + } + + static bool GetDistance(const char* token, size_t len, void* dist, SkScriptValue* value) { + if (SK_LITERAL_STR_EQUAL("distance", token, len)) { + value->fOperand.fScalar = *(SkScalar*) dist; + value->fType = SkType_Float; + return true; + } + return false; + } + + SkDrawShape1DPathEffect* fDraw; + SkAnimateMaker* fMaker; +}; + +//////////// SkDrawShapePathEffect + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawShapePathEffect::fInfo[] = { + SK_MEMBER(addMatrix, Drawable), // either matrix or apply + SK_MEMBER(addPath, Drawable), // either path or apply + SK_MEMBER(path, Path), +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawShapePathEffect); + +SkDrawShapePathEffect::SkDrawShapePathEffect() : + addPath(nil), addMatrix(nil), path(nil), fPathEffect(nil) { +} + +SkDrawShapePathEffect::~SkDrawShapePathEffect() { + fPathEffect->safeUnref(); +} + +bool SkDrawShapePathEffect::add(SkAnimateMaker& , SkDisplayable* child) { + path = (SkDrawPath*) child; + return true; +} + +SkPathEffect* SkDrawShapePathEffect::getPathEffect() { + fPathEffect->ref(); + return fPathEffect; +} + +//////////// SkDrawShape1DPathEffect + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawShape1DPathEffect::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER(phase, String), + SK_MEMBER(spacing, String), +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawShape1DPathEffect); + +SkDrawShape1DPathEffect::SkDrawShape1DPathEffect(SkDisplayTypes type) : fType(type) { +} + +SkDrawShape1DPathEffect::~SkDrawShape1DPathEffect() { +} + +void SkDrawShape1DPathEffect::onEndElement(SkAnimateMaker& maker) { + if (addPath == nil || (addPath->isPath() == false && addPath->isApply() == false)) + maker.setErrorCode(SkDisplayXMLParserError::kUnknownError); // !!! add error + else + fPathEffect = new SkShape1DPathEffect(this, &maker); +} + +////////// SkShape2DPathEffect + +class SkShape2DPathEffect : public Sk2DPathEffect { +public: + SkShape2DPathEffect(SkDrawShape2DPathEffect* draw, SkAnimateMaker* maker, + const SkMatrix& matrix) : Sk2DPathEffect(matrix), fDraw(draw), fMaker(maker) { + } + +protected: + virtual void begin(const SkRect16& uvBounds, SkPath* ) + { + fUVBounds.set(SkIntToScalar(uvBounds.fLeft), SkIntToScalar(uvBounds.fTop), + SkIntToScalar(uvBounds.fRight), SkIntToScalar(uvBounds.fBottom)); + } + + virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) + { + fLoc = loc; + fU = u; + fV = v; + SkDrawPath* drawPath; + fMaker->setExtraPropertyCallBack(fDraw->fType, Get2D, this); + if (fDraw->addPath->isPath()) { + drawPath = (SkDrawPath*) fDraw->addPath; + } else { + SkApply* apply = (SkApply*) fDraw->addPath; + apply->refresh(*fMaker); + apply->activate(*fMaker); + apply->interpolate(*fMaker, v); + drawPath = (SkDrawPath*) apply->getScope(); + } + if (drawPath == nil) + goto clearCallBack; + if (fDraw->matrix) { + SkDrawMatrix* matrix; + if (fDraw->matrix->getType() == SkType_Matrix) + matrix = (SkDrawMatrix*) fDraw->matrix; + else { + SkApply* apply = (SkApply*) fDraw->matrix; + apply->activate(*fMaker); + apply->interpolate(*fMaker, v); + matrix = (SkDrawMatrix*) apply->getScope(); + } + if (matrix) { + dst->addPath(drawPath->getPath(), matrix->getMatrix()); + goto clearCallBack; + } + } + dst->addPath(drawPath->getPath()); +clearCallBack: + fMaker->clearExtraPropertyCallBack(fDraw->fType); + } + +private: + + static bool Get2D(const char* token, size_t len, void* s2D, SkScriptValue* value) { + static const char match[] = "locX|locY|left|top|right|bottom|u|v" ; + SkShape2DPathEffect* shape2D = (SkShape2DPathEffect*) s2D; + int index; + if (SkAnimatorScript::MapEnums(match, token, len, &index) == false) + return false; + SkASSERT((sizeof(SkPoint) + sizeof(SkRect)) / sizeof(SkScalar) == 6); + if (index < 6) { + value->fType = SkType_Float; + value->fOperand.fScalar = (&shape2D->fLoc.fX)[index]; + } else { + value->fType = SkType_Int; + value->fOperand.fS32 = (&shape2D->fU)[index - 6]; + } + return true; + } + + SkPoint fLoc; + SkRect fUVBounds; + S32 fU; + S32 fV; + SkDrawShape2DPathEffect* fDraw; + SkAnimateMaker* fMaker; + + // illegal + SkShape2DPathEffect(const SkShape2DPathEffect&); + SkShape2DPathEffect& operator=(const SkShape2DPathEffect&); +}; + +////////// SkDrawShape2DPathEffect + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawShape2DPathEffect::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER(matrix, Matrix) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawShape2DPathEffect); + +SkDrawShape2DPathEffect::SkDrawShape2DPathEffect(SkDisplayTypes type) : fType(type) { +} + +SkDrawShape2DPathEffect::~SkDrawShape2DPathEffect() { +} + +void SkDrawShape2DPathEffect::onEndElement(SkAnimateMaker& maker) { + if (addPath == nil || (addPath->isPath() == false && addPath->isApply() == false) || + matrix == nil) + maker.setErrorCode(SkDisplayXMLParserError::kUnknownError); // !!! add error + else + fPathEffect = new SkShape2DPathEffect(this, &maker, matrix->getMatrix()); +} + +////////// SkDrawComposePathEffect + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawComposePathEffect::fInfo[] = { + SK_MEMBER(effect1, PathEffect), + SK_MEMBER(effect2, PathEffect) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawComposePathEffect); + +SkDrawComposePathEffect::SkDrawComposePathEffect(SkDisplayTypes type) : fType(type), + effect1(nil), effect2(nil) { +} + +SkDrawComposePathEffect::~SkDrawComposePathEffect() { + delete effect1; + delete effect2; +} + +bool SkDrawComposePathEffect::add(SkAnimateMaker& , SkDisplayable* child) { + if (effect1 == nil) + effect1 = (SkDrawPathEffect*) child; + else + effect2 = (SkDrawPathEffect*) child; + return true; +} + +SkPathEffect* SkDrawComposePathEffect::getPathEffect() { + SkPathEffect* e1 = effect1->getPathEffect(); + SkPathEffect* e2 = effect2->getPathEffect(); + SkPathEffect* composite = new SkComposePathEffect(e1, e2); + e1->unref(); + e2->unref(); + return composite; +} + +bool SkDrawComposePathEffect::isPaint() const { + return true; +} + +//////////// SkDrawCornerPathEffect + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawCornerPathEffect::fInfo[] = { + SK_MEMBER(radius, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawCornerPathEffect); + +SkDrawCornerPathEffect::SkDrawCornerPathEffect(SkDisplayTypes type): + fType(type), radius(0) { +} + +SkDrawCornerPathEffect::~SkDrawCornerPathEffect() { +} + +SkPathEffect* SkDrawCornerPathEffect::getPathEffect() { + return new SkCornerPathEffect(radius); +} + +///////// + +#include "SkExtras.h" + +const char kDrawShape1DPathEffectName[] = "pathEffect:shape1D"; +const char kDrawShape2DPathEffectName[] = "pathEffect:shape2D"; +const char kDrawComposePathEffectName[] = "pathEffect:compose"; +const char kDrawCornerPathEffectName[] = "pathEffect:corner"; + +class SkExtraPathEffects : public SkExtras { +public: + SkExtraPathEffects(SkAnimator* animator) : + skDrawShape1DPathEffectType(SkType_Unknown), + skDrawShape2DPathEffectType(SkType_Unknown), + skDrawComposePathEffectType(SkType_Unknown), + skDrawCornerPathEffectType(SkType_Unknown) { + } + + virtual SkDisplayable* createInstance(SkDisplayTypes type) { + SkDisplayable* result = nil; + if (skDrawShape1DPathEffectType == type) + result = new SkDrawShape1DPathEffect(type); + else if (skDrawShape2DPathEffectType == type) + result = new SkDrawShape2DPathEffect(type); + else if (skDrawComposePathEffectType == type) + result = new SkDrawComposePathEffect(type); + else if (skDrawCornerPathEffectType == type) + result = new SkDrawCornerPathEffect(type); + return result; + } + + virtual bool definesType(SkDisplayTypes type) { + return type == skDrawShape1DPathEffectType || + type == skDrawShape2DPathEffectType || + type == skDrawComposePathEffectType || + type == skDrawCornerPathEffectType; + } + +#if SK_USE_CONDENSED_INFO == 0 + virtual const SkMemberInfo* getMembers(SkDisplayTypes type, int* infoCountPtr) { + const SkMemberInfo* info = nil; + int infoCount = 0; + if (skDrawShape1DPathEffectType == type) { + info = SkDrawShape1DPathEffect::fInfo; + infoCount = SkDrawShape1DPathEffect::fInfoCount; + } else if (skDrawShape2DPathEffectType == type) { + info = SkDrawShape2DPathEffect::fInfo; + infoCount = SkDrawShape2DPathEffect::fInfoCount; + } else if (skDrawComposePathEffectType == type) { + info = SkDrawComposePathEffect::fInfo; + infoCount = SkDrawShape1DPathEffect::fInfoCount; + } else if (skDrawCornerPathEffectType == type) { + info = SkDrawCornerPathEffect::fInfo; + infoCount = SkDrawCornerPathEffect::fInfoCount; + } + if (infoCountPtr) + *infoCountPtr = infoCount; + return info; + } +#endif + +#ifdef SK_DEBUG + virtual const char* getName(SkDisplayTypes type) { + if (skDrawShape1DPathEffectType == type) + return kDrawShape1DPathEffectName; + else if (skDrawShape2DPathEffectType == type) + return kDrawShape2DPathEffectName; + else if (skDrawComposePathEffectType == type) + return kDrawComposePathEffectName; + else if (skDrawCornerPathEffectType == type) + return kDrawCornerPathEffectName; + return NULL; + } +#endif + + virtual SkDisplayTypes getType(const char name[], size_t len ) { + SkDisplayTypes* type = nil; + if (SK_LITERAL_STR_EQUAL(kDrawShape1DPathEffectName, name, len)) + type = &skDrawShape1DPathEffectType; + else if (SK_LITERAL_STR_EQUAL(kDrawShape2DPathEffectName, name, len)) + type = &skDrawShape2DPathEffectType; + else if (SK_LITERAL_STR_EQUAL(kDrawComposePathEffectName, name, len)) + type = &skDrawComposePathEffectType; + else if (SK_LITERAL_STR_EQUAL(kDrawCornerPathEffectName, name, len)) + type = &skDrawCornerPathEffectType; + if (type) { + if (*type == SkType_Unknown) + *type = SkDisplayType::RegisterNewType(); + return *type; + } + return SkType_Unknown; + } + +private: + SkDisplayTypes skDrawShape1DPathEffectType; + SkDisplayTypes skDrawShape2DPathEffectType; + SkDisplayTypes skDrawComposePathEffectType; + SkDisplayTypes skDrawCornerPathEffectType; +}; + + +void InitializeSkExtraPathEffects(SkAnimator* animator) { + animator->addExtras(new SkExtraPathEffects(animator)); +} + +//////////////// + + +SkExtras::SkExtras() : fExtraCallBack(nil), fExtraStorage(nil) { +} diff --git a/libs/graphics/animator/SkDrawFull.cpp b/libs/graphics/animator/SkDrawFull.cpp new file mode 100644 index 0000000000..3bf27d9124 --- /dev/null +++ b/libs/graphics/animator/SkDrawFull.cpp @@ -0,0 +1,10 @@ +#include "SkDrawFull.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" + +bool SkFull::draw(SkAnimateMaker& maker) { + SkBoundableAuto boundable(this, maker); + maker.fCanvas->drawPaint(*maker.fPaint); + return false; +} + diff --git a/libs/graphics/animator/SkDrawFull.h b/libs/graphics/animator/SkDrawFull.h new file mode 100644 index 0000000000..8822b0266b --- /dev/null +++ b/libs/graphics/animator/SkDrawFull.h @@ -0,0 +1,13 @@ +#ifndef SkDrawFull_DEFINED +#define SkDrawFull_DEFINED + +#include "SkBoundable.h" + +class SkFull : public SkBoundable { + DECLARE_EMPTY_MEMBER_INFO(Full); + virtual bool draw(SkAnimateMaker& ); +private: + typedef SkBoundable INHERITED; +}; + +#endif // SkDrawFull_DEFINED diff --git a/libs/graphics/animator/SkDrawGradient.cpp b/libs/graphics/animator/SkDrawGradient.cpp new file mode 100644 index 0000000000..ae40728d25 --- /dev/null +++ b/libs/graphics/animator/SkDrawGradient.cpp @@ -0,0 +1,214 @@ +#include "SkDrawGradient.h" +#include "SkAnimateMaker.h" +#include "SkAnimatorScript.h" +#include "SkGradientShader.h" +#include "SkUnitMapper.h" + +SkScalar SkUnitToScalar(U16CPU x) { +#ifdef SK_SCALAR_IS_FLOAT + return x / 65535.0f; +#else + return x + (x >> 8); +#endif +} + +U16CPU SkScalarToUnit(SkScalar x) { + SkScalar pin = SkScalarPin(x, 0, SK_Scalar1); +#ifdef SK_SCALAR_IS_FLOAT + return (int) (pin * 65535.0f); +#else + return pin - (pin >= 32768); +#endif +} + +class SkGradientUnitMapper : public SkUnitMapper { +public: + SkGradientUnitMapper(SkAnimateMaker* maker, const char* script) : fMaker(maker), fScript(script) { + } +protected: + virtual U16CPU mapUnit16(U16CPU x) { + fUnit = SkUnitToScalar(x); + SkScriptValue value; + SkAnimatorScript engine(*fMaker, nil, SkType_Float); + engine.propertyCallBack(GetUnitValue, &fUnit); + if (engine.evaluate(fScript, &value, SkType_Float)) + x = SkScalarToUnit(value.fOperand.fScalar); + return x; + } + + static bool GetUnitValue(const char* token, size_t len, void* unitPtr, SkScriptValue* value) { + if (SK_LITERAL_STR_EQUAL("unit", token, len)) { + value->fOperand.fScalar = *(SkScalar*) unitPtr; + value->fType = SkType_Float; + return true; + } + return false; + } + + SkAnimateMaker* fMaker; + const char* fScript; + SkScalar fUnit; +}; + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkGradient::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER_ARRAY(offsets, Float), + SK_MEMBER(unitMapper, String) +}; + +#endif + +DEFINE_GET_MEMBER(SkGradient); + +SkGradient::SkGradient() : fUnitMapper(nil) { +} + +SkGradient::~SkGradient() { + for (int index = 0; index < fDrawColors.count(); index++) + delete fDrawColors[index]; + delete fUnitMapper; +} + +bool SkGradient::add(SkAnimateMaker& , SkDisplayable* child) { + SkASSERT(child); + if (child->isColor()) { + SkDrawColor* color = (SkDrawColor*) child; + *fDrawColors.append() = color; + return true; + } + return false; +} + +int SkGradient::addPrelude() { + int count = fDrawColors.count(); + fColors.setCount(count); + for (int index = 0; index < count; index++) + fColors[index] = fDrawColors[index]->color; + return count; +} + +#ifdef SK_DUMP_ENABLED +void SkGradient::dumpRest(SkAnimateMaker* maker) { + dumpAttrs(maker); + //can a gradient have no colors? + bool closedYet = false; + SkDisplayList::fIndent += 4; + for (SkDrawColor** ptr = fDrawColors.begin(); ptr < fDrawColors.end(); ptr++) { + if (closedYet == false) { + SkDebugf(">\n"); + closedYet = true; + } + SkDrawColor* color = *ptr; + color->dump(maker); + } + SkDisplayList::fIndent -= 4; + dumpChildren(maker, closedYet); //dumps the matrix if it has one +} +#endif + +void SkGradient::onEndElement(SkAnimateMaker& maker) { + if (offsets.count() != 0) { + if (offsets.count() != fDrawColors.count()) { + maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsDontMatchColors); + return; + } + if (offsets[0] != 0) { + maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustStartWithZero); + return; + } + if (offsets[offsets.count()-1] != SK_Scalar1) { + maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustEndWithOne); + return; + } + for (int i = 1; i < offsets.count(); i++) { + if (offsets[i] <= offsets[i-1]) { + maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustIncrease); + return; + } + if (offsets[i] > SK_Scalar1) { + maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustBeNoMoreThanOne); + return; + } + } + } + if (unitMapper.size() > 0) + fUnitMapper = new SkGradientUnitMapper(&maker, unitMapper.c_str()); + INHERITED::onEndElement(maker); +} + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkLinearGradient::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER_ARRAY(points, Float), +}; + +#endif + +DEFINE_GET_MEMBER(SkLinearGradient); + +SkLinearGradient::SkLinearGradient() { +} + +void SkLinearGradient::onEndElement(SkAnimateMaker& maker) +{ + if (points.count() != 4) + maker.setErrorCode(SkDisplayXMLParserError::kGradientPointsLengthMustBeFour); + INHERITED::onEndElement(maker); +} + +#ifdef SK_DUMP_ENABLED +void SkLinearGradient::dump(SkAnimateMaker* maker) { + dumpBase(maker); + dumpRest(maker); + } +#endif + +SkShader* SkLinearGradient::getShader() { + if (addPrelude() == 0 || points.count() != 4) + return nil; + SkShader* shader = SkGradientShader::CreateLinear((SkPoint*)points.begin(), + fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, fUnitMapper); + SkAutoTDelete<SkShader> autoDel(shader); + addPostlude(shader); + (void)autoDel.detach(); + return shader; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkRadialGradient::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER(center, Point), + SK_MEMBER(radius, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkRadialGradient); + +SkRadialGradient::SkRadialGradient() : radius(0) { + center.set(0, 0); +} + +#ifdef SK_DUMP_ENABLED +void SkRadialGradient::dump(SkAnimateMaker* maker) { + dumpBase(maker); + dumpRest(maker); +} +#endif + +SkShader* SkRadialGradient::getShader() { + if (addPrelude() == 0) + return nil; + SkShader* shader = SkGradientShader::CreateRadial(center, + radius, fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, fUnitMapper); + SkAutoTDelete<SkShader> autoDel(shader); + addPostlude(shader); + (void)autoDel.detach(); + return shader; +} diff --git a/libs/graphics/animator/SkDrawGradient.h b/libs/graphics/animator/SkDrawGradient.h new file mode 100644 index 0000000000..2940b76142 --- /dev/null +++ b/libs/graphics/animator/SkDrawGradient.h @@ -0,0 +1,59 @@ +#ifndef SkDrawGradient_DEFINED +#define SkDrawGradient_DEFINED + +#include "SkDrawColor.h" +#include "SkDrawShader.h" +#include "SkIntArray.h" + +class SkUnitMapper; + +class SkGradient : public SkDrawShader { + DECLARE_PRIVATE_MEMBER_INFO(Gradient); + SkGradient(); + virtual ~SkGradient(); + virtual bool add(SkAnimateMaker& , SkDisplayable* child); +#ifdef SK_DUMP_ENABLED + virtual void dumpRest(SkAnimateMaker*); +#endif + virtual void onEndElement(SkAnimateMaker& ); +protected: + SkTDScalarArray offsets; + SkString unitMapper; + SkTDColorArray fColors; + SkTDDrawColorArray fDrawColors; + SkUnitMapper* fUnitMapper; + int addPrelude(); +private: + typedef SkDrawShader INHERITED; +}; + +class SkLinearGradient : public SkGradient { + DECLARE_MEMBER_INFO(LinearGradient); + SkLinearGradient(); + virtual void onEndElement(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker*); +#endif + virtual SkShader* getShader(); +protected: + SkTDScalarArray points; +private: + typedef SkGradient INHERITED; +}; + +class SkRadialGradient : public SkGradient { + DECLARE_MEMBER_INFO(RadialGradient); + SkRadialGradient(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker*); +#endif + virtual SkShader* getShader(); +protected: + SkPoint center; + SkScalar radius; +private: + typedef SkGradient INHERITED; +}; + +#endif // SkDrawGradient_DEFINED + diff --git a/libs/graphics/animator/SkDrawGroup.cpp b/libs/graphics/animator/SkDrawGroup.cpp new file mode 100644 index 0000000000..89232dd223 --- /dev/null +++ b/libs/graphics/animator/SkDrawGroup.cpp @@ -0,0 +1,314 @@ +#include "SkDrawGroup.h" +#include "SkAnimateMaker.h" +#include "SkAnimatorScript.h" +#include "SkCanvas.h" +#include "SkDisplayApply.h" +#include "SkPaint.h" +#ifdef SK_DEBUG +#include "SkDisplayList.h" +#endif + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkGroup::fInfo[] = { + SK_MEMBER(condition, String), + SK_MEMBER(enableCondition, String) +}; + +#endif + +DEFINE_GET_MEMBER(SkGroup); + +SkGroup::SkGroup() : fParentList(nil), fOriginal(nil) { +} + +SkGroup::~SkGroup() { + if (fOriginal) // has been copied + return; + int index = 0; + int max = fCopies.count() << 5; + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + if (index >= max || markedForDelete(index)) + delete *ptr; +// else { +// SkApply* apply = (SkApply*) *ptr; +// SkASSERT(apply->isApply()); +// SkASSERT(apply->getScope()); +// delete apply->getScope(); +// } + index++; + } +} + +bool SkGroup::add(SkAnimateMaker& , SkDisplayable* child) { + SkASSERT(child); +// SkASSERT(child->isDrawable()); + *fChildren.append() = (SkDrawable*) child; + if (child->isGroup()) { + SkGroup* groupie = (SkGroup*) child; + SkASSERT(groupie->fParentList == nil); + groupie->fParentList = &fChildren; + } + return true; +} + +bool SkGroup::contains(SkDisplayable* match) { + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + SkDrawable* drawable = *ptr; + if (drawable == match || drawable->contains(match)) + return true; + } + return false; +} + +SkGroup* SkGroup::copy() { + SkGroup* result = new SkGroup(); + result->fOriginal = this; + result->fChildren = fChildren; + return result; +} + +SkBool SkGroup::copySet(int index) { + return (fCopies[index >> 5] & 1 << (index & 0x1f)) != 0; +} + +SkDisplayable* SkGroup::deepCopy(SkAnimateMaker* maker) { + SkDisplayable* copy = INHERITED::deepCopy(maker); + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + SkDisplayable* displayable = (SkDisplayable*)*ptr; + SkDisplayable* deeperCopy = displayable->deepCopy(maker); + ((SkGroup*)copy)->add(*maker, deeperCopy); + } + return copy; +} + +bool SkGroup::doEvent(SkDisplayEvent::Kind kind, SkEventState* state) { + bool handled = false; + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + SkDrawable* drawable = *ptr; + if (drawable->isDrawable() == false) + continue; + handled |= drawable->doEvent(kind, state); + } + return handled; +} + +bool SkGroup::draw(SkAnimateMaker& maker) { + bool conditionTrue = ifCondition(maker, this, condition); + bool result = false; + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + SkDrawable* drawable = *ptr; + if (drawable->isDrawable() == false) + continue; + if (conditionTrue == false) { + if (drawable->isApply()) + ((SkApply*) drawable)->disable(); + continue; + } + maker.validate(); + result |= drawable->draw(maker); + maker.validate(); + } + return result; +} + +#ifdef SK_DUMP_ENABLED +void SkGroup::dump(SkAnimateMaker* maker) { + dumpBase(maker); + if (condition.size() > 0) + SkDebugf("condition=\"%s\" ", condition.c_str()); + if (enableCondition.size() > 0) + SkDebugf("enableCondition=\"%s\" ", enableCondition.c_str()); + dumpDrawables(maker); +} + +void SkGroup::dumpDrawables(SkAnimateMaker* maker) { + SkDisplayList::fIndent += 4; + int save = SkDisplayList::fDumpIndex; + SkDisplayList::fDumpIndex = 0; + bool closedYet = false; + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + if (closedYet == false) { + closedYet = true; + SkDebugf(">\n"); + } + SkDrawable* drawable = *ptr; + drawable->dump(maker); + SkDisplayList::fDumpIndex++; + } + SkDisplayList::fIndent -= 4; + SkDisplayList::fDumpIndex = save; + if (closedYet) //we had children, now it's time to close the group + dumpEnd(maker); + else //no children + SkDebugf("/>\n"); +} + +void SkGroup::dumpEvents() { + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + SkDrawable* drawable = *ptr; + drawable->dumpEvents(); + } +} +#endif + +bool SkGroup::enable(SkAnimateMaker& maker ) { + reset(); + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + SkDrawable* drawable = *ptr; + if (ifCondition(maker, drawable, enableCondition) == false) + continue; + drawable->enable(maker); + } + return true; // skip add; already added so that scope is findable by children +} + +int SkGroup::findGroup(SkDrawable* match, SkTDDrawableArray** list, + SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList) { + *list = &fChildren; + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + SkDrawable* drawable = *ptr; + if (drawable->isGroup()) { + SkGroup* childGroup = (SkGroup*) drawable; + if (childGroup->fOriginal == match) + goto foundMatch; + } + if (drawable == match) { +foundMatch: + *parent = this; + return (int) (ptr - fChildren.begin()); + } + } + *grandList = &fChildren; + return SkDisplayList::SearchForMatch(match, list, parent, found, grandList); +} + +bool SkGroup::hasEnable() const { + return true; +} + +bool SkGroup::ifCondition(SkAnimateMaker& maker, SkDrawable* drawable, + SkString& conditionString) { + if (conditionString.size() == 0) + return true; + int32_t result; + bool success = SkAnimatorScript::EvaluateInt(maker, this, conditionString.c_str(), &result); +#ifdef SK_DUMP_ENABLED + if (maker.fDumpGConditions) { + SkDebugf("group: "); + dumpBase(&maker); + SkDebugf("condition=%s ", conditionString.c_str()); + if (success == false) + SkDebugf("(script failed)\n"); + else + SkDebugf("success=%s\n", result != 0 ? "true" : "false"); + } +#endif + return success && result != 0; +} + +void SkGroup::initialize() { + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + SkDrawable* drawable = *ptr; + if (drawable->isDrawable() == false) + continue; + drawable->initialize(); + } +} + +void SkGroup::markCopyClear(int index) { + if (index < 0) + index = fChildren.count(); + fCopies[index >> 5] &= ~(1 << (index & 0x1f)); +} + +void SkGroup::markCopySet(int index) { + if (index < 0) + index = fChildren.count(); + fCopies[index >> 5] |= 1 << (index & 0x1f); +} + +void SkGroup::markCopySize(int index) { + if (index < 0) + index = fChildren.count() + 1; + int oldLongs = fCopies.count(); + int newLongs = (index >> 5) + 1; + if (oldLongs < newLongs) { + fCopies.setCount(newLongs); + memset(&fCopies[oldLongs], 0, (newLongs - oldLongs) << 2); + } +} + +void SkGroup::reset() { + if (fOriginal) // has been copied + return; + int index = 0; + int max = fCopies.count() << 5; + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + if (index >= max || copySet(index) == false) + continue; + SkApply* apply = (SkApply*) *ptr; + SkASSERT(apply->isApply()); + SkASSERT(apply->getScope()); + *ptr = apply->getScope(); + markCopyClear(index); + index++; + } +} + +bool SkGroup::resolveIDs(SkAnimateMaker& maker, SkDisplayable* orig, SkApply* apply) { + SkGroup* original = (SkGroup*) orig; + SkTDDrawableArray& originalChildren = original->fChildren; + SkDrawable** originalPtr = originalChildren.begin(); + SkDrawable** ptr = fChildren.begin(); + SkDrawable** end = fChildren.end(); + SkDrawable** origChild = ((SkGroup*) orig)->fChildren.begin(); + while (ptr < end) { + SkDrawable* drawable = *ptr++; + maker.resolveID(drawable, *origChild++); + if (drawable->resolveIDs(maker, *originalPtr++, apply) == true) + return true; // failed + } + return false; +} + +void SkGroup::setSteps(int steps) { + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + SkDrawable* drawable = *ptr; + if (drawable->isDrawable() == false) + continue; + drawable->setSteps(steps); + } +} + +#ifdef SK_DEBUG +void SkGroup::validate() { + for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) { + SkDrawable* drawable = *ptr; + drawable->validate(); + } +} +#endif + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkSave::fInfo[] = { + SK_MEMBER_INHERITED +}; + +#endif + +DEFINE_GET_MEMBER(SkSave); + +bool SkSave::draw(SkAnimateMaker& maker) { + maker.fCanvas->save(); + SkPaint* save = maker.fPaint; + SkPaint local = SkPaint(*maker.fPaint); + maker.fPaint = &local; + bool result = INHERITED::draw(maker); + maker.fPaint = save; + maker.fCanvas->restore(); + return result; +} + + diff --git a/libs/graphics/animator/SkDrawGroup.h b/libs/graphics/animator/SkDrawGroup.h new file mode 100644 index 0000000000..45e3a43b90 --- /dev/null +++ b/libs/graphics/animator/SkDrawGroup.h @@ -0,0 +1,63 @@ +#ifndef SkDrawGroup_DEFINED +#define SkDrawGroup_DEFINED + +#include "SkDrawable.h" +#include "SkIntArray.h" +#include "SkMemberInfo.h" + +class SkGroup : public SkDrawable { //interface for schema element <g> +public: + DECLARE_MEMBER_INFO(Group); + SkGroup(); + virtual ~SkGroup(); + virtual bool add(SkAnimateMaker& , SkDisplayable* child); + virtual bool contains(SkDisplayable* ); + SkGroup* copy(); + SkBool copySet(int index); + virtual SkDisplayable* deepCopy(SkAnimateMaker* ); + virtual bool doEvent(SkDisplayEvent::Kind , SkEventState* state ); + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); + virtual void dumpDrawables(SkAnimateMaker* ); + virtual void dumpEvents(); +#endif + int findGroup(SkDrawable* drawable, SkTDDrawableArray** list, + SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList); + virtual bool enable(SkAnimateMaker& ); + SkTDDrawableArray* getChildren() { return &fChildren; } + SkGroup* getOriginal() { return fOriginal; } + virtual bool hasEnable() const; + virtual void initialize(); + SkBool isACopy() { return fOriginal != nil; } + void markCopyClear(int index); + void markCopySet(int index); + void markCopySize(int index); + bool markedForDelete(int index) const { return (fCopies[index >> 5] & 1 << (index & 0x1f)) == 0; } + void reset(); + bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* ); + virtual void setSteps(int steps); +#ifdef SK_DEBUG + virtual void validate(); +#endif +protected: + bool ifCondition(SkAnimateMaker& maker, SkDrawable* drawable, + SkString& conditionString); + SkString condition; + SkString enableCondition; + SkTDDrawableArray fChildren; + SkTDDrawableArray* fParentList; + SkTDIntArray fCopies; + SkGroup* fOriginal; +private: + typedef SkDrawable INHERITED; +}; + +class SkSave: public SkGroup { + DECLARE_MEMBER_INFO(Save); + virtual bool draw(SkAnimateMaker& ); +private: + typedef SkGroup INHERITED; +}; + +#endif // SkDrawGroup_DEFINED diff --git a/libs/graphics/animator/SkDrawLine.cpp b/libs/graphics/animator/SkDrawLine.cpp new file mode 100644 index 0000000000..3c38fbe822 --- /dev/null +++ b/libs/graphics/animator/SkDrawLine.cpp @@ -0,0 +1,28 @@ +#include "SkDrawLine.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkPaint.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkLine::fInfo[] = { + SK_MEMBER(x1, Float), + SK_MEMBER(x2, Float), + SK_MEMBER(y1, Float), + SK_MEMBER(y2, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkLine); + +SkLine::SkLine() : x1(0), x2(0), y1(0), y2(0) { +} + +bool SkLine::draw(SkAnimateMaker& maker) { + SkPoint start = {x1, y1}; + SkPoint stop = {x2, y2}; + SkBoundableAuto boundable(this, maker); + maker.fCanvas->drawLine(start, stop, *maker.fPaint); + return false; +} diff --git a/libs/graphics/animator/SkDrawLine.h b/libs/graphics/animator/SkDrawLine.h new file mode 100644 index 0000000000..682c7ee269 --- /dev/null +++ b/libs/graphics/animator/SkDrawLine.h @@ -0,0 +1,20 @@ +#ifndef SkDrawLine_DEFINED +#define SkDrawLine_DEFINED + +#include "SkBoundable.h" +#include "SkMemberInfo.h" + +class SkLine : public SkBoundable { + DECLARE_MEMBER_INFO(Line); + SkLine(); + virtual bool draw(SkAnimateMaker& ); +private: + SkScalar x1; + SkScalar x2; + SkScalar y1; + SkScalar y2; + typedef SkBoundable INHERITED; +}; + +#endif // SkDrawLine_DEFINED + diff --git a/libs/graphics/animator/SkDrawMatrix.cpp b/libs/graphics/animator/SkDrawMatrix.cpp new file mode 100644 index 0000000000..18b30e6fec --- /dev/null +++ b/libs/graphics/animator/SkDrawMatrix.cpp @@ -0,0 +1,273 @@ +#include "SkDrawMatrix.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkParse.h" +#include "SkMatrixParts.h" +#include "SkScript.h" +#include "SkTypedArray.h" + +enum SkDrawMatrix_Properties { + SK_PROPERTY(perspectX), + SK_PROPERTY(perspectY), + SK_PROPERTY(rotate), + SK_PROPERTY(scale), + SK_PROPERTY(scaleX), + SK_PROPERTY(scaleY), + SK_PROPERTY(skewX), + SK_PROPERTY(skewY), + SK_PROPERTY(translate), + SK_PROPERTY(translateX), + SK_PROPERTY(translateY) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawMatrix::fInfo[] = { + SK_MEMBER_ARRAY(matrix, Float), + SK_MEMBER_PROPERTY(perspectX, Float), + SK_MEMBER_PROPERTY(perspectY, Float), + SK_MEMBER_PROPERTY(rotate, Float), + SK_MEMBER_PROPERTY(scale, Float), + SK_MEMBER_PROPERTY(scaleX, Float), + SK_MEMBER_PROPERTY(scaleY, Float), + SK_MEMBER_PROPERTY(skewX, Float), + SK_MEMBER_PROPERTY(skewY, Float), + SK_MEMBER_PROPERTY(translate, Point), + SK_MEMBER_PROPERTY(translateX, Float), + SK_MEMBER_PROPERTY(translateY, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawMatrix); + +SkDrawMatrix::SkDrawMatrix() : fChildHasID(false), fDirty(false) { + fConcat.reset(); + fMatrix.reset(); +} + +SkDrawMatrix::~SkDrawMatrix() { + for (SkMatrixPart** part = fParts.begin(); part < fParts.end(); part++) + delete *part; +} + +bool SkDrawMatrix::add(SkAnimateMaker& maker, SkDisplayable* child) { + SkASSERT(child && child->isMatrixPart()); + SkMatrixPart* part = (SkMatrixPart*) child; + *fParts.append() = part; + if (part->add()) + maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingToMatrix); + return true; +} + +bool SkDrawMatrix::childrenNeedDisposing() const { + return false; +} + +SkDisplayable* SkDrawMatrix::deepCopy(SkAnimateMaker* maker) { + SkDrawMatrix* copy = (SkDrawMatrix*) + SkDisplayType::CreateInstance(maker, SkType_Matrix); + SkASSERT(fParts.count() == 0); + copy->fMatrix = fMatrix; + copy->fConcat = fConcat; + return copy; +} + +void SkDrawMatrix::dirty() { + fDirty = true; +} + +bool SkDrawMatrix::draw(SkAnimateMaker& maker) { + SkMatrix& concat = getMatrix(); + maker.fCanvas->concat(concat); + return false; +} + +#ifdef SK_DUMP_ENABLED +void SkDrawMatrix::dump(SkAnimateMaker* maker) { + dumpBase(maker); + if (fMatrix.isIdentity()) { + SkDebugf("matrix=\"identity\"/>\n"); + return; + } + SkScalar result; + result = fMatrix.getScaleX(); + if (result != SK_Scalar1) + SkDebugf("sx=\"%g\" ", SkScalarToFloat(result)); + result = fMatrix.getScaleY(); + if (result != SK_Scalar1) + SkDebugf("sy=\"%g\" ", SkScalarToFloat(result)); + result = fMatrix.getSkewX(); + if (result) + SkDebugf("skew-x=\"%g\" ", SkScalarToFloat(result)); + result = fMatrix.getSkewY(); + if (result) + SkDebugf("skew-y=\"%g\" ", SkScalarToFloat(result)); + result = fMatrix.getTranslateX(); + if (result) + SkDebugf("tx=\"%g\" ", SkScalarToFloat(result)); + result = fMatrix.getTranslateY(); + if (result) + SkDebugf("ty=\"%g\" ", SkScalarToFloat(result)); + result = fMatrix.getPerspX(); + if (result) + SkDebugf("perspect-x=\"%g\" ", SkScalarToFloat(result)); + result = fMatrix.getPerspY(); + if (result) + SkDebugf("perspect-y=\"%g\" ", SkScalarToFloat(result)); + SkDebugf("/>\n"); +} +#endif + +SkMatrix& SkDrawMatrix::getMatrix() { + if (fDirty == false) + return fConcat; + fMatrix.reset(); + for (SkMatrixPart** part = fParts.begin(); part < fParts.end(); part++) { + (*part)->add(); + fConcat = fMatrix; + } + fDirty = false; + return fConcat; +} + +bool SkDrawMatrix::getProperty(int index, SkScriptValue* value) const { + value->fType = SkType_Float; + SkScalar result; + switch (index) { + case SK_PROPERTY(perspectX): + result = fMatrix.getPerspX(); + break; + case SK_PROPERTY(perspectY): + result = fMatrix.getPerspY(); + break; + case SK_PROPERTY(scaleX): + result = fMatrix.getScaleX(); + break; + case SK_PROPERTY(scaleY): + result = fMatrix.getScaleY(); + break; + case SK_PROPERTY(skewX): + result = fMatrix.getSkewX(); + break; + case SK_PROPERTY(skewY): + result = fMatrix.getSkewY(); + break; + case SK_PROPERTY(translateX): + result = fMatrix.getTranslateX(); + break; + case SK_PROPERTY(translateY): + result = fMatrix.getTranslateY(); + break; + default: +// SkASSERT(0); + return false; + } + value->fOperand.fScalar = result; + return true; +} + +void SkDrawMatrix::initialize() { + fConcat = fMatrix; +} + +void SkDrawMatrix::onEndElement(SkAnimateMaker& ) { + if (matrix.count() > 0) { + SkScalar* vals = matrix.begin(); + fMatrix.setScaleX(vals[0]); + fMatrix.setSkewX(vals[1]); + fMatrix.setTranslateX(vals[2]); + fMatrix.setSkewY(vals[3]); + fMatrix.setScaleY(vals[4]); + fMatrix.setTranslateY(vals[5]); +#ifdef SK_SCALAR_IS_FIXED + fMatrix.setPerspX(SkFixedToFract(vals[6])); + fMatrix.setPerspY(SkFixedToFract(vals[7])); +#else + fMatrix.setPerspX(vals[6]); + fMatrix.setPerspY(vals[7]); +#endif +// fMatrix.setPerspW(vals[8]); + goto setConcat; + } + if (fChildHasID == false) { + { + for (SkMatrixPart** part = fParts.begin(); part < fParts.end(); part++) + delete *part; + } + fParts.reset(); +setConcat: + fConcat = fMatrix; + fDirty = false; + } +} + +void SkDrawMatrix::setChildHasID() { + fChildHasID = true; +} + +bool SkDrawMatrix::setProperty(int index, SkScriptValue& scriptValue) { + SkScalar number = scriptValue.fOperand.fScalar; + switch (index) { + case SK_PROPERTY(translate): + // SkScalar xy[2]; + SkASSERT(scriptValue.fType == SkType_Array); + SkASSERT(scriptValue.fOperand.fArray->getType() == SkType_Float); + SkASSERT(scriptValue.fOperand.fArray->count() == 2); + // SkParse::FindScalars(scriptValue.fOperand.fString->c_str(), xy, 2); + fMatrix.setTranslateX((*scriptValue.fOperand.fArray)[0].fScalar); + fMatrix.setTranslateY((*scriptValue.fOperand.fArray)[1].fScalar); + return true; + case SK_PROPERTY(perspectX): +#ifdef SK_SCALAR_IS_FIXED + fMatrix.setPerspX(SkFixedToFract(number)); +#else + fMatrix.setPerspX(number); +#endif + break; + case SK_PROPERTY(perspectY): +#ifdef SK_SCALAR_IS_FIXED + fMatrix.setPerspY(SkFixedToFract(number)); +#else + fMatrix.setPerspY(number); +#endif + break; + case SK_PROPERTY(rotate): { + SkMatrix temp; + temp.setRotate(number, 0, 0); + fMatrix.setScaleX(temp.getScaleX()); + fMatrix.setScaleY(temp.getScaleY()); + fMatrix.setSkewX(temp.getSkewX()); + fMatrix.setSkewY(temp.getSkewY()); + } break; + case SK_PROPERTY(scale): + fMatrix.setScaleX(number); + fMatrix.setScaleY(number); + break; + case SK_PROPERTY(scaleX): + fMatrix.setScaleX(number); + break; + case SK_PROPERTY(scaleY): + fMatrix.setScaleY(number); + break; + case SK_PROPERTY(skewX): + fMatrix.setSkewX(number); + break; + case SK_PROPERTY(skewY): + fMatrix.setSkewY(number); + break; + case SK_PROPERTY(translateX): + fMatrix.setTranslateX(number); + break; + case SK_PROPERTY(translateY): + fMatrix.setTranslateY(number); + break; + default: + SkASSERT(0); + return false; + } + fConcat = fMatrix; + return true; +} + diff --git a/libs/graphics/animator/SkDrawMatrix.h b/libs/graphics/animator/SkDrawMatrix.h new file mode 100644 index 0000000000..df55292311 --- /dev/null +++ b/libs/graphics/animator/SkDrawMatrix.h @@ -0,0 +1,65 @@ +#ifndef SkDrawMatrix_DEFINED +#define SkDrawMatrix_DEFINED + +#include "SkDrawable.h" +#include "SkMatrix.h" +#include "SkMemberInfo.h" +#include "SkIntArray.h" + +class SkMatrixPart; + +class SkDrawMatrix : public SkDrawable { + DECLARE_DRAW_MEMBER_INFO(Matrix); + SkDrawMatrix(); + virtual ~SkDrawMatrix(); + virtual bool add(SkAnimateMaker& , SkDisplayable* child); + virtual bool childrenNeedDisposing() const; + virtual void dirty(); + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + SkMatrix& getMatrix(); + virtual bool getProperty(int index, SkScriptValue* value) const; + virtual void initialize(); + virtual void onEndElement(SkAnimateMaker& ); + virtual void setChildHasID(); + virtual bool setProperty(int index, SkScriptValue& ); + + void concat(SkMatrix& inMatrix) { + fConcat.preConcat(inMatrix); + } + + virtual SkDisplayable* deepCopy(SkAnimateMaker* ); + + + void rotate(SkScalar degrees, SkPoint& center) { + fMatrix.preRotate(degrees, center.fX, center.fY); + } + + void set(SkMatrix& src) { + fMatrix.preConcat(src); + } + + void scale(SkScalar scaleX, SkScalar scaleY, SkPoint& center) { + fMatrix.preScale(scaleX, scaleY, center.fX, center.fY); + } + + void skew(SkScalar skewX, SkScalar skewY, SkPoint& center) { + fMatrix.preSkew(skewX, skewY, center.fX, center.fY); + } + + void translate(SkScalar x, SkScalar y) { + fMatrix.preTranslate(x, y); + } +private: + SkTDScalarArray matrix; + SkMatrix fConcat; + SkMatrix fMatrix; + SkTDMatrixPartArray fParts; + SkBool8 fChildHasID; + SkBool8 fDirty; + typedef SkDrawable INHERITED; +}; + +#endif // SkDrawMatrix_DEFINED diff --git a/libs/graphics/animator/SkDrawOval.cpp b/libs/graphics/animator/SkDrawOval.cpp new file mode 100644 index 0000000000..11614ebd1c --- /dev/null +++ b/libs/graphics/animator/SkDrawOval.cpp @@ -0,0 +1,20 @@ +#include "SkDrawOval.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkOval::fInfo[] = { + SK_MEMBER_INHERITED, +}; + +#endif + +DEFINE_GET_MEMBER(SkOval); + +bool SkOval::draw(SkAnimateMaker& maker) { + SkBoundableAuto boundable(this, maker); + maker.fCanvas->drawOval(fRect, *maker.fPaint); + return false; +} + diff --git a/libs/graphics/animator/SkDrawOval.h b/libs/graphics/animator/SkDrawOval.h new file mode 100644 index 0000000000..e91576adaf --- /dev/null +++ b/libs/graphics/animator/SkDrawOval.h @@ -0,0 +1,14 @@ +#ifndef SkDrawOval_DEFINED +#define SkDrawOval_DEFINED + +#include "SkDrawRectangle.h" + +class SkOval : public SkDrawRect { + DECLARE_MEMBER_INFO(Oval); + virtual bool draw(SkAnimateMaker& ); +private: + typedef SkDrawRect INHERITED; +}; + +#endif // SkDrawOval_DEFINED + diff --git a/libs/graphics/animator/SkDrawPaint.cpp b/libs/graphics/animator/SkDrawPaint.cpp new file mode 100644 index 0000000000..1f13091f49 --- /dev/null +++ b/libs/graphics/animator/SkDrawPaint.cpp @@ -0,0 +1,260 @@ +#include "SkDrawPaint.h" +#include "SkAnimateMaker.h" +#include "SkDrawColor.h" +#include "SkDrawShader.h" +#include "SkMaskFilter.h" +#include "SkPaintParts.h" +#include "SkPathEffect.h" + +enum SkPaint_Functions { + SK_FUNCTION(measureText) +}; + +enum SkPaint_Properties { + SK_PROPERTY(ascent), + SK_PROPERTY(descent) +}; + +// !!! in the future, this could be compiled by build-condensed-info into an array of parameters +// with a lookup table to find the first parameter -- for now, it is iteratively searched through +const SkFunctionParamType SkDrawPaint::fFunctionParameters[] = { + (SkFunctionParamType) SkType_String, + (SkFunctionParamType) 0 // terminator for parameter list (there may be multiple parameter lists) +}; + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawPaint::fInfo[] = { + SK_MEMBER(antiAlias, Boolean), + SK_MEMBER_PROPERTY(ascent, Float), + SK_MEMBER(color, Color), + SK_MEMBER_PROPERTY(descent, Float), + SK_MEMBER(fakeBold, Boolean), + SK_MEMBER(filterType, FilterType), + SK_MEMBER(linearText, Boolean), + SK_MEMBER(maskFilter, MaskFilter), + SK_MEMBER_FUNCTION(measureText, Float), + SK_MEMBER(pathEffect, PathEffect), + SK_MEMBER(shader, Shader), + SK_MEMBER(strikeThru, Boolean), + SK_MEMBER(stroke, Boolean), + SK_MEMBER(strokeCap, Cap), + SK_MEMBER(strokeJoin, Join), + SK_MEMBER(strokeMiter, Float), + SK_MEMBER(strokeWidth, Float), + SK_MEMBER(style, Style), + SK_MEMBER(textAlign, Align), + SK_MEMBER(textScaleX, Float), + SK_MEMBER(textSize, Float), + SK_MEMBER(textSkewX, Float), + SK_MEMBER(typeface, Typeface), + SK_MEMBER(underline, Boolean), + SK_MEMBER(xfermode, Xfermode) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawPaint); + +SkDrawPaint::SkDrawPaint() : antiAlias(-1), color(NULL), fakeBold(-1), filterType((SkPaint::FilterType) -1), + linearText(-1), maskFilter((SkDrawMaskFilter*) -1), pathEffect((SkDrawPathEffect*) -1), + shader((SkDrawShader*) -1), strikeThru(-1), stroke(-1), + strokeCap((SkPaint::Cap) -1), strokeJoin((SkPaint::Join) -1), strokeMiter(SK_ScalarNaN), + strokeWidth(SK_ScalarNaN), style((SkPaint::Style) -1), + textAlign((SkPaint::Align) -1), textScaleX(SK_ScalarNaN), textSize(SK_ScalarNaN), + textSkewX(SK_ScalarNaN), typeface((SkDrawTypeface*) -1), + underline(-1), xfermode((SkPorterDuff::Mode) -1), fOwnsColor(false), fOwnsMaskFilter(false), + fOwnsPathEffect(false), fOwnsShader(false), fOwnsTypeface(false) { +} + +SkDrawPaint::~SkDrawPaint() { + if (fOwnsColor) + delete color; + if (fOwnsMaskFilter) + delete maskFilter; + if (fOwnsPathEffect) + delete pathEffect; + if (fOwnsShader) + delete shader; + if (fOwnsTypeface) + delete typeface; +} + +bool SkDrawPaint::add(SkAnimateMaker& maker, SkDisplayable* child) { + SkASSERT(child && child->isPaintPart()); + SkPaintPart* part = (SkPaintPart*) child; + if (part->add()) + maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingToPaint); + return true; +} + +SkDisplayable* SkDrawPaint::deepCopy(SkAnimateMaker* maker) { + SkDrawColor* tempColor = color; + color = NULL; + SkDrawPaint* copy = (SkDrawPaint*) INHERITED::deepCopy(maker); + color = tempColor; + tempColor = (SkDrawColor*) color->deepCopy(maker); + tempColor->setParent(copy); + tempColor->add(); + copy->fOwnsColor = true; + return copy; +} + +bool SkDrawPaint::draw(SkAnimateMaker& maker) { + SkPaint* paint = maker.fPaint; + setupPaint(paint); + return false; +} + +#ifdef SK_DUMP_ENABLED +void SkDrawPaint::dump(SkAnimateMaker* maker) { + dumpBase(maker); + dumpAttrs(maker); + bool closedYet = false; + SkDisplayList::fIndent +=4; + //should i say if (maskFilter && ...? + if (maskFilter != (SkDrawMaskFilter*)-1) { + SkDebugf(">\n"); + maskFilter->dump(maker); + closedYet = true; + } + if (pathEffect != (SkDrawPathEffect*) -1) { + if (closedYet == false) { + SkDebugf(">\n"); + closedYet = true; + } + pathEffect->dump(maker); + } + if (fOwnsTypeface) { + if (closedYet == false) { + SkDebugf(">\n"); + closedYet = true; + } + typeface->dump(maker); + } + SkDisplayList::fIndent -= 4; + dumpChildren(maker, closedYet); +} +#endif + +void SkDrawPaint::executeFunction(SkDisplayable* target, int index, + SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, + SkScriptValue* scriptValue) { + if (scriptValue == NULL) + return; + SkASSERT(target == this); + switch (index) { + case SK_FUNCTION(measureText): { + SkASSERT(parameters.count() == 1); + SkASSERT(type == SkType_Float); + SkPaint paint; + setupPaint(&paint); + scriptValue->fType = SkType_Float; + SkASSERT(parameters[0].fType == SkType_String); + scriptValue->fOperand.fScalar = paint.measureText(parameters[0].fOperand.fString->c_str(), + parameters[0].fOperand.fString->size()); +// SkDebugf("measureText: %s = %g\n", parameters[0].fOperand.fString->c_str(), +// scriptValue->fOperand.fScalar / 65536.0f); + } break; + default: + SkASSERT(0); + } +} + +const SkFunctionParamType* SkDrawPaint::getFunctionsParameters() { + return fFunctionParameters; +} + +bool SkDrawPaint::getProperty(int index, SkScriptValue* value) const { + SkScalar above, below; + SkPaint paint; + setupPaint(&paint); + paint.measureText("", 0, &above, &below); + switch (index) { + case SK_PROPERTY(ascent): + value->fOperand.fScalar = above; + break; + case SK_PROPERTY(descent): + value->fOperand.fScalar = below; + break; + default: + SkASSERT(0); + return false; + } + value->fType = SkType_Float; + return true; +} + +bool SkDrawPaint::resolveIDs(SkAnimateMaker& maker, SkDisplayable* origDisp, SkApply* ) { + SkASSERT(origDisp->isPaint()); + SkDrawPaint* original = (SkDrawPaint*) origDisp; + if (fOwnsColor && maker.resolveID(color, original->color) == false) + return true; + if (fOwnsMaskFilter && maker.resolveID(maskFilter, original->maskFilter) == false) + return true; + if (fOwnsPathEffect && maker.resolveID(pathEffect, original->pathEffect) == false) + return true; + if (fOwnsShader && maker.resolveID(shader, original->shader) == false) + return true; + if (fOwnsTypeface && maker.resolveID(typeface, original->typeface) == false) + return true; + return false; // succeeded +} + +void SkDrawPaint::setupPaint(SkPaint* paint) const { + if (antiAlias != -1) + paint->setAntiAliasOn(SkToBool(antiAlias)); + if (color != NULL) + paint->setColor(color->getColor()); + if (fakeBold != -1) + paint->setFakeBoldTextOn(SkToBool(fakeBold)); + if (filterType != (SkPaint::FilterType) -1) + paint->setFilterType((SkPaint::FilterType) filterType); + // stroke is legacy; style setting if present overrides stroke + if (stroke != -1) + paint->setStyle(SkToBool(stroke) ? SkPaint::kStroke_Style : SkPaint::kFill_Style); + if (style != (SkPaint::Style) -1) + paint->setStyle((SkPaint::Style) style); + if (linearText != -1) + paint->setLinearTextOn(SkToBool(linearText)); + if (maskFilter == NULL) + paint->setMaskFilter(NULL); + else if (maskFilter != (SkDrawMaskFilter*) -1) + paint->setMaskFilter(maskFilter->getMaskFilter())->safeUnref(); + if (pathEffect == NULL) + paint->setPathEffect(NULL); + else if (pathEffect != (SkDrawPathEffect*) -1) + paint->setPathEffect(pathEffect->getPathEffect())->safeUnref(); + if (shader == NULL) + paint->setShader(NULL); + else if (shader != (SkDrawShader*) -1) + paint->setShader(shader->getShader())->safeUnref(); + if (strikeThru != -1) + paint->setStrikeThruTextOn(SkToBool(strikeThru)); + if (strokeCap != (SkPaint::Cap) -1) + paint->setStrokeCap((SkPaint::Cap) strokeCap); + if (strokeJoin != (SkPaint::Join) -1) + paint->setStrokeJoin((SkPaint::Join) strokeJoin); + if (SkScalarIsNaN(strokeMiter) == false) + paint->setStrokeMiter(strokeMiter); + if (SkScalarIsNaN(strokeWidth) == false) + paint->setStrokeWidth(strokeWidth); + if (textAlign != (SkPaint::Align) -1) + paint->setTextAlign((SkPaint::Align) textAlign); + if (SkScalarIsNaN(textScaleX) == false) + paint->setTextScaleX(textScaleX); + if (SkScalarIsNaN(textSize) == false) + paint->setTextSize(textSize); + if (SkScalarIsNaN(textSkewX) == false) + paint->setTextSkewX(textSkewX); + if (typeface == NULL) + paint->setTypeface(NULL); + else if (typeface != (SkDrawTypeface*) -1) + paint->setTypeface(typeface->getTypeface())->safeUnref(); + if (underline != -1) + paint->setUnderlineTextOn(SkToBool(underline)); + if (xfermode != (SkPorterDuff::Mode) -1) + paint->setPorterDuffXfermode((SkPorterDuff::Mode) xfermode); +} + diff --git a/libs/graphics/animator/SkDrawPaint.h b/libs/graphics/animator/SkDrawPaint.h new file mode 100644 index 0000000000..3ae0ffa492 --- /dev/null +++ b/libs/graphics/animator/SkDrawPaint.h @@ -0,0 +1,71 @@ +#ifndef SkDrawPaint_DEFINED +#define SkDrawPaint_DEFINED + +#include "SkDrawable.h" +#include "SkIntArray.h" +#include "SkMemberInfo.h" +#include "SkPaint.h" +#include "SkXfermode.h" + +class SkDrawMaskFilter; +class SkDrawPathEffect; +class SkDrawShader; +class SkTransferMode; +class SkDrawTypeface; + +class SkDrawPaint : public SkDrawable { + DECLARE_DRAW_MEMBER_INFO(Paint); + SkDrawPaint(); + virtual ~SkDrawPaint(); + virtual bool add(SkAnimateMaker& , SkDisplayable* child); + virtual SkDisplayable* deepCopy(SkAnimateMaker* ); + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual void executeFunction(SkDisplayable* target, int index, + SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type, + SkScriptValue* ); + virtual const SkFunctionParamType* getFunctionsParameters(); + virtual bool getProperty(int index, SkScriptValue* value) const; + virtual bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* apply); +protected: + static const SkFunctionParamType fFunctionParameters[]; + void setupPaint(SkPaint* paint) const; +public: + SkBool antiAlias; + SkDrawColor* color; + SkBool fakeBold; + int /*SkPaint::FilterType*/ filterType; + SkBool linearText; + SkDrawMaskFilter* maskFilter; + SkDrawPathEffect* pathEffect; + SkDrawShader* shader; + SkBool strikeThru; + SkBool stroke; + int /*SkPaint::Cap*/ strokeCap; + int /*SkPaint::Join */ strokeJoin; + SkScalar strokeMiter; + SkScalar strokeWidth; + int /* SkPaint::Style */ style; + int /* SkPaint::Align */ textAlign; + SkScalar textScaleX; + SkScalar textSize; + SkScalar textSkewX; + SkDrawTypeface* typeface; + SkBool underline; + int /*SkXfermode::Modes*/ xfermode; + SkBool8 fOwnsColor; + SkBool8 fOwnsMaskFilter; + SkBool8 fOwnsPathEffect; + SkBool8 fOwnsShader; + SkBool8 fOwnsTransferMode; + SkBool8 fOwnsTypeface; +private: + typedef SkDrawable INHERITED; + friend class SkTextToPath; + friend class SkSaveLayer; +}; + +#endif // SkDrawPaint_DEFINED + diff --git a/libs/graphics/animator/SkDrawPath.cpp b/libs/graphics/animator/SkDrawPath.cpp new file mode 100644 index 0000000000..302460089d --- /dev/null +++ b/libs/graphics/animator/SkDrawPath.cpp @@ -0,0 +1,212 @@ +#include "SkDrawPath.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkMath.h" +#include "SkMatrixParts.h" +#include "SkPaint.h" +#include "SkPathParts.h" + +enum SkPath_Properties { + SK_PROPERTY(fillType), + SK_PROPERTY(length) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawPath::fInfo[] = { + SK_MEMBER(d, String), + SK_MEMBER_PROPERTY(fillType, FillType), + SK_MEMBER_PROPERTY(length, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawPath); + +SkDrawPath::SkDrawPath() +{ + fParent = nil; + fLength = SK_ScalarNaN; + fChildHasID = false; + fDirty = false; +} + +SkDrawPath::~SkDrawPath() { + for (SkPathPart** part = fParts.begin(); part < fParts.end(); part++) + delete *part; +} + +bool SkDrawPath::add(SkAnimateMaker& maker, SkDisplayable* child) { + SkASSERT(child && child->isPathPart()); + SkPathPart* part = (SkPathPart*) child; + *fParts.append() = part; + if (part->add()) + maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingToPath); + fDirty = false; + return true; +} + +bool SkDrawPath::childrenNeedDisposing() const { + return false; +} + +void SkDrawPath::dirty() { + fDirty = true; + fLength = SK_ScalarNaN; + if (fParent) + fParent->dirty(); +} + +bool SkDrawPath::draw(SkAnimateMaker& maker) { + SkPath& path = getPath(); + SkBoundableAuto boundable(this, maker); + maker.fCanvas->drawPath(path, *maker.fPaint); + return false; +} + +SkDisplayable* SkDrawPath::getParent() const { + return fParent; +} + +#ifdef SK_DUMP_ENABLED +void SkDrawPath::dump(SkAnimateMaker* maker) { + dumpBase(maker); + dumpAttrs(maker); + bool closedYet = false; + SkDisplayList::fIndent += 4; + for(SkPathPart** part = fParts.begin(); part < fParts.end(); part++) { + if (closedYet == false) { + SkDebugf(">\n"); + closedYet = true; + } + (*part)->dump(maker); + } + SkDisplayList::fIndent -= 4; + if (closedYet) + dumpEnd(maker); + else + SkDebugf("/>\n"); +} +#endif + +SkPath& SkDrawPath::getPath() { + if (fDirty == false) + return fPath; + if (d.size() > 0) + { + parseSVG(); + d.reset(); + } + else + { + fPath.reset(); + for (SkPathPart** part = fParts.begin(); part < fParts.end(); part++) + (*part)->add(); + } + fDirty = false; + return fPath; +} + +void SkDrawPath::onEndElement(SkAnimateMaker& ) { + if (d.size() > 0) { + parseSVG(); + d.reset(); + fDirty = false; + return; + } + if (fChildHasID == false) { + for (SkPathPart** part = fParts.begin(); part < fParts.end(); part++) + delete *part; + fParts.reset(); + fDirty = false; + } +} + +bool SkDrawPath::getProperty(int index, SkScriptValue* value) const { + switch (index) { + case SK_PROPERTY(length): + if (SkScalarIsNaN(fLength)) { + const SkPath& path = ((SkDrawPath*) this)->getPath(); + SkPathMeasure pathMeasure(path, false); + fLength = pathMeasure.getLength(); + } + value->fType = SkType_Float; + value->fOperand.fScalar = fLength; + break; + case SK_PROPERTY(fillType): + value->fType = SkType_FillType; + value->fOperand.fS32 = (int) fPath.getFillType(); + break; + default: + SkASSERT(0); + return false; + } + return true; +} + +void SkDrawPath::setChildHasID() { + fChildHasID = true; +} + +bool SkDrawPath::setParent(SkDisplayable* parent) { + fParent = parent; + return false; +} + +bool SkDrawPath::setProperty(int index, SkScriptValue& value) +{ + switch (index) { + case SK_PROPERTY(fillType): + SkASSERT(value.fType == SkType_FillType); + SkASSERT(value.fOperand.fS32 >= SkPath::kWinding_FillType && + value.fOperand.fS32 <= SkPath::kEvenOdd_FillType); + fPath.setFillType((SkPath::FillType) value.fOperand.fS32); + break; + default: + SkASSERT(0); + return false; + } + return true; +} + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkPolyline::fInfo[] = { + SK_MEMBER_ARRAY(points, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkPolyline); + +bool SkPolyline::add(SkAnimateMaker& , SkDisplayable*) const { + return false; +} + +void SkPolyline::onEndElement(SkAnimateMaker& maker) { + INHERITED::onEndElement(maker); + if (points.count() <= 0) + return; + fPath.reset(); + fPath.moveTo(points[0], points[1]); + int count = points.count(); + for (int index = 2; index < count; index += 2) + fPath.lineTo(points[index], points[index+1]); +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkPolygon::fInfo[] = { + SK_MEMBER_INHERITED +}; + +#endif + +DEFINE_GET_MEMBER(SkPolygon); + +void SkPolygon::onEndElement(SkAnimateMaker& maker) { + INHERITED::onEndElement(maker); + fPath.close(); +} + diff --git a/libs/graphics/animator/SkDrawPath.h b/libs/graphics/animator/SkDrawPath.h new file mode 100644 index 0000000000..3c005a5dfd --- /dev/null +++ b/libs/graphics/animator/SkDrawPath.h @@ -0,0 +1,60 @@ +#ifndef SkDrawPath_DEFINED +#define SkDrawPath_DEFINED + +#include "SkBoundable.h" +#include "SkIntArray.h" +#include "SkMemberInfo.h" +#include "SkPath.h" + +class SkDrawPath : public SkBoundable { + DECLARE_DRAW_MEMBER_INFO(Path); + SkDrawPath(); + virtual ~SkDrawPath(); + virtual bool add(SkAnimateMaker& , SkDisplayable* child); + bool childHasID() { return SkToBool(fChildHasID); } + virtual bool childrenNeedDisposing() const; + virtual void dirty(); + virtual bool draw(SkAnimateMaker& ); + virtual SkDisplayable* getParent() const; +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + SkPath& getPath(); + virtual bool getProperty(int index, SkScriptValue* value) const; + virtual bool setProperty(int index, SkScriptValue& value); + virtual void onEndElement(SkAnimateMaker& ); + virtual void setChildHasID(); + virtual bool setParent(SkDisplayable* parent); + virtual bool isPath() const { return true; } +public: + SkPath fPath; +protected: + void parseSVG(); + SkString d; + SkTDPathPartArray fParts; + mutable SkScalar fLength; + SkDisplayable* fParent; // SkPolyToPoly or SkFromPath, for instance + SkBool8 fChildHasID; + SkBool8 fDirty; +private: + typedef SkBoundable INHERITED; +}; + +class SkPolyline : public SkDrawPath { + DECLARE_MEMBER_INFO(Polyline); + virtual bool add(SkAnimateMaker& , SkDisplayable*) const; + virtual void onEndElement(SkAnimateMaker& ); +protected: + SkTDScalarArray points; +private: + typedef SkDrawPath INHERITED; +}; + +class SkPolygon : public SkPolyline { + DECLARE_MEMBER_INFO(Polygon); + virtual void onEndElement(SkAnimateMaker& ); +private: + typedef SkPolyline INHERITED; +}; + +#endif // SkDrawPath_DEFINED diff --git a/libs/graphics/animator/SkDrawPoint.cpp b/libs/graphics/animator/SkDrawPoint.cpp new file mode 100644 index 0000000000..4bbd00611f --- /dev/null +++ b/libs/graphics/animator/SkDrawPoint.cpp @@ -0,0 +1,37 @@ +#include "SkDrawPoint.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkPaint.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo Sk_Point::fInfo[] = { + SK_MEMBER_ALIAS(x, fPoint.fX, Float), + SK_MEMBER_ALIAS(y, fPoint.fY, Float) +}; + +#endif + +DEFINE_NO_VIRTUALS_GET_MEMBER(Sk_Point); + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawPoint::fInfo[] = { + SK_MEMBER_ALIAS(x, fPoint.fX, Float), + SK_MEMBER_ALIAS(y, fPoint.fY, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawPoint); + +SkDrawPoint::SkDrawPoint() { + fPoint.set(0, 0); +} + +void SkDrawPoint::getBounds(SkRect* rect ) { + rect->fLeft = rect->fRight = fPoint.fX; + rect->fTop = rect->fBottom = fPoint.fY; +} + + diff --git a/libs/graphics/animator/SkDrawPoint.h b/libs/graphics/animator/SkDrawPoint.h new file mode 100644 index 0000000000..c59c78a972 --- /dev/null +++ b/libs/graphics/animator/SkDrawPoint.h @@ -0,0 +1,24 @@ +#ifndef SkDrawPoint_DEFINED +#define SkDrawPoint_DEFINED + +#include "SkBoundable.h" +#include "SkMemberInfo.h" +#include "SkPoint.h" + +struct Sk_Point { + DECLARE_NO_VIRTUALS_MEMBER_INFO(_Point); + Sk_Point(); +private: + SkPoint fPoint; +}; + +class SkDrawPoint : public SkDisplayable { + DECLARE_MEMBER_INFO(DrawPoint); + SkDrawPoint(); + virtual void getBounds(SkRect* ); +private: + SkPoint fPoint; + typedef SkDisplayable INHERITED; +}; + +#endif // SkDrawPoint_DEFINED diff --git a/libs/graphics/animator/SkDrawRectangle.cpp b/libs/graphics/animator/SkDrawRectangle.cpp new file mode 100644 index 0000000000..3ccb347ed5 --- /dev/null +++ b/libs/graphics/animator/SkDrawRectangle.cpp @@ -0,0 +1,136 @@ +#include "SkDrawRectangle.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkMatrixParts.h" +#include "SkPaint.h" +#include "SkScript.h" + +enum SkRectangle_Properties { + SK_PROPERTY(height), + SK_PROPERTY(needsRedraw), + SK_PROPERTY(width) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawRect::fInfo[] = { + SK_MEMBER_ALIAS(bottom, fRect.fBottom, Float), + SK_MEMBER_PROPERTY(height, Float), + SK_MEMBER_ALIAS(left, fRect.fLeft, Float), + SK_MEMBER_PROPERTY(needsRedraw, Boolean), + SK_MEMBER_ALIAS(right, fRect.fRight, Float), + SK_MEMBER_ALIAS(top, fRect.fTop, Float), + SK_MEMBER_PROPERTY(width, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawRect); + +SkDrawRect::SkDrawRect() : fParent(nil) { + fRect.setEmpty(); +} + +void SkDrawRect::dirty() { + if (fParent) + fParent->dirty(); +} + +bool SkDrawRect::draw(SkAnimateMaker& maker) { + SkBoundableAuto boundable(this, maker); + maker.fCanvas->drawRect(fRect, *maker.fPaint); + return false; +} + +#ifdef SK_DUMP_ENABLED +void SkDrawRect::dump(SkAnimateMaker* maker) { + dumpBase(maker); + SkDebugf("left=\"%g\" top=\"%g\" right=\"%g\" bottom=\"%g\" />\n", + SkScalarToFloat(fRect.fLeft), SkScalarToFloat(fRect.fTop), SkScalarToFloat(fRect.fRight), + SkScalarToFloat(fRect.fBottom)); +} +#endif + +SkDisplayable* SkDrawRect::getParent() const { + return fParent; +} + +bool SkDrawRect::getProperty(int index, SkScriptValue* value) const { + SkScalar result; + switch (index) { + case SK_PROPERTY(height): + result = fRect.height(); + break; + case SK_PROPERTY(needsRedraw): + value->fType = SkType_Boolean; + value->fOperand.fS32 = fBounds.isEmpty() == false; + return true; + case SK_PROPERTY(width): + result = fRect.width(); + break; + default: + SkASSERT(0); + return false; + } + value->fType = SkType_Float; + value->fOperand.fScalar = result; + return true; +} + + +bool SkDrawRect::setParent(SkDisplayable* parent) { + fParent = parent; + return false; +} + +bool SkDrawRect::setProperty(int index, SkScriptValue& value) { + SkScalar scalar = value.fOperand.fScalar; + switch (index) { + case SK_PROPERTY(height): + SkASSERT(value.fType == SkType_Float); + fRect.fBottom = scalar + fRect.fTop; + return true; + case SK_PROPERTY(needsRedraw): + return false; + case SK_PROPERTY(width): + SkASSERT(value.fType == SkType_Float); + fRect.fRight = scalar + fRect.fLeft; + return true; + default: + SkASSERT(0); + } + return false; +} + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkRoundRect::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER(rx, Float), + SK_MEMBER(ry, Float), +}; + +#endif + +DEFINE_GET_MEMBER(SkRoundRect); + +SkRoundRect::SkRoundRect() : rx(0), ry(0) { +} + +bool SkRoundRect::draw(SkAnimateMaker& maker) { + SkBoundableAuto boundable(this, maker); + maker.fCanvas->drawRoundRect(fRect, rx, ry, *maker.fPaint); + return false; +} + +#ifdef SK_DUMP_ENABLED +void SkRoundRect::dump(SkAnimateMaker* maker) { + dumpBase(maker); + SkDebugf("left=\"%g\" top=\"%g\" right=\"%g\" bottom=\"%g\" rx=\"%g\" ry=\"%g\" />\n", + SkScalarToFloat(fRect.fLeft), SkScalarToFloat(fRect.fTop), SkScalarToFloat(fRect.fRight), + SkScalarToFloat(fRect.fBottom), SkScalarToFloat(rx), SkScalarToFloat(ry)); +} +#endif + + + diff --git a/libs/graphics/animator/SkDrawRectangle.h b/libs/graphics/animator/SkDrawRectangle.h new file mode 100644 index 0000000000..6abb6e486b --- /dev/null +++ b/libs/graphics/animator/SkDrawRectangle.h @@ -0,0 +1,47 @@ +#ifndef SkDrawRectangle_DEFINED +#define SkDrawRectangle_DEFINED + +#include "SkBoundable.h" +#include "SkMemberInfo.h" +#include "SkRect.h" + +class SkRectToRect; + +class SkDrawRect : public SkBoundable { + DECLARE_DRAW_MEMBER_INFO(Rect); + SkDrawRect(); + virtual void dirty(); + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual SkDisplayable* getParent() const; + virtual bool getProperty(int index, SkScriptValue* value) const; + virtual bool setParent(SkDisplayable* parent); + virtual bool setProperty(int index, SkScriptValue& ); +protected: + SkRect fRect; + SkDisplayable* fParent; +private: + friend class SkDrawClip; + friend class SkRectToRect; + friend class SkSaveLayer; + typedef SkBoundable INHERITED; +}; + +class SkRoundRect : public SkDrawRect { + DECLARE_MEMBER_INFO(RoundRect); + SkRoundRect(); + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif +protected: + SkScalar rx; + SkScalar ry; +private: + typedef SkDrawRect INHERITED; +}; + +#endif // SkDrawRectangle_DEFINED + diff --git a/libs/graphics/animator/SkDrawSaveLayer.cpp b/libs/graphics/animator/SkDrawSaveLayer.cpp new file mode 100644 index 0000000000..c6addb888d --- /dev/null +++ b/libs/graphics/animator/SkDrawSaveLayer.cpp @@ -0,0 +1,67 @@ +#include "SkDrawSaveLayer.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkDrawPaint.h" +#include "SkDrawRectangle.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkSaveLayer::fInfo[] = { + SK_MEMBER(bounds, Rect), + SK_MEMBER(paint, Paint) +}; + +#endif + +DEFINE_GET_MEMBER(SkSaveLayer); + +SkSaveLayer::SkSaveLayer() : paint(NULL), bounds(NULL) { +} + +SkSaveLayer::~SkSaveLayer(){ +} + +bool SkSaveLayer::draw(SkAnimateMaker& maker) +{ + if (!bounds) { + return false; + } + SkPaint* save = maker.fPaint; + //paint is an SkDrawPaint + if (paint) + { + SkPaint realPaint; + paint->setupPaint(&realPaint); + maker.fCanvas->saveLayer(bounds->fRect, realPaint); + } + else + maker.fCanvas->saveLayer(bounds->fRect, *save); + SkPaint local = SkPaint(*maker.fPaint); + maker.fPaint = &local; + bool result = INHERITED::draw(maker); + maker.fPaint = save; + maker.fCanvas->restore(); + return result; +} + +#ifdef SK_DUMP_ENABLED +void SkSaveLayer::dump(SkAnimateMaker* maker) +{ + dumpBase(maker); + //would dump enabled be defined but not debug? +#ifdef SK_DEBUG + if (paint) + SkDebugf("paint=\"%s\" ", paint->id); + if (bounds) + SkDebugf("bounds=\"%s\" ", bounds->id); +#endif + dumpDrawables(maker); +} +#endif + +void SkSaveLayer::onEndElement(SkAnimateMaker& maker) +{ + if (!bounds) + maker.setErrorCode(SkDisplayXMLParserError::kSaveLayerNeedsBounds); + INHERITED::onEndElement(maker); +}
\ No newline at end of file diff --git a/libs/graphics/animator/SkDrawSaveLayer.h b/libs/graphics/animator/SkDrawSaveLayer.h new file mode 100644 index 0000000000..964445711f --- /dev/null +++ b/libs/graphics/animator/SkDrawSaveLayer.h @@ -0,0 +1,27 @@ +#ifndef SkDrawSaveLayer_DEFINED +#define SkDrawSaveLayer_DEFINED + +#include "SkDrawGroup.h" +#include "SkMemberInfo.h" + +class SkDrawPaint; +class SkDrawRect; + +class SkSaveLayer : public SkGroup { + DECLARE_MEMBER_INFO(SaveLayer); + SkSaveLayer(); + virtual ~SkSaveLayer(); + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual void onEndElement(SkAnimateMaker& ); +protected: + SkDrawPaint* paint; + SkDrawRect* bounds; +private: + typedef SkGroup INHERITED; + +}; + +#endif //SkDrawSaveLayer_DEFINED diff --git a/libs/graphics/animator/SkDrawShader.cpp b/libs/graphics/animator/SkDrawShader.cpp new file mode 100644 index 0000000000..4b071a15b1 --- /dev/null +++ b/libs/graphics/animator/SkDrawShader.cpp @@ -0,0 +1,74 @@ +#include "SkDrawShader.h" +#include "SkDrawBitmap.h" +#include "SkDrawMatrix.h" +#include "SkDrawPaint.h" +#include "SkTemplates.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawShader::fInfo[] = { + SK_MEMBER(matrix, Matrix), + SK_MEMBER(tileMode, TileMode) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawShader); + +SkDrawShader::SkDrawShader() : matrix(nil), + tileMode(SkShader::kClamp_TileMode) { +} + +bool SkDrawShader::add() { + if (fPaint->shader != (SkDrawShader*) -1) + return true; + fPaint->shader = this; + fPaint->fOwnsShader = true; + return false; +} + +void SkDrawShader::addPostlude(SkShader* shader) { + if (matrix) + shader->setLocalMatrix(matrix->getMatrix()); +} + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawBitmapShader::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER(filterType, FilterType), + SK_MEMBER(image, BaseBitmap) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawBitmapShader); + +SkDrawBitmapShader::SkDrawBitmapShader() : filterType(SkPaint::kNo_FilterType), image(nil) {} + +bool SkDrawBitmapShader::add() { + if (fPaint->shader != (SkDrawShader*) -1) + return true; + fPaint->shader = this; + fPaint->fOwnsShader = true; + return false; +} + +SkShader* SkDrawBitmapShader::getShader() { + if (image == NULL) + return NULL; + + // note: bitmap shader now supports independent tile modes for X and Y + // we pass the same to both, but later we should extend this flexibility + // to the xml (e.g. tileModeX="repeat" tileModeY="clmap") + // <reed> + SkShader* shader = SkShader::CreateBitmapShader(image->fBitmap, false, + (SkPaint::FilterType) filterType, + (SkShader::TileMode) tileMode, + (SkShader::TileMode) tileMode); + SkAutoTDelete<SkShader> autoDel(shader); + addPostlude(shader); + (void)autoDel.detach(); + return shader; +} + diff --git a/libs/graphics/animator/SkDrawShader.h b/libs/graphics/animator/SkDrawShader.h new file mode 100644 index 0000000000..860140593c --- /dev/null +++ b/libs/graphics/animator/SkDrawShader.h @@ -0,0 +1,21 @@ +#ifndef SkDrawShader_DEFINED +#define SkDrawShader_DEFINED + +#include "SkPaintParts.h" +#include "SkShader.h" + +class SkBaseBitmap; + +class SkDrawBitmapShader : public SkDrawShader { + DECLARE_DRAW_MEMBER_INFO(BitmapShader); + SkDrawBitmapShader(); + virtual bool add(); + virtual SkShader* getShader(); +protected: + int /*SkPaint::FilterType*/ filterType; + SkBaseBitmap* image; +private: + typedef SkDrawShader INHERITED; +}; + +#endif // SkDrawShader_DEFINED diff --git a/libs/graphics/animator/SkDrawText.cpp b/libs/graphics/animator/SkDrawText.cpp new file mode 100644 index 0000000000..093e7e496c --- /dev/null +++ b/libs/graphics/animator/SkDrawText.cpp @@ -0,0 +1,47 @@ +#include "SkDrawText.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkPaint.h" + +enum SkText_Properties { + SK_PROPERTY(length) +}; + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkText::fInfo[] = { + SK_MEMBER_PROPERTY(length, Int), + SK_MEMBER(text, String), + SK_MEMBER(x, Float), + SK_MEMBER(y, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkText); + +SkText::SkText() : x(0), y(0) { +} + +SkText::~SkText() { +} + +bool SkText::draw(SkAnimateMaker& maker) { + SkBoundableAuto boundable(this, maker); + maker.fCanvas->drawText(text.c_str(), text.size(), x, y, *maker.fPaint); + return false; +} + +#ifdef SK_DUMP_ENABLED +void SkText::dump(SkAnimateMaker* maker) { + INHERITED::dump(maker); +} +#endif + +bool SkText::getProperty(int index, SkScriptValue* value) const { + SkASSERT(index == SK_PROPERTY(length)); + value->fType = SkType_Int; + value->fOperand.fS32 = (S32) text.size(); + return true; +} + diff --git a/libs/graphics/animator/SkDrawText.h b/libs/graphics/animator/SkDrawText.h new file mode 100644 index 0000000000..2cc8c86239 --- /dev/null +++ b/libs/graphics/animator/SkDrawText.h @@ -0,0 +1,27 @@ +#ifndef SkDrawText_DEFINED +#define SkDrawText_DEFINED + +#include "SkBoundable.h" +#include "SkMemberInfo.h" + +class SkText : public SkBoundable { + DECLARE_MEMBER_INFO(Text); + SkText(); + virtual ~SkText(); + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual bool getProperty(int index, SkScriptValue* value) const ; + const char* getText() { return text.c_str(); } + size_t getSize() { return text.size(); } +protected: + SkString text; + SkScalar x; + SkScalar y; +private: + friend class SkTextToPath; + typedef SkBoundable INHERITED; +}; + +#endif // SkDrawText_DEFINED diff --git a/libs/graphics/animator/SkDrawTextBox.cpp b/libs/graphics/animator/SkDrawTextBox.cpp new file mode 100644 index 0000000000..204d398694 --- /dev/null +++ b/libs/graphics/animator/SkDrawTextBox.cpp @@ -0,0 +1,73 @@ +#include "SkDrawTextBox.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkPaint.h" + +enum SkDrawTextBox_Properties { + foo = 100, + SK_PROPERTY(spacingAlign), + SK_PROPERTY(mode) +}; + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawTextBox::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER(mode, TextBoxMode), + SK_MEMBER_ALIAS(spacingAdd, fSpacingAdd, Float), + SK_MEMBER(spacingAlign, TextBoxAlign), + SK_MEMBER_ALIAS(spacingMul, fSpacingMul, Float), + SK_MEMBER_ALIAS(text, fText, String) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawTextBox); + +SkDrawTextBox::SkDrawTextBox() +{ + fSpacingMul = SK_Scalar1; + fSpacingAdd = 0; + spacingAlign = SkTextBox::kStart_SpacingAlign; + mode = SkTextBox::kLineBreak_Mode; +} + +#ifdef SK_DUMP_ENABLED +void SkDrawTextBox::dump(SkAnimateMaker* maker) +{ + dumpBase(maker); + dumpAttrs(maker); + if (mode == 0) + SkDebugf("mode=\"oneLine\" "); + if (spacingAlign == 1) + SkDebugf("spacingAlign=\"center\" "); + else if (spacingAlign == 2) + SkDebugf("spacingAlign=\"end\" "); + SkDebugf("/>\n"); +} +#endif + +bool SkDrawTextBox::getProperty(int index, SkScriptValue* value) const +{ + return this->INHERITED::getProperty(index, value); +} + +bool SkDrawTextBox::setProperty(int index, SkScriptValue& scriptValue) +{ + return this->INHERITED::setProperty(index, scriptValue); +} + +bool SkDrawTextBox::draw(SkAnimateMaker& maker) +{ + SkTextBox box; + box.setMode((SkTextBox::Mode) mode); + box.setSpacingAlign((SkTextBox::SpacingAlign) spacingAlign); + box.setBox(fRect); + box.setSpacing(fSpacingMul, fSpacingAdd); + SkBoundableAuto boundable(this, maker); + box.draw(maker.fCanvas, fText.c_str(), fText.size(), *maker.fPaint); + return false; +} + + diff --git a/libs/graphics/animator/SkDrawTextBox.h b/libs/graphics/animator/SkDrawTextBox.h new file mode 100644 index 0000000000..20bb14c196 --- /dev/null +++ b/libs/graphics/animator/SkDrawTextBox.h @@ -0,0 +1,30 @@ +#ifndef SkDrawTextBox_DEFINED +#define SkDrawTextBox_DEFINED + +#include "SkDrawRectangle.h" +#include "SkTextBox.h" + +class SkDrawTextBox : public SkDrawRect { + DECLARE_DRAW_MEMBER_INFO(TextBox); + SkDrawTextBox(); + + // overrides + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual bool getProperty(int index, SkScriptValue* value) const; + virtual bool setProperty(int index, SkScriptValue& ); + +private: + SkString fText; + SkScalar fSpacingMul; + SkScalar fSpacingAdd; + int /*SkTextBox::Mode*/ mode; + int /*SkTextBox::SpacingAlign*/ spacingAlign; + + typedef SkDrawRect INHERITED; +}; + +#endif // SkDrawTextBox_DEFINED + diff --git a/libs/graphics/animator/SkDrawTo.cpp b/libs/graphics/animator/SkDrawTo.cpp new file mode 100644 index 0000000000..2019c4b1c6 --- /dev/null +++ b/libs/graphics/animator/SkDrawTo.cpp @@ -0,0 +1,47 @@ +#include "SkDrawTo.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkDrawBitmap.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawTo::fInfo[] = { + SK_MEMBER(drawOnce, Boolean), + SK_MEMBER(use, Bitmap) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawTo); + +SkDrawTo::SkDrawTo() : drawOnce(false), use(nil), fDrawnOnce(false) { +} + +#if 0 +SkDrawTo::~SkDrawTo() { + SkASSERT(0); +} +#endif + +bool SkDrawTo::draw(SkAnimateMaker& maker) { + if (fDrawnOnce) + return false; + SkCanvas canvas(use->fBitmap); + SkCanvas* save = maker.fCanvas; + maker.fCanvas = &canvas; + INHERITED::draw(maker); + maker.fCanvas = save; + fDrawnOnce = drawOnce; + return false; +} + +#ifdef SK_DUMP_ENABLED +void SkDrawTo::dump(SkAnimateMaker* maker) { + dumpBase(maker); + dumpAttrs(maker); + if (use) + SkDebugf("use=\"%s\" ", use->id); + dumpDrawables(maker); +} +#endif + diff --git a/libs/graphics/animator/SkDrawTo.h b/libs/graphics/animator/SkDrawTo.h new file mode 100644 index 0000000000..403ced6f3a --- /dev/null +++ b/libs/graphics/animator/SkDrawTo.h @@ -0,0 +1,25 @@ +#ifndef SkDrawTo_DEFINED +#define SkDrawTo_DEFINED + +#include "SkDrawGroup.h" +#include "SkMemberInfo.h" + +class SkDrawBitmap; + +class SkDrawTo : public SkGroup { + DECLARE_MEMBER_INFO(DrawTo); + SkDrawTo(); +// virtual ~SkDrawTo(); + virtual bool draw(SkAnimateMaker& ); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif +protected: + SkBool drawOnce; + SkDrawBitmap* use; +private: + typedef SkGroup INHERITED; + SkBool fDrawnOnce; +}; + +#endif // SkDrawTo_DEFINED diff --git a/libs/graphics/animator/SkDrawTransparentShader.cpp b/libs/graphics/animator/SkDrawTransparentShader.cpp new file mode 100644 index 0000000000..c71fb37295 --- /dev/null +++ b/libs/graphics/animator/SkDrawTransparentShader.cpp @@ -0,0 +1,7 @@ +#include "SkDrawTransparentShader.h" +#include "SkTransparentShader.h" + +SkShader* SkDrawTransparentShader::getShader() { + return new SkTransparentShader(); +} + diff --git a/libs/graphics/animator/SkDrawTransparentShader.h b/libs/graphics/animator/SkDrawTransparentShader.h new file mode 100644 index 0000000000..06599378d7 --- /dev/null +++ b/libs/graphics/animator/SkDrawTransparentShader.h @@ -0,0 +1,12 @@ +#ifndef SkDrawTransparentShader_DEFINED +#define SkDrawTransparentShader_DEFINED + +#include "SkPaintParts.h" + +class SkDrawTransparentShader : public SkDrawShader { + DECLARE_EMPTY_MEMBER_INFO(TransparentShader); + virtual SkShader* getShader(); +}; + +#endif // SkDrawTransparentShader_DEFINED + diff --git a/libs/graphics/animator/SkDrawable.cpp b/libs/graphics/animator/SkDrawable.cpp new file mode 100644 index 0000000000..e3e3662467 --- /dev/null +++ b/libs/graphics/animator/SkDrawable.cpp @@ -0,0 +1,16 @@ +#include "SkDrawable.h" + +bool SkDrawable::doEvent(SkDisplayEvent::Kind , SkEventState* ) { + return false; +} + +bool SkDrawable::isDrawable() const { + return true; +} + +void SkDrawable::initialize() { +} + +void SkDrawable::setSteps(int steps) { +} + diff --git a/libs/graphics/animator/SkDrawable.h b/libs/graphics/animator/SkDrawable.h new file mode 100644 index 0000000000..6c62b15203 --- /dev/null +++ b/libs/graphics/animator/SkDrawable.h @@ -0,0 +1,19 @@ +#ifndef SkDrawable_DEFINED +#define SkDrawable_DEFINED + +#include "SkDisplayable.h" +#include "SkDisplayEvent.h" +#include "SkMath.h" + +struct SkEventState; + +class SkDrawable : public SkDisplayable { +public: + virtual bool doEvent(SkDisplayEvent::Kind , SkEventState* state ); + virtual bool draw(SkAnimateMaker& ) = 0; + virtual void initialize(); + virtual bool isDrawable() const; + virtual void setSteps(int steps); +}; + +#endif // SkDrawable_DEFINED diff --git a/libs/graphics/animator/SkDump.cpp b/libs/graphics/animator/SkDump.cpp new file mode 100644 index 0000000000..cd7dcf09be --- /dev/null +++ b/libs/graphics/animator/SkDump.cpp @@ -0,0 +1,141 @@ +#include "SkDump.h" + +#ifdef SK_DUMP_ENABLED + +#include "SkAnimateMaker.h" +#include "SkAnimatorScript.h" +#include "SkDisplayEvents.h" +#include "SkDisplayList.h" +#include "SkString.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDump::fInfo[] = { + SK_MEMBER(displayList, Boolean), + SK_MEMBER(eventList, Boolean), + SK_MEMBER(events, Boolean), + SK_MEMBER(groups, Boolean), + SK_MEMBER(name, String), + SK_MEMBER(posts, Boolean), + SK_MEMBER(script, String) +}; + +#endif + +DEFINE_GET_MEMBER(SkDump); + +SkDump::SkDump() : displayList(-1), eventList(-1), events(-1), groups(-1), posts(-1) { +} + +bool SkDump::enable(SkAnimateMaker& maker ) { + if (script.size() > 0) + return evaluate(maker); + bool hasAttr = false; + if (events > 0) + hasAttr |= maker.fDumpEvents = true; + if (posts > 0) + hasAttr |= maker.fDumpPosts = true; + if (groups > 0) + hasAttr |= maker.fDumpGConditions = true; + if ((hasAttr |= (eventList > 0)) == true) + maker.fEvents.dump(maker); + if ((hasAttr |= (name.size() > 0)) == true) + maker.dump(name.c_str()); + if (displayList > 0 || displayList != 0 && hasAttr == false) + maker.fDisplayList.dump(&maker); + return true; +} + +bool SkDump::evaluate(SkAnimateMaker &maker) { + SkAnimatorScript scriptEngine(maker, nil, SkType_Int); + SkScriptValue value; + const char* cScript = script.c_str(); + bool success = scriptEngine.evaluateScript(&cScript, &value); + SkDebugf("%*s<dump script=\"%s\" answer=\" ", SkDisplayList::fIndent, "", script.c_str()); + if (success == false) { + SkDebugf("INVALID\" />\n"); + return false; + } + switch (value.fType) { + case SkType_Float: + SkDebugf("%g\" />\n", SkScalarToFloat(value.fOperand.fScalar)); + break; + case SkType_Int: + SkDebugf("%d\" />\n", value.fOperand.fS32); + break; + case SkType_String: + SkDebugf("%s\" />\n", value.fOperand.fString->c_str()); + break; + default: + return false; + } + return true; +} + +bool SkDump::hasEnable() const { + return true; +} + +void SkDump::GetEnumString(SkDisplayTypes type, int index, SkString* result) { + int badEnum = index; + const SkDisplayEnumMap& map = SkAnimatorScript::GetEnumValues(type); + const char* str = map.fValues; + while (--index >= 0) { + str = strchr(str, '|'); + if (str == nil) { + result->reset(); + result->appendS32(badEnum); + return; + } + str += 1; + } + const char* end = strchr(str, '|'); + if (end == nil) + end = str + strlen(str); + result->set(str, end - str); +} + +#else + +// in the release version, <dump> is allowed, and its attributes are defined, but +// are not stored and have no effect + +#if SK_USE_CONDENSED_INFO == 0 + +enum SkDump_Properties { + SK_PROPERTY(displayList), + SK_PROPERTY(eventList), + SK_PROPERTY(events), + SK_PROPERTY(groups), + SK_PROPERTY(name), + SK_PROPERTY(posts), + SK_PROPERTY(script) +}; + +const SkMemberInfo SkDump::fInfo[] = { + SK_MEMBER_PROPERTY(displayList, Boolean), + SK_MEMBER_PROPERTY(eventList, Boolean), + SK_MEMBER_PROPERTY(events, Boolean), + SK_MEMBER_PROPERTY(groups, Boolean), + SK_MEMBER_PROPERTY(name, String), + SK_MEMBER_PROPERTY(posts, Boolean), + SK_MEMBER_PROPERTY(script, String) +}; + +#endif + +DEFINE_GET_MEMBER(SkDump); + +bool SkDump::enable(SkAnimateMaker& maker ) { + return true; +} + +bool SkDump::hasEnable() const { + return true; +} + +bool SkDump::setProperty(int index, SkScriptValue& ) { + return index <= SK_PROPERTY(posts); +} + +#endif diff --git a/libs/graphics/animator/SkDump.h b/libs/graphics/animator/SkDump.h new file mode 100644 index 0000000000..2d9c99f4e4 --- /dev/null +++ b/libs/graphics/animator/SkDump.h @@ -0,0 +1,34 @@ +#ifndef SkDump_DEFINED +#define SkDump_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" + +class SkAnimateMaker; +class SkString; + +class SkDump : public SkDisplayable { + DECLARE_MEMBER_INFO(Dump); +#ifdef SK_DUMP_ENABLED + SkDump(); + virtual bool enable(SkAnimateMaker & ); + bool evaluate(SkAnimateMaker &); + virtual bool hasEnable() const; + static void GetEnumString(SkDisplayTypes , int index, SkString* result); + SkBool displayList; + SkBool eventList; + SkBool events; + SkString name; + SkBool groups; + SkBool posts; + SkString script; +#else + virtual bool enable(SkAnimateMaker & ); + virtual bool hasEnable() const; + virtual bool setProperty(int index, SkScriptValue& ); +#endif +}; + + +#endif // SkDump_DEFINED + diff --git a/libs/graphics/animator/SkExtraPathEffects.xsd b/libs/graphics/animator/SkExtraPathEffects.xsd new file mode 100644 index 0000000000..9592443a08 --- /dev/null +++ b/libs/graphics/animator/SkExtraPathEffects.xsd @@ -0,0 +1,33 @@ +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+xmlns:Sk="urn:screenplay"
+xmlns:extra="urn:extraPathEffects" targetNamespace="urn:extraPathEffects" >
+ <xs:import namespace="urn:screenplay"
+ schemaLocation="SkAnimateSchema.xsd" />
+
+ <xs:element name="composePathEffect" >
+ <xs:complexType>
+ <xs:choice maxOccurs="1">
+ <xs:element ref="Sk:dash"/>
+ <xs:element ref="extra:shape1DPathEffect"/>
+ </xs:choice>
+ <xs:attribute name="id" type="xs:ID"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="shape1DPathEffect" >
+ <xs:complexType>
+ <xs:choice maxOccurs="1">
+ <xs:element ref="Sk:matrix"/>
+ <xs:element ref="Sk:path"/>
+ </xs:choice>
+ <xs:attribute name="addPath" type="Sk:DynamicString" />
+ <xs:attribute name="matrix" type="Sk:DynamicString" />
+ <xs:attribute name="path" type="Sk:Path" />
+ <xs:attribute name="phase" type="Sk:DynamicString"/>
+ <xs:attribute name="spacing" type="Sk:DynamicString"/>
+ <xs:attribute name="id" type="xs:ID"/>
+ </xs:complexType>
+ </xs:element>
+
+</xs:schema>
+ diff --git a/libs/graphics/animator/SkExtras.h b/libs/graphics/animator/SkExtras.h new file mode 100644 index 0000000000..f8af4c5047 --- /dev/null +++ b/libs/graphics/animator/SkExtras.h @@ -0,0 +1,25 @@ +#ifndef SkExtras_DEFINED +#define SkExtras_DEFINED + +#include "SkScript.h" + +class SkExtras { +public: + SkExtras(); + virtual ~SkExtras() {} + + virtual SkDisplayable* createInstance(SkDisplayTypes type) = 0; + virtual bool definesType(SkDisplayTypes type) = 0; +#if SK_USE_CONDENSED_INFO == 0 + virtual const SkMemberInfo* getMembers(SkDisplayTypes type, int* infoCountPtr) = 0; +#endif +#ifdef SK_DEBUG + virtual const char* getName(SkDisplayTypes type) = 0; +#endif + virtual SkDisplayTypes getType(const char match[], size_t len ) = 0; + + SkScriptEngine::_propertyCallBack fExtraCallBack; + void* fExtraStorage; +}; + +#endif // SkExtras_DEFINED diff --git a/libs/graphics/animator/SkGetCondensedInfo.cpp b/libs/graphics/animator/SkGetCondensedInfo.cpp new file mode 100644 index 0000000000..28290fde1e --- /dev/null +++ b/libs/graphics/animator/SkGetCondensedInfo.cpp @@ -0,0 +1,113 @@ +#include "SkMemberInfo.h" + +#if SK_USE_CONDENSED_INFO == 1 + +// SkCondensed.cpp is auto-generated +// To generate it, execute SkDisplayType::BuildCondensedInfo() +#ifdef SK_DEBUG +#include "SkCondensedDebug.cpp" +#else +#include "SkCondensedRelease.cpp" +#endif + +static int _searchByName(const unsigned char* lengths, int count, const char* strings, const char target[]) { + int lo = 0; + int hi = count - 1; + while (lo < hi) { + int mid = (hi + lo) >> 1; + if (strcmp(&strings[lengths[mid << 2]], target) < 0) + lo = mid + 1; + else + hi = mid; + } + if (strcmp(&strings[lengths[hi << 2]], target) != 0) + return -1; + return hi; +} + +static int _searchByType(SkDisplayTypes type) { + unsigned char match = (unsigned char) type; + int lo = 0; + int hi = kTypeIDs - 1; + while (lo < hi) { + int mid = (hi + lo) >> 1; + if (gTypeIDs[mid] < match) + lo = mid + 1; + else + hi = mid; + } + if (gTypeIDs[hi] != type) + return -1; + return hi; +} + +const SkMemberInfo* SkDisplayType::GetMembers(SkAnimateMaker* , SkDisplayTypes type, int* infoCountPtr) { + int lookup = _searchByType(type); + if (lookup < 0) + return nil; + if (infoCountPtr) + *infoCountPtr = gInfoCounts[lookup]; + return gInfoTables[lookup]; +} + +// !!! replace with inline +const SkMemberInfo* SkDisplayType::GetMember(SkAnimateMaker* , SkDisplayTypes type, const char** matchPtr ) { + const SkMemberInfo* info = SkMemberInfo::Find(type, matchPtr); + SkASSERT(info); + return info; +} + +static const SkMemberInfo* _lookup(int lookup, const char** matchPtr) { + int count = gInfoCounts[lookup]; + const SkMemberInfo* info = gInfoTables[lookup]; + if (info->fType == SkType_BaseClassInfo) { + int baseTypeLookup = info->fOffset; + const SkMemberInfo* result = _lookup(baseTypeLookup, matchPtr); + if (result != nil) + return result; + if (--count == 0) + return nil; + info++; + } + SkASSERT(info->fType != SkType_BaseClassInfo); + const char* match = *matchPtr; + const char* strings = gInfoNames[lookup]; + int index = _searchByName(&info->fName, count, strings, match); + if (index < 0) + return nil; + return &info[index]; +} + +const SkMemberInfo* SkMemberInfo::Find(SkDisplayTypes type, int* index) { + int count = gInfoCounts[lookup]; + const SkMemberInfo* info = gInfoTables[lookup]; + if (info->fType == SkType_BaseClassInfo) { + int baseTypeLookup = info->fOffset; + const SkMemberInfo* result = Find(baseTypeLookup, index); + if (result != nil) + return result; + if (--count == 0) + return nil; + info++; + } + SkASSERT(info->fType != SkType_BaseClassInfo); + if (*index >= count) { + *index -= count; + return nil; + } + return &info[index]; +} + +const SkMemberInfo* SkMemberInfo::Find(SkDisplayTypes type, const char** matchPtr) { + int lookup = _searchByType(type); + SkASSERT(lookup >= 0); + return _lookup(lookup, matchPtr); +} + +const SkMemberInfo* SkMemberInfo::getInherited() const { + int baseTypeLookup = fOffset; + return gInfoTables[baseTypeLookup]; +} + +#endif + diff --git a/libs/graphics/animator/SkHitClear.cpp b/libs/graphics/animator/SkHitClear.cpp new file mode 100644 index 0000000000..6d90a5a449 --- /dev/null +++ b/libs/graphics/animator/SkHitClear.cpp @@ -0,0 +1,24 @@ +#include "SkHitClear.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkHitClear::fInfo[] = { + SK_MEMBER_ARRAY(targets, Displayable) +}; + +#endif + +DEFINE_GET_MEMBER(SkHitClear); + +bool SkHitClear::enable(SkAnimateMaker& maker) { + for (int tIndex = 0; tIndex < targets.count(); tIndex++) { + SkDisplayable* target = targets[tIndex]; + target->clearBounder(); + } + return true; +} + +bool SkHitClear::hasEnable() const { + return true; +} + diff --git a/libs/graphics/animator/SkHitClear.h b/libs/graphics/animator/SkHitClear.h new file mode 100644 index 0000000000..57bc6b55ae --- /dev/null +++ b/libs/graphics/animator/SkHitClear.h @@ -0,0 +1,16 @@ +#ifndef SkHitClear_DEFINED +#define SkHitClear_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" +#include "SkTypedArray.h" + +class SkHitClear : public SkDisplayable { + DECLARE_MEMBER_INFO(HitClear); + virtual bool enable(SkAnimateMaker& ); + virtual bool hasEnable() const; +private: + SkTDDisplayableArray targets; +}; + +#endif // SkHitClear_DEFINED diff --git a/libs/graphics/animator/SkHitTest.cpp b/libs/graphics/animator/SkHitTest.cpp new file mode 100644 index 0000000000..7e48adbe2c --- /dev/null +++ b/libs/graphics/animator/SkHitTest.cpp @@ -0,0 +1,66 @@ +#include "SkHitTest.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkHitTest::fInfo[] = { + SK_MEMBER_ARRAY(bullets, Displayable), + SK_MEMBER_ARRAY(hits, Int), + SK_MEMBER_ARRAY(targets, Displayable), + SK_MEMBER(value, Boolean) +}; + +#endif + +DEFINE_GET_MEMBER(SkHitTest); + +SkHitTest::SkHitTest() : value(false) { +} + +bool SkHitTest::draw(SkAnimateMaker& maker) { + hits.setCount(bullets.count()); + value = false; + int bulletCount = bullets.count(); + int targetCount = targets.count(); + for (int bIndex = 0; bIndex < bulletCount; bIndex++) { + SkDisplayable* bullet = bullets[bIndex]; + SkRect bBounds; + bullet->getBounds(&bBounds); + hits[bIndex] = -1; + if (bBounds.fLeft == (S16)0x8000U) + continue; + for (int tIndex = 0; tIndex < targetCount; tIndex++) { + SkDisplayable* target = targets[tIndex]; + SkRect tBounds; + target->getBounds(&tBounds); + if (bBounds.intersect(tBounds)) { + hits[bIndex] = tIndex; + value = true; + break; + } + } + } + return false; +} + +bool SkHitTest::enable(SkAnimateMaker& maker) { + for (int bIndex = 0; bIndex < bullets.count(); bIndex++) { + SkDisplayable* bullet = bullets[bIndex]; + bullet->enableBounder(); + } + for (int tIndex = 0; tIndex < targets.count(); tIndex++) { + SkDisplayable* target = targets[tIndex]; + target->enableBounder(); + } + return false; +} + +bool SkHitTest::hasEnable() const { + return true; +} + +const SkMemberInfo* SkHitTest::preferredChild(SkDisplayTypes type) { + if (bullets.count() == 0) + return getMember("bullets"); + return getMember("targets"); // !!! cwap! need to refer to member through enum like kScope instead +} + diff --git a/libs/graphics/animator/SkHitTest.h b/libs/graphics/animator/SkHitTest.h new file mode 100644 index 0000000000..a8c9fa457e --- /dev/null +++ b/libs/graphics/animator/SkHitTest.h @@ -0,0 +1,21 @@ +#ifndef SkHitTest_DEFINED +#define SkHitTest_DEFINED + +#include "SkDrawable.h" +#include "SkTypedArray.h" + +class SkHitTest : public SkDrawable { + DECLARE_MEMBER_INFO(HitTest); + SkHitTest(); + virtual bool draw(SkAnimateMaker& ); + virtual bool enable(SkAnimateMaker& ); + virtual bool hasEnable() const; + virtual const SkMemberInfo* preferredChild(SkDisplayTypes type); +private: + SkTDDisplayableArray bullets; + SkTDIntArray hits; + SkTDDisplayableArray targets; + SkBool value; +}; + +#endif // SkHitTest_DEFINED diff --git a/libs/graphics/animator/SkIntArray.h b/libs/graphics/animator/SkIntArray.h new file mode 100644 index 0000000000..f1824a129a --- /dev/null +++ b/libs/graphics/animator/SkIntArray.h @@ -0,0 +1,49 @@ +#ifndef SkIntArray_DEFINED +#define SkIntArray_DEFINED + +#include "SkColor.h" +#include "SkDisplayType.h" +#include "SkMath.h" +#include "SkTDArray_Experimental.h" + +class SkActive; +class SkAnimateBase; +class SkData; +class SkDisplayable; +class SkDisplayEvent; +class SkDrawable; +class SkDrawColor; +class SkMatrixPart; +struct SkMemberInfo; +class SkPathPart; +class SkPaintPart; +class SkTypedArray; +class SkString; +union SkOperand; + +typedef SkIntArray(int) SkTDIntArray; +typedef SkIntArray(SkColor) SkTDColorArray; +typedef SkIntArray(SkDisplayTypes) SkTDDisplayTypesArray; +typedef SkIntArray(SkMSec) SkTDMSecArray; +typedef SkIntArray(SkScalar) SkTDScalarArray; + +typedef SkLongArray(SkActive*) SkTDActiveArray; +typedef SkLongArray(SkAnimateBase*) SkTDAnimateArray; +typedef SkLongArray(SkData*) SkTDDataArray; +typedef SkLongArray(SkDisplayable*) SkTDDisplayableArray; +typedef SkLongArray(SkDisplayEvent*) SkTDDisplayEventArray; +typedef SkLongArray(SkDrawable*) SkTDDrawableArray; +typedef SkLongArray(SkDrawColor*) SkTDDrawColorArray; +typedef SkLongArray(SkMatrixPart*) SkTDMatrixPartArray; +typedef SkLongArray(const SkMemberInfo*) SkTDMemberInfoArray; +typedef SkLongArray(SkPaintPart*) SkTDPaintPartArray; +typedef SkLongArray(SkPathPart*) SkTDPathPartArray; +typedef SkLongArray(SkTypedArray*) SkTDTypedArrayArray; +typedef SkLongArray(SkString*) SkTDStringArray; +typedef SkLongArray(SkOperand) SkTDOperandArray; +typedef SkLongArray(SkOperand*) SkTDOperandPtrArray; + +#endif // SkIntArray_DEFINED + + + diff --git a/libs/graphics/animator/SkInterpolator.cpp b/libs/graphics/animator/SkInterpolator.cpp new file mode 100644 index 0000000000..f151bd4a23 --- /dev/null +++ b/libs/graphics/animator/SkInterpolator.cpp @@ -0,0 +1,252 @@ +#include "SkInterpolator.h" +#include "SkTSearch.h" + +SkInterpolatorBase::SkInterpolatorBase() +{ + fStorage = nil; + fTimes = nil; + SkDEBUGCODE(fTimesArray = nil;) +} + +SkInterpolatorBase::~SkInterpolatorBase() +{ + if (fStorage) + sk_free(fStorage); +} + +void SkInterpolatorBase::reset(int elemCount, int frameCount) +{ + fFlags = 0; + fElemCount = SkToU8(elemCount); + fFrameCount = SkToS16(frameCount); + fRepeat = SK_Scalar1; + if (fStorage) { + sk_free(fStorage); + fStorage = nil; + fTimes = nil; + SkDEBUGCODE(fTimesArray = nil); + } +} + +/* Each value[] run is formated as: + <time (in msec)> + <blend> + <data[fElemCount]> + + Totaling fElemCount+2 entries per keyframe +*/ + +bool SkInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const +{ + if (fFrameCount == 0) + return false; + + if (startTime) + *startTime = fTimes[0].fTime; + if (endTime) + *endTime = fTimes[fFrameCount - 1].fTime; + return true; +} + +SkScalar SkInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime, SkMSec nextTime, SkScalar blend) +{ + SkASSERT(time > prevTime && time < nextTime); + SkASSERT(blend >= 0); + + SkScalar t = SkScalarDiv((SkScalar)(time - prevTime), (SkScalar)(nextTime - prevTime)); + return Blend(t, blend); +} + +SkScalar SkInterpolatorBase::Blend(SkScalar t, SkScalar blend) +{ + // f(t) = -2(1-blend)t^3 + 3(1 - blend)t^2 + blend*t + return SkScalarMul(SkScalarMul(SkScalarMul(-2*(SK_Scalar1 - blend), t) + 3*(SK_Scalar1 - blend), t) + blend, t); +} + +SkInterpolatorBase::Result SkInterpolatorBase::timeToT(SkMSec time, SkScalar* T, int* indexPtr, SkBool* exactPtr) const +{ + SkASSERT(fFrameCount > 0); + Result result = kNormal_Result; + if (fRepeat != SK_Scalar1) + { + SkMSec startTime, endTime; + this->getDuration(&startTime, &endTime); + SkMSec totalTime = endTime - startTime; + SkMSec offsetTime = time - startTime; + endTime = SkScalarMulFloor(fRepeat, totalTime); + if (offsetTime >= endTime) + { + SkScalar fraction = SkScalarFraction(fRepeat); + offsetTime = fraction == 0 && fRepeat > 0 ? totalTime : + SkScalarMulFloor(fraction, totalTime); + result = kFreezeEnd_Result; + } + else + { + int mirror = fFlags & kMirror; + offsetTime = offsetTime % (totalTime << mirror); + if (offsetTime > totalTime) // can only be true if fMirror is true + offsetTime = (totalTime << 1) - offsetTime; + } + time = offsetTime + startTime; + } + + int index = SkTSearch<SkMSec>(&fTimes[0].fTime, fFrameCount, time, sizeof(SkTimeCode)); + + bool exact = true; + + if (index < 0) + { + index = ~index; + if (index == 0) + result = kFreezeStart_Result; + else if (index == fFrameCount) + { + if (fFlags & kReset) + index = 0; + else + index -= 1; + result = kFreezeEnd_Result; + } + else + exact = false; + } + SkASSERT(index < fFrameCount); + const SkTimeCode* nextTime = &fTimes[index]; + SkMSec nextT = nextTime[0].fTime; + if (exact) + *T = 0; + else { + SkMSec prevT = nextTime[-1].fTime; + *T = ComputeRelativeT(time, prevT, nextT, nextTime[-1].fBlend); + } + *indexPtr = index; + *exactPtr = exact; + return result; +} + + +SkInterpolator::SkInterpolator() { + INHERITED::reset(0, 0); + fValues = nil; + SkDEBUGCODE(fScalarsArray = nil;) +} + +SkInterpolator::SkInterpolator(int elemCount, int frameCount) +{ + SkASSERT(elemCount > 0); + this->reset(elemCount, frameCount); +} + +void SkInterpolator::reset(int elemCount, int frameCount) { + INHERITED::reset(elemCount, frameCount); + fStorage = sk_malloc_throw((sizeof(SkScalar) * elemCount + sizeof(SkTimeCode)) * frameCount); + fTimes = (SkTimeCode*) fStorage; + fValues = (SkScalar*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount); +#ifdef SK_DEBUG + fTimesArray = (SkTimeCode(*)[10]) fTimes; + fScalarsArray = (SkScalar(*)[10]) fValues; +#endif +} + +bool SkInterpolator::setKeyFrame(int index, SkMSec time, const SkScalar values[], SkScalar blend) +{ + SkASSERT(values != nil); + blend = SkScalarPin(blend, 0, SK_Scalar1); + + bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time, sizeof(SkTimeCode)); + SkASSERT(success); + if (success) { + SkTimeCode* timeCode = &fTimes[index]; + timeCode->fTime = time; + timeCode->fBlend = blend; + SkScalar* dst = &fValues[fElemCount * index]; + memcpy(dst, values, fElemCount * sizeof(SkScalar)); + } + return success; +} + +SkInterpolator::Result SkInterpolator::timeToValues(SkMSec time, SkScalar values[]) const +{ + SkScalar T; + int index; + SkBool exact; + Result result = timeToT(time, &T, &index, &exact); + if (values) + { + const SkScalar* nextSrc = &fValues[index * fElemCount]; + + if (exact) + memcpy(values, nextSrc, fElemCount * sizeof(SkScalar)); + else + { + SkASSERT(index > 0); + + const SkScalar* prevSrc = nextSrc - fElemCount; + + for (int i = fElemCount - 1; i >= 0; --i) + values[i] = SkScalarInterp(prevSrc[i], nextSrc[i], T); + } + } + return result; +} + + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_DEBUG + +#ifdef SK_SUPPORT_UNITTEST + static SkScalar* iset(SkScalar array[3], int a, int b, int c) + { + array[0] = SkIntToScalar(a); + array[1] = SkIntToScalar(b); + array[2] = SkIntToScalar(c); + return array; + } +#endif + +void SkInterpolator::UnitTest() +{ +#ifdef SK_SUPPORT_UNITTEST + SkInterpolator inter(3, 2); + SkScalar v1[3], v2[3], v[3], vv[3]; + Result result; + + inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0); + inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330)); + + result = inter.timeToValues(0, v); + SkASSERT(result == kFreezeStart_Result); + SkASSERT(memcmp(v, v1, sizeof(v)) == 0); + + result = inter.timeToValues(99, v); + SkASSERT(result == kFreezeStart_Result); + SkASSERT(memcmp(v, v1, sizeof(v)) == 0); + + result = inter.timeToValues(100, v); + SkASSERT(result == kNormal_Result); + SkASSERT(memcmp(v, v1, sizeof(v)) == 0); + + result = inter.timeToValues(200, v); + SkASSERT(result == kNormal_Result); + SkASSERT(memcmp(v, v2, sizeof(v)) == 0); + + result = inter.timeToValues(201, v); + SkASSERT(result == kFreezeEnd_Result); + SkASSERT(memcmp(v, v2, sizeof(v)) == 0); + + result = inter.timeToValues(150, v); + SkASSERT(result == kNormal_Result); + SkASSERT(memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0); + + result = inter.timeToValues(125, v); + SkASSERT(result == kNormal_Result); + result = inter.timeToValues(175, v); + SkASSERT(result == kNormal_Result); +#endif +} + +#endif + diff --git a/libs/graphics/animator/SkMatrixParts.cpp b/libs/graphics/animator/SkMatrixParts.cpp new file mode 100644 index 0000000000..b9a06333d6 --- /dev/null +++ b/libs/graphics/animator/SkMatrixParts.cpp @@ -0,0 +1,284 @@ +#include "SkMatrixParts.h" +#include "SkAnimateMaker.h" +#include "SkDrawMatrix.h" +#include "SkDrawRectangle.h" +#include "SkDrawPath.h" + +SkMatrixPart::SkMatrixPart() : fMatrix(nil) { +} + +void SkMatrixPart::dirty() { + fMatrix->dirty(); +} + +SkDisplayable* SkMatrixPart::getParent() const { + return fMatrix; +} + +bool SkMatrixPart::setParent(SkDisplayable* parent) { + SkASSERT(parent != nil); + if (parent->isMatrix() == false) + return true; + fMatrix = (SkDrawMatrix*) parent; + return false; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkRotate::fInfo[] = { + SK_MEMBER(center, Point), + SK_MEMBER(degrees, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkRotate); + +SkRotate::SkRotate() : degrees(0) { + center.fX = center.fY = 0; +} + +bool SkRotate::add() { + fMatrix->rotate(degrees, center); + return false; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkScale::fInfo[] = { + SK_MEMBER(center, Point), + SK_MEMBER(x, Float), + SK_MEMBER(y, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkScale); + +SkScale::SkScale() : x(SK_Scalar1), y(SK_Scalar1) { + center.fX = center.fY = 0; +} + +bool SkScale::add() { + fMatrix->scale(x, y, center); + return false; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkSkew::fInfo[] = { + SK_MEMBER(center, Point), + SK_MEMBER(x, Float), + SK_MEMBER(y, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkSkew); + +SkSkew::SkSkew() : x(0), y(0) { + center.fX = center.fY = 0; +} + +bool SkSkew::add() { + fMatrix->skew(x, y, center); + return false; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkTranslate::fInfo[] = { + SK_MEMBER(x, Float), + SK_MEMBER(y, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkTranslate); + +SkTranslate::SkTranslate() : x(0), y(0) { +} + +bool SkTranslate::add() { + fMatrix->translate(x, y); + return false; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkFromPath::fInfo[] = { + SK_MEMBER(mode, FromPathMode), + SK_MEMBER(offset, Float), + SK_MEMBER(path, Path) +}; + +#endif + +DEFINE_GET_MEMBER(SkFromPath); + +SkFromPath::SkFromPath() : + mode(0), offset(0), path(nil) { +} + +SkFromPath::~SkFromPath() { +} + +bool SkFromPath::add() { + if (path == nil) + return true; + static const U8 gFlags[] = { + SkPathMeasure::kGetPosAndTan_MatrixFlag, // normal + SkPathMeasure::kGetTangent_MatrixFlag, // angle + SkPathMeasure::kGetPosition_MatrixFlag // position + }; + if ((unsigned)mode >= SK_ARRAY_COUNT(gFlags)) + return true; + SkMatrix result; + fPathMeasure.setPath(&path->getPath(), false); + if (fPathMeasure.getMatrix(offset, &result, (SkPathMeasure::MatrixFlags)gFlags[mode])) + fMatrix->set(result); + return false; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkRectToRect::fInfo[] = { + SK_MEMBER(destination, Rect), + SK_MEMBER(source, Rect) +}; + +#endif + +DEFINE_GET_MEMBER(SkRectToRect); + +SkRectToRect::SkRectToRect() : + source(nil), destination(nil) { +} + +SkRectToRect::~SkRectToRect() { +} + +bool SkRectToRect::add() { + if (source == nil || destination == nil) + return true; + SkMatrix temp; + temp.setRectToRect(source->fRect, destination->fRect); + fMatrix->set(temp); + return false; +} + +#ifdef SK_DUMP_ENABLED +void SkRectToRect::dump(SkAnimateMaker* maker) { + dumpBase(maker); + SkDebugf("/>\n"); + SkDisplayList::fIndent += 4; + if (source) { + SkDebugf("%*s<source>\n", SkDisplayList::fIndent, ""); + SkDisplayList::fIndent += 4; + source->dump(maker); + SkDisplayList::fIndent -= 4; + SkDebugf("%*s</source>\n", SkDisplayList::fIndent, ""); + } + if (destination) { + SkDebugf("%*s<destination>\n", SkDisplayList::fIndent, ""); + SkDisplayList::fIndent += 4; + destination->dump(maker); + SkDisplayList::fIndent -= 4; + SkDebugf("%*s</destination>\n", SkDisplayList::fIndent, ""); + } + SkDisplayList::fIndent -= 4; + dumpEnd(maker); +} +#endif + +const SkMemberInfo* SkRectToRect::preferredChild(SkDisplayTypes ) { + if (source == nil) + return getMember("source"); // !!! cwap! need to refer to member through enum like kScope instead + else { + SkASSERT(destination == nil); + return getMember("destination"); + } +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkPolyToPoly::fInfo[] = { + SK_MEMBER(destination, Polygon), + SK_MEMBER(source, Polygon) +}; + +#endif + +DEFINE_GET_MEMBER(SkPolyToPoly); + +SkPolyToPoly::SkPolyToPoly() : source(nil), destination(nil) { +} + +SkPolyToPoly::~SkPolyToPoly() { +} + +bool SkPolyToPoly::add() { + SkASSERT(source); + SkASSERT(destination); + SkPoint src[4]; + SkPoint dst[4]; + SkPath& sourcePath = source->getPath(); + int srcPts = sourcePath.getPoints(src, 4); + SkPath& destPath = destination->getPath(); + int dstPts = destPath.getPoints(dst, 4); + if (srcPts != dstPts) + return true; + SkMatrix temp; + temp.setPolyToPoly(dst, src, srcPts); + fMatrix->set(temp); + return false; +} + +#ifdef SK_DUMP_ENABLED +void SkPolyToPoly::dump(SkAnimateMaker* maker) { + dumpBase(maker); + SkDebugf("/>\n"); + SkDisplayList::fIndent += 4; + if (source) { + SkDebugf("%*s<source>\n", SkDisplayList::fIndent, ""); + SkDisplayList::fIndent += 4; + source->dump(maker); + SkDisplayList::fIndent -= 4; + SkDebugf("%*s</source>\n", SkDisplayList::fIndent, ""); + } + if (destination) { + SkDebugf("%*s<destination>\n", SkDisplayList::fIndent, ""); + SkDisplayList::fIndent += 4; + destination->dump(maker); + SkDisplayList::fIndent -= 4; + SkDebugf("%*s</destination>\n", SkDisplayList::fIndent, ""); + } + SkDisplayList::fIndent -= 4; + dumpEnd(maker); +} +#endif + +void SkPolyToPoly::onEndElement(SkAnimateMaker& ) { + SkASSERT(source); + SkASSERT(destination); + if (source->childHasID() || destination->childHasID()) + fMatrix->setChildHasID(); +} + +const SkMemberInfo* SkPolyToPoly::preferredChild(SkDisplayTypes ) { + if (source == nil) + return getMember("source"); // !!! cwap! need to refer to member through enum like kScope instead + else { + SkASSERT(destination == nil); + return getMember("destination"); + } +} + + diff --git a/libs/graphics/animator/SkMatrixParts.h b/libs/graphics/animator/SkMatrixParts.h new file mode 100644 index 0000000000..95353551c0 --- /dev/null +++ b/libs/graphics/animator/SkMatrixParts.h @@ -0,0 +1,110 @@ +#ifndef SkMatrixParts_DEFINED +#define SkMatrixParts_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" +#include "SkPathMeasure.h" + +class SkDrawPath; +class SkDrawRect; +class SkPolygon; + +class SkDrawMatrix; +// class SkMatrix; + +class SkMatrixPart : public SkDisplayable { +public: + SkMatrixPart(); + virtual bool add() = 0; + virtual void dirty(); + virtual SkDisplayable* getParent() const; + virtual bool setParent(SkDisplayable* parent); +#ifdef SK_DEBUG + virtual bool isMatrixPart() const { return true; } +#endif +protected: + SkDrawMatrix* fMatrix; +}; + +class SkRotate : public SkMatrixPart { + DECLARE_MEMBER_INFO(Rotate); + SkRotate(); +protected: + virtual bool add(); + SkScalar degrees; + SkPoint center; +}; + +class SkScale : public SkMatrixPart { + DECLARE_MEMBER_INFO(Scale); + SkScale(); +protected: + virtual bool add(); + SkScalar x; + SkScalar y; + SkPoint center; +}; + +class SkSkew : public SkMatrixPart { + DECLARE_MEMBER_INFO(Skew); + SkSkew(); +protected: + virtual bool add(); + SkScalar x; + SkScalar y; + SkPoint center; +}; + +class SkTranslate : public SkMatrixPart { + DECLARE_MEMBER_INFO(Translate); + SkTranslate(); +protected: + virtual bool add(); + SkScalar x; + SkScalar y; +}; + +class SkFromPath : public SkMatrixPart { + DECLARE_MEMBER_INFO(FromPath); + SkFromPath(); + virtual ~SkFromPath(); +protected: + virtual bool add(); + S32 mode; + SkScalar offset; + SkDrawPath* path; + SkPathMeasure fPathMeasure; +}; + +class SkRectToRect : public SkMatrixPart { + DECLARE_MEMBER_INFO(RectToRect); + SkRectToRect(); + virtual ~SkRectToRect(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual const SkMemberInfo* preferredChild(SkDisplayTypes type); +protected: + virtual bool add(); + SkDrawRect* source; + SkDrawRect* destination; +}; + +class SkPolyToPoly : public SkMatrixPart { + DECLARE_MEMBER_INFO(PolyToPoly); + SkPolyToPoly(); + virtual ~SkPolyToPoly(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker* ); +#endif + virtual void onEndElement(SkAnimateMaker& ); + virtual const SkMemberInfo* preferredChild(SkDisplayTypes type); +protected: + virtual bool add(); + SkPolygon* source; + SkPolygon* destination; +}; + +// !!! add concat matrix ? + +#endif // SkMatrixParts_DEFINED diff --git a/libs/graphics/animator/SkMemberInfo.cpp b/libs/graphics/animator/SkMemberInfo.cpp new file mode 100644 index 0000000000..9ad26d6894 --- /dev/null +++ b/libs/graphics/animator/SkMemberInfo.cpp @@ -0,0 +1,551 @@ +#include "SkMemberInfo.h" +#include "SkAnimateMaker.h" +#include "SkAnimatorScript.h" +#include "SkBase64.h" +#include "SkCamera.h" +#include "SkDisplayable.h" +#include "SkDisplayTypes.h" +#include "SkDraw3D.h" +#include "SkDrawColor.h" +#include "SkParse.h" +#include "SkScript.h" +#include "SkTSearch.h" +#include "SkTypedArray.h" + +size_t SkMemberInfo::GetSize(SkDisplayTypes type) { // size of simple types only + size_t byteSize; + switch (type) { + case SkType_ARGB: + byteSize = sizeof(SkColor); + break; + case SkType_AddMode: + case SkType_Align: + case SkType_ApplyMode: + case SkType_ApplyTransition: + case SkType_BitmapEncoding: + case SkType_Boolean: + case SkType_Cap: + case SkType_EventCode: + case SkType_EventKind: + case SkType_EventMode: + case SkType_FilterType: + case SkType_FontStyle: + case SkType_FromPathMode: + case SkType_Join: + case SkType_MaskFilterBlurStyle: + case SkType_PathDirection: + case SkType_Style: + case SkType_TileMode: + case SkType_Xfermode: + byteSize = sizeof(int); + break; + case SkType_Base64: // assume base64 data is always const, copied by ref + case SkType_Displayable: + case SkType_Drawable: + case SkType_Matrix: + byteSize = sizeof(void*); + break; + case SkType_MSec: + byteSize = sizeof(SkMSec); + break; + case SkType_Point: + byteSize = sizeof(SkPoint); + break; + case SkType_3D_Point: + byteSize = sizeof(Sk3D_Point); + break; + case SkType_Int: + byteSize = sizeof(S32); + break; + case SkType_Float: + byteSize = sizeof(SkScalar); + break; + case SkType_DynamicString: + case SkType_String: + byteSize = sizeof(SkString); // assume we'll copy by reference, not value + break; + default: +// SkASSERT(0); + byteSize = 0; + } + return byteSize; +} + +bool SkMemberInfo::getArrayValue(const SkDisplayable* displayable, int index, SkOperand* value) const { + SkASSERT(fType != SkType_String && fType != SkType_MemberProperty); + char* valuePtr = (char*) *(SkOperand**) memberData(displayable); + SkDisplayTypes type = (SkDisplayTypes) 0; + if (displayable->getType() == SkType_Array) { + SkDisplayArray* dispArray = (SkDisplayArray*) displayable; + if (dispArray->values.count() <= index) + return false; + type = dispArray->values.getType(); + } else + SkASSERT(0); // incomplete + size_t byteSize = GetSize(type); + memcpy(value, valuePtr + index * byteSize, byteSize); + return true; +} + +size_t SkMemberInfo::getSize(const SkDisplayable* displayable) const { + size_t byteSize; + switch (fType) { + case SkType_MemberProperty: + byteSize = GetSize(propertyType()); + break; + case SkType_Array: { + SkDisplayTypes type; + if (displayable == nil) + return sizeof(int); + if (displayable->getType() == SkType_Array) { + SkDisplayArray* dispArray = (SkDisplayArray*) displayable; + type = dispArray->values.getType(); + } else + type = propertyType(); + SkTDOperandArray* array = (SkTDOperandArray*) memberData(displayable); + byteSize = GetSize(type) * array->count(); + } break; + default: + byteSize = GetSize((SkDisplayTypes) fType); + } + return byteSize; +} + +void SkMemberInfo::getString(const SkDisplayable* displayable, SkString** string) const { + if (fType == SkType_MemberProperty) { + SkScriptValue value; + displayable->getProperty(propertyIndex(), &value); + SkASSERT(value.fType == SkType_String); + *string = value.fOperand.fString; + return; + } + SkASSERT(fCount == sizeof(SkString) / sizeof(SkScalar)); + SkASSERT(fType == SkType_String || fType == SkType_DynamicString); + void* valuePtr = memberData(displayable); + *string = (SkString*) valuePtr; +} + +void SkMemberInfo::getValue(const SkDisplayable* displayable, SkOperand value[], int count) const { + SkASSERT(fType != SkType_String && fType != SkType_MemberProperty); + SkASSERT(count == fCount); + void* valuePtr = memberData(displayable); + size_t byteSize = getSize(displayable); + SkASSERT(sizeof(value[0].fScalar) == sizeof(value[0])); // no support for 64 bit pointers, yet + memcpy(value, valuePtr, byteSize); +} + +void SkMemberInfo::setString(SkDisplayable* displayable, SkString* value) const { + SkString* string = (SkString*) memberData(displayable); + string->set(*value); + displayable->dirty(); +} + +void SkMemberInfo::setValue(SkDisplayable* displayable, const SkOperand values[], + int count) const { + SkASSERT(sizeof(values[0].fScalar) == sizeof(values[0])); // no support for 64 bit pointers, yet + char* dst = (char*) memberData(displayable); + if (fType == SkType_Array) { + SkTDScalarArray* array = (SkTDScalarArray* ) dst; + array->setCount(count); + dst = (char*) array->begin(); + } + memcpy(dst, values, count * sizeof(SkOperand)); + displayable->dirty(); +} + + +static inline bool is_between(int c, int min, int max) +{ + return (unsigned)(c - min) <= (unsigned)(max - min); +} + +static inline bool is_hex(int c) +{ + if (is_between(c, '0', '9')) + return true; + c |= 0x20; // make us lower-case + if (is_between(c, 'a', 'f')) + return true; + return false; +} + + +bool SkMemberInfo::setValue(SkAnimateMaker& maker, SkTDOperandArray* arrayStorage, + int storageOffset, int maxStorage, SkDisplayable* displayable, SkDisplayTypes outType, + const char rawValue[], size_t rawValueLen) const +{ + SkString valueStr(rawValue, rawValueLen); + SkScriptValue scriptValue; + scriptValue.fType = SkType_Unknown; + scriptValue.fOperand.fS32 = 0; + SkDisplayTypes type = getType(); + SkAnimatorScript engine(maker, displayable, type); + if (arrayStorage) + displayable = nil; + bool success = true; + void* untypedStorage = nil; + if (displayable && fType != SkType_MemberProperty && fType != SkType_MemberFunction) + untypedStorage = (SkTDOperandArray*) memberData(displayable); + + if (type == SkType_ARGB) { + // for both SpiderMonkey and SkiaScript, substitute any #xyz or #xxyyzz first + // it's enough to expand the colors into 0xFFxxyyzz + const char* poundPos; + while ((poundPos = strchr(valueStr.c_str(), '#')) != nil) { + size_t offset = poundPos - valueStr.c_str(); + if (valueStr.size() - offset < 4) + break; + char r = poundPos[1]; + char g = poundPos[2]; + char b = poundPos[3]; + if (is_hex(r) == false || is_hex(g) == false || is_hex(b) == false) + break; + char hex = poundPos[4]; + if (is_hex(hex) == false) { + valueStr.insertUnichar(offset + 1, r); + valueStr.insertUnichar(offset + 3, g); + valueStr.insertUnichar(offset + 5, b); + } + *(char*) poundPos = '0'; // overwrite '#' + valueStr.insert(offset + 1, "xFF"); + } + } + if (SkDisplayType::IsDisplayable(&maker, type) || SkDisplayType::IsEnum(&maker, type) || type == SkType_ARGB) + goto scriptCommon; + switch (type) { + case SkType_String: +#if 0 + if (displayable && displayable->isAnimate()) { + + goto noScriptString; + } + if (strncmp(rawValue, "#string:", sizeof("#string:") - 1) == 0) { + SkASSERT(sizeof("string") == sizeof("script")); + char* stringHeader = valueStr.writable_str(); + memcpy(&stringHeader[1], "script", sizeof("script") - 1); + rawValue = valueStr.c_str(); + goto noScriptString; + } else +#endif + if (strncmp(rawValue, "#script:", sizeof("#script:") - 1) != 0) + goto noScriptString; + valueStr.remove(0, 8); + case SkType_Unknown: + case SkType_Int: + case SkType_MSec: // for the purposes of script, MSec is treated as a Scalar + case SkType_Point: + case SkType_3D_Point: + case SkType_Float: + case SkType_Array: +scriptCommon: { + const char* script = valueStr.c_str(); + success = engine.evaluateScript(&script, &scriptValue); + if (success == false) { + maker.setScriptError(engine); + return false; + } + } + SkASSERT(success); + if (scriptValue.fType == SkType_Displayable) { + if (type == SkType_String) { + const char* charPtr; + maker.findKey(scriptValue.fOperand.fDisplayable, &charPtr); + scriptValue.fOperand.fString = new SkString(charPtr); + scriptValue.fType = SkType_String; + engine.SkScriptEngine::track(scriptValue.fOperand.fString); + break; + } + SkASSERT(SkDisplayType::IsDisplayable(&maker, type)); + if (displayable) + displayable->setReference(this, scriptValue.fOperand.fDisplayable); + else + arrayStorage->begin()[0].fDisplayable = scriptValue.fOperand.fDisplayable; + return true; + } + if (type != scriptValue.fType) { + if (scriptValue.fType == SkType_Array) { + engine.forget(scriptValue.getArray()); + goto writeStruct; // real structs have already been written by script + } + switch (type) { + case SkType_String: + success = engine.convertTo(SkType_String, &scriptValue); + break; + case SkType_MSec: + case SkType_Float: + success = engine.convertTo(SkType_Float, &scriptValue); + break; + case SkType_Int: + success = engine.convertTo(SkType_Int, &scriptValue); + break; + case SkType_Array: + success = engine.convertTo(arrayType(), &scriptValue); + // !!! incomplete; create array of appropriate type and add scriptValue to it + SkASSERT(0); + break; + case SkType_Displayable: + case SkType_Drawable: + return false; // no way to convert other types to this + default: // to avoid warnings + break; + } + if (success == false) + return false; + } + if (type == SkType_MSec) + scriptValue.fOperand.fMSec = SkScalarMulRound(scriptValue.fOperand.fScalar, 1000); + scriptValue.fType = type; + break; + noScriptString: + case SkType_DynamicString: + if (fType == SkType_MemberProperty && displayable) { + SkString string(rawValue, rawValueLen); + SkScriptValue scriptValue; + scriptValue.fOperand.fString = &string; + scriptValue.fType = SkType_String; + displayable->setProperty(propertyIndex(), scriptValue); + } else if (displayable) { + SkString* string = (SkString*) memberData(displayable); + string->set(rawValue, rawValueLen); + } else { + SkASSERT(arrayStorage->count() == 1); + arrayStorage->begin()->fString->set(rawValue, rawValueLen); + } + goto dirty; + case SkType_Base64: { + SkBase64 base64; + base64.decode(rawValue, rawValueLen); + *(SkBase64* ) untypedStorage = base64; + } goto dirty; + default: + SkASSERT(0); + break; + } +// if (SkDisplayType::IsStruct(type) == false) + { +writeStruct: + if (writeValue(displayable, arrayStorage, storageOffset, maxStorage, + untypedStorage, outType, scriptValue)) { + maker.setErrorCode(SkDisplayXMLParserError::kUnexpectedType); + return false; + } + } +dirty: + if (displayable) + displayable->dirty(); + return true; +} + +bool SkMemberInfo::setValue(SkAnimateMaker& maker, SkTDOperandArray* arrayStorage, + int storageOffset, int maxStorage, SkDisplayable* displayable, SkDisplayTypes outType, + SkString& raw) const { + return setValue(maker, arrayStorage, storageOffset, maxStorage, displayable, outType, raw.c_str(), + raw.size()); +} + +bool SkMemberInfo::writeValue(SkDisplayable* displayable, SkTDOperandArray* arrayStorage, + int storageOffset, int maxStorage, void* untypedStorage, SkDisplayTypes outType, + SkScriptValue& scriptValue) const +{ + SkOperand* storage = untypedStorage ? (SkOperand*) untypedStorage : arrayStorage ? + arrayStorage->begin() : nil; + if (storage) + storage += storageOffset; + SkDisplayTypes type = getType(); + if (fType == SkType_MemberProperty) { + if(displayable) + displayable->setProperty(propertyIndex(), scriptValue); + else { + SkASSERT(storageOffset < arrayStorage->count()); + switch (scriptValue.fType) { + case SkType_Boolean: + case SkType_Float: + case SkType_Int: + memcpy(&storage->fScalar, &scriptValue.fOperand.fScalar, sizeof(SkScalar)); + break; + case SkType_Array: + memcpy(&storage->fScalar, scriptValue.fOperand.fArray->begin(), scriptValue.fOperand.fArray->count() * sizeof(SkScalar)); + break; + case SkType_String: + storage->fString->set(*scriptValue.fOperand.fString); + break; + default: + SkASSERT(0); // type isn't handled yet + } + } + } else if (fType == SkType_MemberFunction) { + SkASSERT(scriptValue.fType == SkType_Array); + if (displayable) + displayable->executeFunction(displayable, this, scriptValue.fOperand.fArray, nil); + else { + int count = scriptValue.fOperand.fArray->count(); + // SkASSERT(maxStorage == 0 || count == maxStorage); + if (arrayStorage->count() == 2) + arrayStorage->setCount(2 * count); + else { + storageOffset *= count; + SkASSERT(count + storageOffset <= arrayStorage->count()); + } + memcpy(&(*arrayStorage)[storageOffset], scriptValue.fOperand.fArray->begin(), count * sizeof(SkOperand)); + } + + } else if (fType == SkType_Array) { + SkTypedArray* destArray = (SkTypedArray*) (untypedStorage ? untypedStorage : arrayStorage); + SkASSERT(destArray); + // destArray->setCount(0); + if (scriptValue.fType != SkType_Array) { + SkASSERT(type == scriptValue.fType); + // SkASSERT(storageOffset + 1 <= maxStorage); + destArray->setCount(storageOffset + 1); + (*destArray)[storageOffset] = scriptValue.fOperand; + } else { + if (type == SkType_Unknown) { + type = scriptValue.fOperand.fArray->getType(); + destArray->setType(type); + } + SkASSERT(type == scriptValue.fOperand.fArray->getType()); + int count = scriptValue.fOperand.fArray->count(); + // SkASSERT(storageOffset + count <= maxStorage); + destArray->setCount(storageOffset + count); + memcpy(destArray->begin() + storageOffset, scriptValue.fOperand.fArray->begin(), sizeof(SkOperand) * count); + } + } else if (type == SkType_String) { + SkString* string = untypedStorage ? (SkString*) untypedStorage : (*arrayStorage)[storageOffset].fString; + string->set(*scriptValue.fOperand.fString); + } else if (type == SkType_ARGB && outType == SkType_Float) { + SkTypedArray* array = scriptValue.fOperand.fArray; + SkASSERT(scriptValue.fType == SkType_Int || scriptValue.fType == SkType_ARGB || + scriptValue.fType == SkType_Array); + SkASSERT(scriptValue.fType != SkType_Array || (array != nil && + array->getType() == SkType_Int)); + int numberOfColors = scriptValue.fType == SkType_Array ? array->count() : 1; + int numberOfComponents = numberOfColors * 4; + // SkASSERT(maxStorage == 0 || maxStorage == numberOfComponents); + if (maxStorage == 0) + arrayStorage->setCount(numberOfComponents); + for (int index = 0; index < numberOfColors; index++) { + SkColor color = scriptValue.fType == SkType_Array ? + (SkColor) array->begin()[index].fS32 : (SkColor) scriptValue.fOperand.fS32; + storage[0].fScalar = SkIntToScalar(SkColorGetA(color)); + storage[1].fScalar = SkIntToScalar(SkColorGetR(color)); + storage[2].fScalar = SkIntToScalar(SkColorGetG(color)); + storage[3].fScalar = SkIntToScalar(SkColorGetB(color)); + storage += 4; + } + } else if (SkDisplayType::IsStruct(nil /* !!! maker*/, type)) { + if (scriptValue.fType != SkType_Array) + return true; // error + SkASSERT(sizeof(SkScalar) == sizeof(SkOperand)); // !!! no 64 bit pointer support yet + int count = scriptValue.fOperand.fArray->count(); + if (count > 0) { + SkASSERT(fCount == count); + memcpy(storage, scriptValue.fOperand.fArray->begin(), count * sizeof(SkOperand)); + } + } else if (scriptValue.fType == SkType_Array) { + SkASSERT(scriptValue.fOperand.fArray->getType() == type); + SkASSERT(scriptValue.fOperand.fArray->count() == getCount()); + memcpy(storage, scriptValue.fOperand.fArray->begin(), getCount() * sizeof(SkOperand)); + } else { + memcpy(storage, &scriptValue.fOperand, sizeof(SkOperand)); + } + return false; +} + + +//void SkMemberInfo::setValue(SkDisplayable* displayable, const char value[], const char name[]) const { +// void* valuePtr = (void*) ((char*) displayable + fOffset); +// switch (fType) { +// case SkType_Point3D: { +// static const char xyz[] = "x|y|z"; +// int index = find_one(xyz, name); +// SkASSERT(index >= 0); +// valuePtr = (void*) ((char*) valuePtr + index * sizeof(SkScalar)); +// } break; +// default: +// SkASSERT(0); +// } +// SkParse::FindScalar(value, (SkScalar*) valuePtr); +// displayable->dirty(); +//} + +#if SK_USE_CONDENSED_INFO == 0 + +// Find Nth memberInfo +const SkMemberInfo* SkMemberInfo::Find(const SkMemberInfo info[], int count, int* index) { + SkASSERT(*index >= 0); + if (info->fType == SkType_BaseClassInfo) { + const SkMemberInfo* inherited = (SkMemberInfo*) info->fName; + const SkMemberInfo* result = SkMemberInfo::Find(inherited, info->fCount, index); + if (result != nil) + return result; + if (--count == 0) + return nil; + info++; + } + SkASSERT(info->fName); + SkASSERT(info->fType != SkType_BaseClassInfo); + if (*index >= count) { + *index -= count; + return nil; + } + return &info[*index]; +} + +// Find named memberinfo +const SkMemberInfo* SkMemberInfo::Find(const SkMemberInfo info[], int count, const char** matchPtr) { + const char* match = *matchPtr; + if (info->fType == SkType_BaseClassInfo) { + const SkMemberInfo* inherited = (SkMemberInfo*) info->fName; + const SkMemberInfo* result = SkMemberInfo::Find(inherited, info->fCount, matchPtr); + if (result != nil) + return result; + if (--count == 0) + return nil; + info++; + } + SkASSERT(info->fName); + SkASSERT(info->fType != SkType_BaseClassInfo); + int index = SkStrSearch(&info->fName, count, match, sizeof(*info)); + if (index < 0 || index >= count) + return nil; + return &info[index]; +} + +const SkMemberInfo* SkMemberInfo::getInherited() const { + return (SkMemberInfo*) fName; +} + +#endif // SK_USE_CONDENSED_INFO == 0 + +#if 0 +bool SkMemberInfo::SetValue(void* valuePtr, const char value[], SkDisplayTypes type, + int count) { + switch (type) { + case SkType_Animate: + case SkType_BaseBitmap: + case SkType_Bitmap: + case SkType_Dash: + case SkType_Displayable: + case SkType_Drawable: + case SkType_Matrix: + case SkType_Path: + case SkType_Text: + case SkType_3D_Patch: + return false; // ref to object; caller must resolve + case SkType_MSec: { + SkParse::FindMSec(value, (SkMSec*) valuePtr); + } break; + case SkType_3D_Point: + case SkType_Point: + // case SkType_PointArray: + case SkType_ScalarArray: + SkParse::FindScalars(value, (SkScalar*) valuePtr, count); + break; + default: + SkASSERT(0); + } + return true; +} +#endif + + diff --git a/libs/graphics/animator/SkMemberInfo.h b/libs/graphics/animator/SkMemberInfo.h new file mode 100644 index 0000000000..ec66846b07 --- /dev/null +++ b/libs/graphics/animator/SkMemberInfo.h @@ -0,0 +1,266 @@ +#ifndef SkMemberInfo_DEFINED +#define SkMemberInfo_DEFINED + +#if defined SK_BUILD_CONDENSED + #define SK_USE_CONDENSED_INFO 0 +#elif defined SK_BUILD_FOR_BREW + #define SK_USE_CONDENSED_INFO 1 /* required by BREW to handle its lack of writable globals */ +#else + #define SK_USE_CONDENSED_INFO 0 /* optional, but usually 1 unless Cary is testing something */ +#endif + +#include "SkDisplayType.h" +#include "SkScript.h" +#include "SkString.h" +#include "SkIntArray.h" + +class SkAnimateMaker; +class SkDisplayable; +class SkScriptEngine; + +// temporary hacks until name change is more complete +#define SkFloat SkScalar +#define SkInt SkS32 + +struct SkMemberInfo { + //!!! alternative: + // if fCount == 0, record is member property + // then fType can be type, so caller doesn't have to check +#if SK_USE_CONDENSED_INFO == 0 + const char* fName; // may be nil for anonymous functions + size_t fOffset; // if negative, is index into member pointer table (for properties and functions) + SkDisplayTypes fType; + int fCount; // for properties, actual type (count is always assumed to be 1) +#else + unsigned char fName; + signed char fOffset; + unsigned char fType; + signed char fCount; +#endif + SkDisplayTypes arrayType() const { + SkASSERT(fType == SkType_Array); + return (SkDisplayTypes) fCount; // hack, but worth it? + } + int functionIndex() const { + SkASSERT(fType == SkType_MemberFunction); + return (signed) fOffset > 0 ? -1 + (int) fOffset : -1 - (int) fOffset; + } + bool getArrayValue(const SkDisplayable* displayable, int index, SkOperand* value) const; + int getCount() const { + return fType == SkType_MemberProperty || fType == SkType_Array || + fType == SkType_MemberFunction ? 1 : fCount; + } + const SkMemberInfo* getInherited() const; + size_t getSize(const SkDisplayable* ) const; + void getString(const SkDisplayable* , SkString** string) const; + SkDisplayTypes getType() const { + return fType == SkType_MemberProperty || fType == SkType_Array || + fType == SkType_MemberFunction ? (SkDisplayTypes) fCount : (SkDisplayTypes) fType; + } + void getValue(const SkDisplayable* , SkOperand values[], int count) const; + bool isEnum() const; + const char* mapEnums(const char* match, int* value) const; + void* memberData(const SkDisplayable* displayable) const { + SkASSERT(fType != SkType_MemberProperty && fType != SkType_MemberFunction); + return (void*) ((const char*) displayable + fOffset); + } + int propertyIndex() const { + SkASSERT(fType == SkType_MemberProperty); + return (signed) fOffset > 0 ? -1 + (int) fOffset : -1 - (int) fOffset; + } + SkDisplayTypes propertyType() const { + SkASSERT(fType == SkType_MemberProperty || fType == SkType_Array); + return (SkDisplayTypes) fCount; // hack, but worth it? + } + void setMemberData(SkDisplayable* displayable, const void* child, size_t size) const { + SkASSERT(fType != SkType_MemberProperty && fType != SkType_MemberFunction); + memcpy((char*) displayable + fOffset, child, size); + } + void setString(SkDisplayable* , SkString* ) const; + void setValue(SkDisplayable* , const SkOperand values[], int count) const; + bool setValue(SkAnimateMaker& , SkTDOperandArray* storage, + int storageOffset, int maxStorage, SkDisplayable* , + SkDisplayTypes outType, const char value[], size_t len) const; + bool setValue(SkAnimateMaker& , SkTDOperandArray* storage, + int storageOffset, int maxStorage, SkDisplayable* , + SkDisplayTypes outType, SkString& str) const; +// void setValue(SkDisplayable* , const char value[], const char name[]) const; + bool writeValue(SkDisplayable* displayable, SkTDOperandArray* arrayStorage, + int storageOffset, int maxStorage, void* untypedStorage, SkDisplayTypes outType, + SkScriptValue& scriptValue) const; +#if SK_USE_CONDENSED_INFO == 0 + static const SkMemberInfo* Find(const SkMemberInfo [], int count, int* index); + static const SkMemberInfo* Find(const SkMemberInfo [], int count, const char** name); +#else + static const SkMemberInfo* Find(SkDisplayTypes type, int* index); + static const SkMemberInfo* Find(SkDisplayTypes type, const char** name); +#endif + static size_t GetSize(SkDisplayTypes type); // size of simple types only +// static bool SetValue(void* value, const char* name, SkDisplayTypes , int count); +}; + +#define SK_MEMBER(_member, _type) \ + { #_member, SK_OFFSETOF(BASE_CLASS, _member), SkType_##_type, \ + sizeof(((BASE_CLASS*) 1)->_member) / sizeof(SkScalar) } + +#define SK_MEMBER_ALIAS(_member, _alias, _type) \ + { #_member, SK_OFFSETOF(BASE_CLASS, _alias), SkType_##_type, \ + sizeof(((BASE_CLASS*) 1)->_alias) / sizeof(SkScalar) } + +#define SK_MEMBER_ARRAY(_member, _type) \ + { #_member, SK_OFFSETOF(BASE_CLASS, _member), SkType_Array, \ + (int) SkType_##_type } + +#define SK_MEMBER_INHERITED \ + { (const char*) INHERITED::fInfo, 0, SkType_BaseClassInfo, INHERITED::fInfoCount } + +// #define SK_MEMBER_KEY_TYPE(_member, _type) +// {#_member, (size_t) -1, SkType_##_type, 0} + +#define SK_FUNCTION(_member) \ + k_##_member##Function + +#define SK_PROPERTY(_member) \ + k_##_member##Property + +#define SK_MEMBER_DYNAMIC_FUNCTION(_member, _type) \ + {#_member, (size_t) (+1 + SK_FUNCTION(_member)), SkType_MemberFunction, \ + (int) SkType_##_type } + +#define SK_MEMBER_DYNAMIC_PROPERTY(_member, _type) \ + {#_member, (size_t) (1 + SK_PROPERTY(_member)), SkType_MemberProperty, \ + (int) SkType_##_type } + +#define SK_MEMBER_FUNCTION(_member, _type) \ + {#_member, (size_t) (-1 - SK_FUNCTION(_member)), SkType_MemberFunction, \ + (int) SkType_##_type } + +#define SK_MEMBER_PROPERTY(_member, _type) \ + {#_member, (size_t) (-1 - SK_PROPERTY(_member)), SkType_MemberProperty, \ + (int) SkType_##_type } + +#if SK_USE_CONDENSED_INFO == 0 + +#define DECLARE_PRIVATE_MEMBER_INFO(_type) \ +public: \ + static const SkMemberInfo fInfo[]; \ + static const int fInfoCount; \ + virtual const SkMemberInfo* getMember(int index); \ + virtual const SkMemberInfo* getMember(const char name[]); \ + typedef Sk##_type BASE_CLASS + +#define DECLARE_MEMBER_INFO(_type) \ +public: \ + static const SkMemberInfo fInfo[]; \ + static const int fInfoCount; \ + virtual const SkMemberInfo* getMember(int index); \ + virtual const SkMemberInfo* getMember(const char name[]); \ + virtual SkDisplayTypes getType() const { return SkType_##_type; } \ + typedef Sk##_type BASE_CLASS + +#define DECLARE_DRAW_MEMBER_INFO(_type) \ +public: \ + static const SkMemberInfo fInfo[]; \ + static const int fInfoCount; \ + virtual const SkMemberInfo* getMember(int index); \ + virtual const SkMemberInfo* getMember(const char name[]); \ + virtual SkDisplayTypes getType() const { return SkType_##_type; } \ + typedef SkDraw##_type BASE_CLASS + +#define DECLARE_DISPLAY_MEMBER_INFO(_type) \ +public: \ + static const SkMemberInfo fInfo[]; \ + static const int fInfoCount; \ + virtual const SkMemberInfo* getMember(int index); \ + virtual const SkMemberInfo* getMember(const char name[]); \ + virtual SkDisplayTypes getType() const { return SkType_##_type; } \ + typedef SkDisplay##_type BASE_CLASS + +#define DECLARE_EMPTY_MEMBER_INFO(_type) \ +public: \ + virtual SkDisplayTypes getType() const { return SkType_##_type; } + +#define DECLARE_EXTRAS_MEMBER_INFO(_type) \ +public: \ + static const SkMemberInfo fInfo[]; \ + static const int fInfoCount; \ + virtual const SkMemberInfo* getMember(int index); \ + virtual const SkMemberInfo* getMember(const char name[]); \ + SkDisplayTypes fType; \ + virtual SkDisplayTypes getType() const { return fType; } \ + typedef _type BASE_CLASS + +#define DECLARE_NO_VIRTUALS_MEMBER_INFO(_type) \ +public: \ + static const SkMemberInfo fInfo[]; \ + static const int fInfoCount; \ + typedef Sk##_type BASE_CLASS + +#define DEFINE_GET_MEMBER(_class) \ + const SkMemberInfo* _class::getMember(int index) { \ + const SkMemberInfo* result = SkMemberInfo::Find(fInfo, SK_ARRAY_COUNT(fInfo), &index); \ + return result; \ + } \ + const SkMemberInfo* _class::getMember(const char name[]) { \ + const SkMemberInfo* result = SkMemberInfo::Find(fInfo, SK_ARRAY_COUNT(fInfo), &name); \ + return result; \ + } \ + const int _class::fInfoCount = SK_ARRAY_COUNT(fInfo) + +#define DEFINE_NO_VIRTUALS_GET_MEMBER(_class) \ + const int _class::fInfoCount = SK_ARRAY_COUNT(fInfo) + +#else + +#define DECLARE_PRIVATE_MEMBER_INFO(_type) \ +public: \ + typedef Sk##_type BASE_CLASS + +#define DECLARE_MEMBER_INFO(_type) \ +public: \ + virtual const SkMemberInfo* getMember(int index) { \ + return SkDisplayType::GetMember(nil, SkType_##_type, &index); } \ + virtual const SkMemberInfo* getMember(const char name[]) { \ + return SkDisplayType::GetMember(nil, SkType_##_type, &name); } \ + virtual SkDisplayTypes getType() const { return SkType_##_type; } \ + typedef Sk##_type BASE_CLASS + +#define DECLARE_DRAW_MEMBER_INFO(_type) \ +public: \ + virtual const SkMemberInfo* getMember(int index) { \ + return SkDisplayType::GetMember(nil, SkType_##_type, &index); } \ + virtual const SkMemberInfo* getMember(const char name[]) { \ + return SkDisplayType::GetMember(nil, SkType_##_type, &name); } \ + virtual SkDisplayTypes getType() const { return SkType_##_type; } \ + typedef SkDraw##_type BASE_CLASS + +#define DECLARE_DISPLAY_MEMBER_INFO(_type) \ +public: \ + virtual const SkMemberInfo* getMember(int index) { \ + return SkDisplayType::GetMember(nil, SkType_##_type, &index); } \ + virtual const SkMemberInfo* getMember(const char name[]) { \ + return SkDisplayType::GetMember(nil, SkType_##_type, &name); } \ + virtual SkDisplayTypes getType() const { return SkType_##_type; } \ + typedef SkDisplay##_type BASE_CLASS + +#define DECLARE_EXTRAS_MEMBER_INFO(_type) \ +public: \ + virtual const SkMemberInfo* getMember(int index) { \ + return SkDisplayType::GetMember(nil, SkType_##_type, &index); } \ + virtual const SkMemberInfo* getMember(const char name[]) { \ + return SkDisplayType::GetMember(nil, fType, &name); } \ + SkDisplayTypes fType; \ + virtual SkDisplayTypes getType() const { return fType; } \ + typedef _type BASE_CLASS + +#define DECLARE_NO_VIRTUALS_MEMBER_INFO(_type) \ +public: \ + typedef Sk##_type BASE_CLASS + +#define DEFINE_GET_MEMBER(_class) +#define DEFINE_NO_VIRTUALS_GET_MEMBER(_class) + +#endif + +#endif // SkMemberInfo_DEFINED + diff --git a/libs/graphics/animator/SkOpArray.cpp b/libs/graphics/animator/SkOpArray.cpp new file mode 100755 index 0000000000..c6c9ae9c7a --- /dev/null +++ b/libs/graphics/animator/SkOpArray.cpp @@ -0,0 +1,16 @@ +#include "SkOpArray.h"
+
+SkOpArray::SkOpArray() : fType(SkOperand2::kNoType) {
+}
+
+SkOpArray::SkOpArray(SkOperand2::OpType type) : fType(type) {
+}
+
+bool SkOpArray::getIndex(int index, SkOperand2* operand) {
+ if (index >= count()) {
+ SkASSERT(0);
+ return false;
+ }
+ *operand = begin()[index];
+ return true;
+}
diff --git a/libs/graphics/animator/SkOpArray.h b/libs/graphics/animator/SkOpArray.h new file mode 100755 index 0000000000..19ae968c7e --- /dev/null +++ b/libs/graphics/animator/SkOpArray.h @@ -0,0 +1,22 @@ +#ifndef SkOpArray_DEFINED
+#define SkOpArray_DEFINED
+
+#include "SkOperand2.h"
+#include "SkTDArray_Experimental.h"
+
+typedef SkLongArray(SkOperand2) SkTDOperand2Array;
+
+class SkOpArray : public SkTDOperand2Array {
+public:
+ SkOpArray();
+ SkOpArray(SkOperand2::OpType type);
+ bool getIndex(int index, SkOperand2* operand);
+ SkOperand2::OpType getType() { return fType; }
+ void setType(SkOperand2::OpType type) {
+ fType = type;
+ }
+protected:
+ SkOperand2::OpType fType;
+};
+
+#endif // SkOpArray_DEFINED
diff --git a/libs/graphics/animator/SkOperand.h b/libs/graphics/animator/SkOperand.h new file mode 100644 index 0000000000..547cdbda6a --- /dev/null +++ b/libs/graphics/animator/SkOperand.h @@ -0,0 +1,37 @@ +#ifndef SkOperand_DEFINED +#define SkOperand_DEFINED + +#include "SkDisplayType.h" + +class SkTypedArray; +class SkDisplayable; +class SkDrawable; +class SkString; + +union SkOperand { +// SkOperand() {} +// SkOperand(SkScalar scalar) : fScalar(scalar) {} + SkTypedArray* fArray; + SkDisplayable* fDisplayable; + SkDrawable* fDrawable; + void* fObject; + int32_t fS32; + SkMSec fMSec; + SkScalar fScalar; + SkString* fString; +}; + +struct SkScriptValue { + SkOperand fOperand; + SkDisplayTypes fType; + SkTypedArray* getArray() { SkASSERT(fType == SkType_Array); return fOperand.fArray; } + SkDisplayable* getDisplayable() { SkASSERT(fType == SkType_Displayable); return fOperand.fDisplayable; } + SkDrawable* getDrawable() { SkASSERT(fType == SkType_Drawable); return fOperand.fDrawable; } + int32_t getS32(SkAnimateMaker* maker) { SkASSERT(fType == SkType_Int || fType == SkType_Boolean || + SkDisplayType::IsEnum(maker, fType)); return fOperand.fS32; } + SkMSec getMSec() { SkASSERT(fType == SkType_MSec); return fOperand.fMSec; } + SkScalar getScalar() { SkASSERT(fType == SkType_Float); return fOperand.fScalar; } + SkString* getString() { SkASSERT(fType == SkType_String); return fOperand.fString; } +}; + +#endif // SkOperand_DEFINED diff --git a/libs/graphics/animator/SkOperand2.h b/libs/graphics/animator/SkOperand2.h new file mode 100755 index 0000000000..f482e669b9 --- /dev/null +++ b/libs/graphics/animator/SkOperand2.h @@ -0,0 +1,47 @@ +#ifndef SkOperand2_DEFINED +#define SkOperand2_DEFINED + +#include "SkScalar.h" + +class SkOpArray; +class SkString; + +union SkOperand2 { + enum OpType { + kNoType, + kS32 = 1, + kScalar = 2, + kString = 4, + kArray = 8, + kObject = 16 + }; + SkOpArray* fArray; + void* fObject; + size_t fReference; + int32_t fS32; + SkScalar fScalar; + SkString* fString; +}; + +struct SkScriptValue2 { + enum IsConstant { + kConstant, + kVariable + }; + enum IsWritten { + kUnwritten, + kWritten + }; + SkOperand2 fOperand; + SkOperand2::OpType fType : 8; + IsConstant fIsConstant : 8; + IsWritten fIsWritten : 8; + SkOpArray* getArray() { SkASSERT(fType == SkOperand2::kArray); return fOperand.fArray; } + void* getObject() { SkASSERT(fType == SkOperand2::kObject); return fOperand.fObject; } + int32_t getS32() { SkASSERT(fType == SkOperand2::kS32); return fOperand.fS32; } + SkScalar getScalar() { SkASSERT(fType == SkOperand2::kScalar); return fOperand.fScalar; } + SkString* getString() { SkASSERT(fType == SkOperand2::kString); return fOperand.fString; } + bool isConstant() const { return fIsConstant == kConstant; } +}; + +#endif // SkOperand2_DEFINED diff --git a/libs/graphics/animator/SkOperandInterpolator.h b/libs/graphics/animator/SkOperandInterpolator.h new file mode 100644 index 0000000000..c6e38c25eb --- /dev/null +++ b/libs/graphics/animator/SkOperandInterpolator.h @@ -0,0 +1,39 @@ +#ifndef SkOperandInterpolator_DEFINED +#define SkOperandInterpolator_DEFINED + +#include "SkDisplayType.h" +#include "SkInterpolator.h" +#include "SkOperand.h" + +class SkOperandInterpolator : public SkInterpolatorBase { +public: + SkOperandInterpolator(); + SkOperandInterpolator(int elemCount, int frameCount, SkDisplayTypes type); + SkOperand* getValues() { return fValues; } + int getValuesCount() { return fFrameCount * fElemCount; } + void reset(int elemCount, int frameCount, SkDisplayTypes type); + + /** Add or replace a key frame, copying the values[] data into the interpolator. + @param index The index of this frame (frames must be ordered by time) + @param time The millisecond time for this frame + @param values The array of values [elemCount] for this frame. The data is copied + into the interpolator. + @param blend A positive scalar specifying how to blend between this and the next key frame. + [0...1) is a cubic lag/log/lag blend (slow to change at the beginning and end) + 1 is a linear blend (default) + (1...inf) is a cubic log/lag/log blend (fast to change at the beginning and end) + */ + bool setKeyFrame(int index, SkMSec time, const SkOperand values[], SkScalar blend = SK_Scalar1); + Result timeToValues(SkMSec time, SkOperand values[]) const; + SkDEBUGCODE(static void UnitTest();) +private: + SkDisplayTypes fType; + SkOperand* fValues; // pointer into fStorage +#ifdef SK_DEBUG + SkOperand(* fValuesArray)[10]; +#endif + typedef SkInterpolatorBase INHERITED; +}; + +#endif // SkOperandInterpolator_DEFINED + diff --git a/libs/graphics/animator/SkOperandIterpolator.cpp b/libs/graphics/animator/SkOperandIterpolator.cpp new file mode 100644 index 0000000000..8d9f44929d --- /dev/null +++ b/libs/graphics/animator/SkOperandIterpolator.cpp @@ -0,0 +1,139 @@ +#include "SkOperandInterpolator.h" +#include "SkScript.h" + +SkOperandInterpolator::SkOperandInterpolator() { + INHERITED::reset(0, 0); + fType = SkType_Unknown; +} + +SkOperandInterpolator::SkOperandInterpolator(int elemCount, int frameCount, + SkDisplayTypes type) +{ + this->reset(elemCount, frameCount, type); +} + +void SkOperandInterpolator::reset(int elemCount, int frameCount, SkDisplayTypes type) +{ +// SkASSERT(type == SkType_String || type == SkType_Float || type == SkType_Int || +// type == SkType_Displayable || type == SkType_Drawable); + INHERITED::reset(elemCount, frameCount); + fType = type; + fStorage = sk_malloc_throw((sizeof(SkOperand) * elemCount + sizeof(SkTimeCode)) * frameCount); + fTimes = (SkTimeCode*) fStorage; + fValues = (SkOperand*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount); +#ifdef SK_DEBUG + fTimesArray = (SkTimeCode(*)[10]) fTimes; + fValuesArray = (SkOperand(*)[10]) fValues; +#endif +} + +bool SkOperandInterpolator::setKeyFrame(int index, SkMSec time, const SkOperand values[], SkScalar blend) +{ + SkASSERT(values != nil); + blend = SkScalarPin(blend, 0, SK_Scalar1); + + bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time, sizeof(SkTimeCode)); + SkASSERT(success); + if (success) { + SkTimeCode* timeCode = &fTimes[index]; + timeCode->fTime = time; + timeCode->fBlend = blend; + SkOperand* dst = &fValues[fElemCount * index]; + memcpy(dst, values, fElemCount * sizeof(SkOperand)); + } + return success; +} + +SkInterpolatorBase::Result SkOperandInterpolator::timeToValues(SkMSec time, SkOperand values[]) const +{ + SkScalar T; + int index; + SkBool exact; + Result result = timeToT(time, &T, &index, &exact); + if (values) + { + const SkOperand* nextSrc = &fValues[index * fElemCount]; + + if (exact) + memcpy(values, nextSrc, fElemCount * sizeof(SkScalar)); + else + { + SkASSERT(index > 0); + + const SkOperand* prevSrc = nextSrc - fElemCount; + + if (fType == SkType_Float || fType == SkType_3D_Point) { + for (int i = fElemCount - 1; i >= 0; --i) + values[i].fScalar = SkScalarInterp(prevSrc[i].fScalar, nextSrc[i].fScalar, T); + } else if (fType == SkType_Int || fType == SkType_MSec) { + for (int i = fElemCount - 1; i >= 0; --i) { + S32 a = prevSrc[i].fS32; + S32 b = nextSrc[i].fS32; + values[i].fS32 = a + SkScalarRound((b - a) * T); + } + } else + memcpy(values, prevSrc, sizeof(SkOperand) * fElemCount); + } + } + return result; +} + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_DEBUG + +#ifdef SK_SUPPORT_UNITTEST + static SkOperand* iset(SkOperand array[3], int a, int b, int c) + { + array[0].fScalar = SkIntToScalar(a); + array[1].fScalar = SkIntToScalar(b); + array[2].fScalar = SkIntToScalar(c); + return array; + } +#endif + +void SkOperandInterpolator::UnitTest() +{ +#ifdef SK_SUPPORT_UNITTEST + SkOperandInterpolator inter(3, 2, SkType_Float); + SkOperand v1[3], v2[3], v[3], vv[3]; + Result result; + + inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0); + inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330)); + + result = inter.timeToValues(0, v); + SkASSERT(result == kFreezeStart_Result); + SkASSERT(memcmp(v, v1, sizeof(v)) == 0); + + result = inter.timeToValues(99, v); + SkASSERT(result == kFreezeStart_Result); + SkASSERT(memcmp(v, v1, sizeof(v)) == 0); + + result = inter.timeToValues(100, v); + SkASSERT(result == kNormal_Result); + SkASSERT(memcmp(v, v1, sizeof(v)) == 0); + + result = inter.timeToValues(200, v); + SkASSERT(result == kNormal_Result); + SkASSERT(memcmp(v, v2, sizeof(v)) == 0); + + result = inter.timeToValues(201, v); + SkASSERT(result == kFreezeEnd_Result); + SkASSERT(memcmp(v, v2, sizeof(v)) == 0); + + result = inter.timeToValues(150, v); + SkASSERT(result == kNormal_Result); + SkASSERT(memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0); + + result = inter.timeToValues(125, v); + SkASSERT(result == kNormal_Result); + result = inter.timeToValues(175, v); + SkASSERT(result == kNormal_Result); +#endif +} + +#endif + + diff --git a/libs/graphics/animator/SkPaintParts.cpp b/libs/graphics/animator/SkPaintParts.cpp new file mode 100644 index 0000000000..b45a125489 --- /dev/null +++ b/libs/graphics/animator/SkPaintParts.cpp @@ -0,0 +1,94 @@ +#include "SkPaintParts.h" +#include "SkDrawPaint.h" +#ifdef SK_DUMP_ENABLED +#include "SkDisplayList.h" +#include "SkDump.h" +#endif + +SkPaintPart::SkPaintPart() : fPaint(nil) { +} + +SkDisplayable* SkPaintPart::getParent() const { + return fPaint; +} + +bool SkPaintPart::setParent(SkDisplayable* parent) { + SkASSERT(parent != nil); + if (parent->isPaint() == false) + return true; + fPaint = (SkDrawPaint*) parent; + return false; +} + + +// SkDrawMaskFilter +bool SkDrawMaskFilter::add() { + if (fPaint->maskFilter != (SkDrawMaskFilter*) -1) + return true; + fPaint->maskFilter = this; + fPaint->fOwnsMaskFilter = true; + return false; +} + +SkMaskFilter* SkDrawMaskFilter::getMaskFilter() { + return nil; +} + + +// SkDrawPathEffect +bool SkDrawPathEffect::add() { + if (fPaint->isPaint()) { + if (fPaint->pathEffect != (SkDrawPathEffect*) -1) + return true; + fPaint->pathEffect = this; + fPaint->fOwnsPathEffect = true; + return false; + } + fPaint->add(*(SkAnimateMaker*) nil, this); + return false; +} + +SkPathEffect* SkDrawPathEffect::getPathEffect() { + return nil; +} + + +// SkDrawShader +SkShader* SkDrawShader::getShader() { + return nil; +} + + +// Typeface +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkDrawTypeface::fInfo[] = { + SK_MEMBER(fontName, String), + SK_MEMBER(style, FontStyle) +}; + +#endif + +DEFINE_GET_MEMBER(SkDrawTypeface); + +SkDrawTypeface::SkDrawTypeface() : style (SkTypeface::kNormal){ +} + +bool SkDrawTypeface::add() { + if (fPaint->typeface != (SkDrawTypeface*) -1) + return true; + fPaint->typeface = this; + fPaint->fOwnsTypeface = true; + return false; +} + +#ifdef SK_DUMP_ENABLED +void SkDrawTypeface::dump(SkAnimateMaker* maker) { + SkDebugf("%*s<typeface fontName=\"%s\" ", SkDisplayList::fIndent, "", fontName.c_str()); + SkString string; + SkDump::GetEnumString(SkType_FontStyle, style, &string); + SkDebugf("style=\"%s\" />\n", string.c_str()); +} +#endif + + diff --git a/libs/graphics/animator/SkPaintParts.h b/libs/graphics/animator/SkPaintParts.h new file mode 100644 index 0000000000..c0f84da78e --- /dev/null +++ b/libs/graphics/animator/SkPaintParts.h @@ -0,0 +1,66 @@ +#ifndef SkPaintParts_DEFINED +#define SkPaintParts_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" +#include "SkPaint.h" +#include "SkShader.h" +#include "SkTypeface.h" +#include "SkXfermode.h" + +class SkDrawPaint; +class SkDrawMatrix; + +class SkPaintPart : public SkDisplayable { +public: + SkPaintPart(); + virtual bool add() = 0; + virtual SkDisplayable* getParent() const; + virtual bool setParent(SkDisplayable* parent); +#ifdef SK_DEBUG + virtual bool isPaintPart() const { return true; } +#endif +protected: + SkDrawPaint* fPaint; +}; + +class SkDrawMaskFilter : public SkPaintPart { + DECLARE_EMPTY_MEMBER_INFO(MaskFilter); + virtual SkMaskFilter* getMaskFilter(); +protected: + virtual bool add(); +}; + +class SkDrawPathEffect : public SkPaintPart { + DECLARE_EMPTY_MEMBER_INFO(PathEffect); + virtual SkPathEffect* getPathEffect(); +protected: + virtual bool add(); +}; + +class SkDrawShader : public SkPaintPart { + DECLARE_DRAW_MEMBER_INFO(Shader); + SkDrawShader(); + virtual SkShader* getShader(); +protected: + virtual bool add(); + void addPostlude(SkShader* shader); + SkDrawMatrix* matrix; + int /*SkShader::TileMode*/ tileMode; +}; + +class SkDrawTypeface : public SkPaintPart { + DECLARE_DRAW_MEMBER_INFO(Typeface); + SkDrawTypeface(); +#ifdef SK_DUMP_ENABLED + virtual void dump(SkAnimateMaker *); +#endif + SkTypeface* getTypeface() { + return SkTypeface::Create(fontName.c_str(), style); } +protected: + virtual bool add(); + SkString fontName; + SkTypeface::Style style; +}; + +#endif // SkPaintParts_DEFINED diff --git a/libs/graphics/animator/SkPathParts.cpp b/libs/graphics/animator/SkPathParts.cpp new file mode 100644 index 0000000000..537a32db77 --- /dev/null +++ b/libs/graphics/animator/SkPathParts.cpp @@ -0,0 +1,311 @@ +#include "SkPathParts.h" +#include "SkAnimateMaker.h" +#include "SkDrawMatrix.h" +#include "SkDrawRectangle.h" +#include "SkDrawPath.h" + +SkPathPart::SkPathPart() : fPath(nil) { +} + +void SkPathPart::dirty() { + fPath->dirty(); +} + +SkDisplayable* SkPathPart::getParent() const { + return fPath; +} + +bool SkPathPart::setParent(SkDisplayable* parent) { + SkASSERT(parent != nil); + if (parent->isPath() == false) + return true; + fPath = (SkDrawPath*) parent; + return false; +} + +// MoveTo +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkMoveTo::fInfo[] = { + SK_MEMBER(x, Float), + SK_MEMBER(y, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkMoveTo); + +SkMoveTo::SkMoveTo() : x(0), y(0) { +} + +bool SkMoveTo::add() { + fPath->fPath.moveTo(x, y); + return false; +} + + +// RMoveTo +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkRMoveTo::fInfo[] = { + SK_MEMBER_INHERITED +}; + +#endif + +DEFINE_GET_MEMBER(SkRMoveTo); + +bool SkRMoveTo::add() { + fPath->fPath.rMoveTo(x, y); + return false; +} + + +// LineTo +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkLineTo::fInfo[] = { + SK_MEMBER(x, Float), + SK_MEMBER(y, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkLineTo); + +SkLineTo::SkLineTo() : x(0), y(0) { +} + +bool SkLineTo::add() { + fPath->fPath.lineTo(x, y); + return false; +} + + +// RLineTo +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkRLineTo::fInfo[] = { + SK_MEMBER_INHERITED +}; + +#endif + +DEFINE_GET_MEMBER(SkRLineTo); + +bool SkRLineTo::add() { + fPath->fPath.rLineTo(x, y); + return false; +} + + +// QuadTo +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkQuadTo::fInfo[] = { + SK_MEMBER(x1, Float), + SK_MEMBER(x2, Float), + SK_MEMBER(y1, Float), + SK_MEMBER(y2, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkQuadTo); + +SkQuadTo::SkQuadTo() : x1(0), y1(0), x2(0), y2(0) { +} + +bool SkQuadTo::add() { + fPath->fPath.quadTo(x1, y1, x2, y2); + return false; +} + + +// RQuadTo +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkRQuadTo::fInfo[] = { + SK_MEMBER_INHERITED +}; + +#endif + +DEFINE_GET_MEMBER(SkRQuadTo); + +bool SkRQuadTo::add() { + fPath->fPath.rQuadTo(x1, y1, x2, y2); + return false; +} + + +// CubicTo +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkCubicTo::fInfo[] = { + SK_MEMBER(x1, Float), + SK_MEMBER(x2, Float), + SK_MEMBER(x3, Float), + SK_MEMBER(y1, Float), + SK_MEMBER(y2, Float), + SK_MEMBER(y3, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkCubicTo); + +SkCubicTo::SkCubicTo() : x1(0), y1(0), x2(0), y2(0), x3(0), y3(0) { +} + +bool SkCubicTo::add() { + fPath->fPath.cubicTo(x1, y1, x2, y2, x3, y3); + return false; +} + + +// RCubicTo +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkRCubicTo::fInfo[] = { + SK_MEMBER_INHERITED +}; + +#endif + +DEFINE_GET_MEMBER(SkRCubicTo); + +bool SkRCubicTo::add() { + fPath->fPath.rCubicTo(x1, y1, x2, y2, x3, y3); + return false; +} + + +// SkClose +bool SkClose::add() { + fPath->fPath.close(); + return false; +} + + +// SkAddGeom +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkAddGeom::fInfo[] = { + SK_MEMBER(direction, PathDirection) +}; + +#endif + +DEFINE_GET_MEMBER(SkAddGeom); + +SkAddGeom::SkAddGeom() : direction(SkPath::kCCW_Direction) { +} + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkAddRect::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER_ALIAS(bottom, fRect.fBottom, Float), + SK_MEMBER_ALIAS(left, fRect.fLeft, Float), + SK_MEMBER_ALIAS(right, fRect.fRight, Float), + SK_MEMBER_ALIAS(top, fRect.fTop, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkAddRect); + +SkAddRect::SkAddRect() { + fRect.setEmpty(); +} + +bool SkAddRect::add() { + fPath->fPath.addRect(fRect, (SkPath::Direction) direction); + return false; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkAddOval::fInfo[] = { + SK_MEMBER_INHERITED +}; + +#endif + +DEFINE_GET_MEMBER(SkAddOval); + +bool SkAddOval::add() { + fPath->fPath.addOval(fRect, (SkPath::Direction) direction); + return false; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkAddCircle::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER(radius, Float), + SK_MEMBER(x, Float), + SK_MEMBER(y, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkAddCircle); + +SkAddCircle::SkAddCircle() : radius(0), x(0), y(0) { +} + +bool SkAddCircle::add() { + fPath->fPath.addCircle(x, y, radius, (SkPath::Direction) direction); + return false; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkAddRoundRect::fInfo[] = { + SK_MEMBER_INHERITED, + SK_MEMBER(rx, Float), + SK_MEMBER(ry, Float) +}; + +#endif + +DEFINE_GET_MEMBER(SkAddRoundRect); + +SkAddRoundRect::SkAddRoundRect() : rx(0), ry(0) { +} + +bool SkAddRoundRect::add() { + fPath->fPath.addRoundRect(fRect, rx, ry, (SkPath::Direction) direction); + return false; +} + + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkAddPath::fInfo[] = { + SK_MEMBER(matrix, Matrix), + SK_MEMBER(path, Path) +}; + +#endif + +DEFINE_GET_MEMBER(SkAddPath); + +SkAddPath::SkAddPath() : matrix(nil), path(nil) { +} + +bool SkAddPath::add() { + SkASSERT (path != nil); + if (matrix) + fPath->fPath.addPath(path->fPath, matrix->getMatrix()); + else + fPath->fPath.addPath(path->fPath); + return false; +} + + diff --git a/libs/graphics/animator/SkPathParts.h b/libs/graphics/animator/SkPathParts.h new file mode 100644 index 0000000000..ed78c92cac --- /dev/null +++ b/libs/graphics/animator/SkPathParts.h @@ -0,0 +1,156 @@ +#ifndef SkPathParts_DEFINED +#define SkPathParts_DEFINED + +#include "SkDisplayable.h" +#include "SkMemberInfo.h" +#include "SkPath.h" + +class SkDrawPath; +class SkDrawMatrix; + +class SkPathPart : public SkDisplayable { +public: + SkPathPart(); + virtual bool add() = 0; + virtual void dirty(); + virtual SkDisplayable* getParent() const; + virtual bool setParent(SkDisplayable* parent); +#ifdef SK_DEBUG + virtual bool isPathPart() const { return true; } +#endif +protected: + SkDrawPath* fPath; +}; + +class SkMoveTo : public SkPathPart { + DECLARE_MEMBER_INFO(MoveTo); + SkMoveTo(); + virtual bool add(); +protected: + SkScalar x; + SkScalar y; +}; + +class SkRMoveTo : public SkMoveTo { + DECLARE_MEMBER_INFO(RMoveTo); + virtual bool add(); +private: + typedef SkMoveTo INHERITED; +}; + +class SkLineTo : public SkPathPart { + DECLARE_MEMBER_INFO(LineTo); + SkLineTo(); + virtual bool add(); +protected: + SkScalar x; + SkScalar y; +}; + +class SkRLineTo : public SkLineTo { + DECLARE_MEMBER_INFO(RLineTo); + virtual bool add(); +private: + typedef SkLineTo INHERITED; +}; + +class SkQuadTo : public SkPathPart { + DECLARE_MEMBER_INFO(QuadTo); + SkQuadTo(); + virtual bool add(); +protected: + SkScalar x1; + SkScalar y1; + SkScalar x2; + SkScalar y2; +}; + +class SkRQuadTo : public SkQuadTo { + DECLARE_MEMBER_INFO(RQuadTo); + virtual bool add(); +private: + typedef SkQuadTo INHERITED; +}; + +class SkCubicTo : public SkPathPart { + DECLARE_MEMBER_INFO(CubicTo); + SkCubicTo(); + virtual bool add(); +protected: + SkScalar x1; + SkScalar y1; + SkScalar x2; + SkScalar y2; + SkScalar x3; + SkScalar y3; +}; + +class SkRCubicTo : public SkCubicTo { + DECLARE_MEMBER_INFO(RCubicTo); + virtual bool add(); +private: + typedef SkCubicTo INHERITED; +}; + +class SkClose : public SkPathPart { + DECLARE_EMPTY_MEMBER_INFO(Close); + virtual bool add(); +}; + +class SkAddGeom : public SkPathPart { + DECLARE_PRIVATE_MEMBER_INFO(AddGeom); + SkAddGeom(); +protected: + int /*SkPath::Direction*/ direction; +}; + +class SkAddRect : public SkAddGeom { + DECLARE_MEMBER_INFO(AddRect); + SkAddRect(); + virtual bool add(); +protected: + SkRect fRect; +private: + typedef SkAddGeom INHERITED; +}; + +class SkAddOval : public SkAddRect { + DECLARE_MEMBER_INFO(AddOval); + virtual bool add(); +private: + typedef SkAddRect INHERITED; +}; + +class SkAddCircle : public SkAddGeom { + DECLARE_MEMBER_INFO(AddCircle); + SkAddCircle(); + virtual bool add(); +private: + SkScalar radius; + SkScalar x; + SkScalar y; + typedef SkAddGeom INHERITED; +}; + +class SkAddRoundRect : public SkAddRect { + DECLARE_MEMBER_INFO(AddRoundRect); + SkAddRoundRect(); + virtual bool add(); +private: + SkScalar rx; + SkScalar ry; + typedef SkAddRect INHERITED; +}; + +class SkAddPath : public SkPathPart { + DECLARE_MEMBER_INFO(AddPath); + SkAddPath(); + virtual bool add(); +private: + typedef SkPathPart INHERITED; + SkDrawMatrix* matrix; + SkDrawPath* path; +}; + +#endif // SkPathParts_DEFINED + diff --git a/libs/graphics/animator/SkPostParts.cpp b/libs/graphics/animator/SkPostParts.cpp new file mode 100644 index 0000000000..3782e47fae --- /dev/null +++ b/libs/graphics/animator/SkPostParts.cpp @@ -0,0 +1,48 @@ +#include "SkPostParts.h" +#include "SkDisplayPost.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkData::fInfo[] = { + SK_MEMBER_INHERITED +}; + +#endif + +DEFINE_GET_MEMBER(SkData); + +SkData::SkData() : fParent(nil) {} + +bool SkData::add() { + SkASSERT(name.size() > 0); + const char* dataName = name.c_str(); + if (fInt != (int) SK_NaN32) + fParent->fEvent.setS32(dataName, fInt); + else if (SkScalarIsNaN(fFloat) == false) + fParent->fEvent.setScalar(dataName, fFloat); + else if (string.size() > 0) + fParent->fEvent.setString(dataName, string); +// else +// SkASSERT(0); + return false; +} + +void SkData::dirty() { + fParent->dirty(); +} + +SkDisplayable* SkData::getParent() const { + return fParent; +} + +bool SkData::setParent(SkDisplayable* displayable) { + if (displayable->isPost() == false) + return true; + fParent = (SkPost*) displayable; + return false; +} + +void SkData::onEndElement(SkAnimateMaker&) { + add(); +} + diff --git a/libs/graphics/animator/SkPostParts.h b/libs/graphics/animator/SkPostParts.h new file mode 100644 index 0000000000..4aca6c0d5d --- /dev/null +++ b/libs/graphics/animator/SkPostParts.h @@ -0,0 +1,22 @@ +#ifndef SkPostParts_DEFINED +#define SkPostParts_DEFINED + +#include "SkDisplayInput.h" + +class SkPost; + +class SkData: public SkInput { + DECLARE_MEMBER_INFO(Data); + SkData(); + bool add(); + virtual void dirty(); + virtual SkDisplayable* getParent() const; + virtual void onEndElement(SkAnimateMaker& ); + virtual bool setParent(SkDisplayable* ); +protected: + SkPost* fParent; + typedef SkInput INHERITED; + friend class SkPost; +}; + +#endif // SkPostParts_DEFINED diff --git a/libs/graphics/animator/SkSVGPath.cpp b/libs/graphics/animator/SkSVGPath.cpp new file mode 100644 index 0000000000..e3c4083df2 --- /dev/null +++ b/libs/graphics/animator/SkSVGPath.cpp @@ -0,0 +1,226 @@ +#include <ctype.h> +#include "SkDrawPath.h" +#include "SkParse.h" +#include "SkPoint.h" +#include "SkUtils.h" +#define QUADRATIC_APPROXIMATION 1 + +#if QUADRATIC_APPROXIMATION +//////////////////////////////////////////////////////////////////////////////////// +//functions to approximate a cubic using two quadratics + +// midPt sets the first argument to be the midpoint of the other two +// it is used by quadApprox +static inline void midPt(SkPoint& dest,const SkPoint& a,const SkPoint& b) +{ + dest.set(SkScalarAve(a.fX, b.fX),SkScalarAve(a.fY, b.fY)); +} +// quadApprox - makes an approximation, which we hope is faster +static void quadApprox(SkPath &fPath, const SkPoint &p0, const SkPoint &p1, const SkPoint &p2) +{ + //divide the cubic up into two cubics, then convert them into quadratics + //define our points + SkPoint c,j,k,l,m,n,o,p,q, mid; + fPath.getLastPt(&c); + midPt(j, p0, c); + midPt(k, p0, p1); + midPt(l, p1, p2); + midPt(o, j, k); + midPt(p, k, l); + midPt(q, o, p); + //compute the first half + m.set(SkScalarHalf(3*j.fX - c.fX), SkScalarHalf(3*j.fY - c.fY)); + n.set(SkScalarHalf(3*o.fX -q.fX), SkScalarHalf(3*o.fY - q.fY)); + midPt(mid,m,n); + fPath.quadTo(mid,q); + c = q; + //compute the second half + m.set(SkScalarHalf(3*p.fX - c.fX), SkScalarHalf(3*p.fY - c.fY)); + n.set(SkScalarHalf(3*l.fX -p2.fX),SkScalarHalf(3*l.fY -p2.fY)); + midPt(mid,m,n); + fPath.quadTo(mid,p2); +} +#endif + + +static inline bool is_between(int c, int min, int max) +{ + return (unsigned)(c - min) <= (unsigned)(max - min); +} + +static inline bool is_ws(int c) +{ + return is_between(c, 1, 32); +} + +static inline bool is_digit(int c) +{ + return is_between(c, '0', '9'); +} + +static inline bool is_sep(int c) +{ + return is_ws(c) || c == ','; +} + +static const char* skip_ws(const char str[]) +{ + SkASSERT(str); + while (is_ws(*str)) + str++; + return str; +} + +static const char* skip_sep(const char str[]) +{ + SkASSERT(str); + while (is_sep(*str)) + str++; + return str; +} + +static const char* find_points(const char str[], SkPoint value[], int count, + bool isRelative, SkPoint* relative) +{ + str = SkParse::FindScalars(str, &value[0].fX, count * 2); + if (isRelative) { + for (int index = 0; index < count; index++) { + value[index].fX += relative->fX; + value[index].fY += relative->fY; + } + } + return str; +} + +static const char* find_scalar(const char str[], SkScalar* value, + bool isRelative, SkScalar relative) +{ + str = SkParse::FindScalar(str, value); + if (isRelative) + *value += relative; + return str; +} + +void SkDrawPath::parseSVG() { + fPath.reset(); + const char* data = d.c_str(); + SkPoint f = {0, 0}; + SkPoint c = {0, 0}; + SkPoint lastc = {0, 0}; + SkPoint points[3]; + char op = '\0'; + char previousOp = '\0'; + bool relative = false; + do { + data = skip_ws(data); + if (data[0] == '\0') + break; + char ch = data[0]; + if (is_digit(ch) || ch == '-' || ch == '+') { + if (op == '\0') + return; + } + else { + op = ch; + relative = false; + if (islower(op)) { + op = (char) toupper(op); + relative = true; + } + data++; + data = skip_sep(data); + } + switch (op) { + case 'M': + data = find_points(data, points, 1, relative, &c); + fPath.moveTo(points[0]); + op = 'L'; + c = points[0]; + break; + case 'L': + data = find_points(data, points, 1, relative, &c); + fPath.lineTo(points[0]); + c = points[0]; + break; + case 'H': { + SkScalar x; + data = find_scalar(data, &x, relative, c.fX); + fPath.lineTo(x, c.fY); + c.fX = x; + } + break; + case 'V': { + SkScalar y; + data = find_scalar(data, &y, relative, c.fY); + fPath.lineTo(c.fX, y); + c.fY = y; + } + break; + case 'C': + data = find_points(data, points, 3, relative, &c); + goto cubicCommon; + case 'S': + data = find_points(data, &points[1], 2, relative, &c); + points[0] = c; + if (previousOp == 'C' || previousOp == 'S') { + points[0].fX -= lastc.fX - c.fX; + points[0].fY -= lastc.fY - c.fY; + } + cubicCommon: + // if (data[0] == '\0') + // return; +#if QUADRATIC_APPROXIMATION + quadApprox(fPath, points[0], points[1], points[2]); +#else //this way just does a boring, slow old cubic + fPath.cubicTo(points[0], points[1], points[2]); +#endif + //if we are using the quadApprox, lastc is what it would have been if we had used + //cubicTo + lastc = points[1]; + c = points[2]; + break; + case 'Q': // Quadratic Bezier Curve + data = find_points(data, points, 2, relative, &c); + goto quadraticCommon; + case 'T': + data = find_points(data, &points[1], 1, relative, &c); + points[0] = points[1]; + if (previousOp == 'Q' || previousOp == 'T') { + points[0].fX = c.fX * 2 - lastc.fX; + points[0].fY = c.fY * 2 - lastc.fY; + } + quadraticCommon: + fPath.quadTo(points[0], points[1]); + lastc = points[0]; + c = points[1]; + break; + case 'Z': + fPath.close(); +#if 0 // !!! still a bug? + if (fPath.isEmpty() && (f.fX != 0 || f.fY != 0)) { + c.fX -= SkScalar.Epsilon; // !!! enough? + fPath.moveTo(c); + fPath.lineTo(f); + fPath.close(); + } +#endif + c = f; + op = '\0'; + break; + case '~': { + SkPoint args[2]; + data = find_points(data, args, 2, false, nil); + fPath.moveTo(args[0].fX, args[0].fY); + fPath.lineTo(args[1].fX, args[1].fY); + } + break; + default: + SkASSERT(0); + return; + } + if (previousOp == 0) + f = c; + previousOp = op; + } while (data[0] > 0); +} + diff --git a/libs/graphics/animator/SkScript.cpp b/libs/graphics/animator/SkScript.cpp new file mode 100644 index 0000000000..136e1fd7eb --- /dev/null +++ b/libs/graphics/animator/SkScript.cpp @@ -0,0 +1,1901 @@ +#include "SkScript.h" +#include "SkMath.h" +#include "SkParse.h" +#include "SkString.h" +#include "SkTypedArray.h" + +/* things to do + ? re-enable support for struct literals (e.g., for initializing points or rects) + {x:1, y:2} + ? use standard XML / script notation like document.getElementById("canvas"); + finish support for typed arrays + ? allow indexing arrays by string + this could map to the 'name' attribute of a given child of an array + ? allow multiple types in the array + remove SkDisplayType.h // from SkOperand.h + merge type and operand arrays into scriptvalue array +*/ + +#ifdef SK_DEBUG +static const char* errorStrings[] = { + "array index of out bounds", // kArrayIndexOutOfBounds + "could not find reference id", // kCouldNotFindReferencedID + "dot operator expects object", // kDotOperatorExpectsObject + "error in array index", // kErrorInArrrayIndex + "error in function parameters", // kErrorInFunctionParameters + "expected array", // kExpectedArray + "expected boolean expression", // kExpectedBooleanExpression + "expected field name", // kExpectedFieldName + "expected hex", // kExpectedHex + "expected int for condition operator", // kExpectedIntForConditionOperator + "expected number", // kExpectedNumber + "expected number for array index", // kExpectedNumberForArrayIndex + "expected operator", // kExpectedOperator + "expected token", // kExpectedToken + "expected token before dot operator", // kExpectedTokenBeforeDotOperator + "expected value", // kExpectedValue + "handle member failed", // kHandleMemberFailed + "handle member function failed", // kHandleMemberFunctionFailed + "handle unbox failed", // kHandleUnboxFailed + "index out of range", // kIndexOutOfRange + "mismatched array brace", // kMismatchedArrayBrace + "mismatched brackets", // kMismatchedBrackets + "no function handler found", // kNoFunctionHandlerFound + "premature end", // kPrematureEnd + "too many parameters", // kTooManyParameters + "type conversion failed", // kTypeConversionFailed + "unterminated string" // kUnterminatedString +}; +#endif + +const SkScriptEngine::SkOperatorAttributes SkScriptEngine::gOpAttributes[] = { + { kNoType, kNoType, kNoBias }, // kUnassigned, + { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsString }, // kAdd + // kAddInt = kAdd, + { kNoType, kNoType, kNoBias }, // kAddScalar, + { kNoType, kNoType, kNoBias }, // kAddString, + { kNoType, kNoType, kNoBias }, // kArrayOp, + { kInt, kInt, kNoBias }, // kBitAnd + { kNoType, kInt, kNoBias }, // kBitNot + { kInt, kInt, kNoBias }, // kBitOr + { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kDivide + // kDivideInt = kDivide + { kNoType, kNoType, kNoBias }, // kDivideScalar + { kNoType, kNoType, kNoBias }, // kElse + { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kEqual + // kEqualInt = kEqual + { kNoType, kNoType, kNoBias }, // kEqualScalar + { kNoType, kNoType, kNoBias }, // kEqualString + { kInt, kNoType, kNoBias }, // kFlipOps + { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kGreaterEqual + // kGreaterEqualInt = kGreaterEqual + { kNoType, kNoType, kNoBias }, // kGreaterEqualScalar + { kNoType, kNoType, kNoBias }, // kGreaterEqualString + { kNoType, kNoType, kNoBias }, // kIf + { kNoType, kInt, kNoBias }, // kLogicalAnd (really, ToBool) + { kNoType, kInt, kNoBias }, // kLogicalNot + { kInt, kInt, kNoBias }, // kLogicalOr + { kNoType, SkOpType(kInt | kScalar), kNoBias }, // kMinus + // kMinusInt = kMinus + { kNoType, kNoType, kNoBias }, // kMinusScalar + { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kModulo + // kModuloInt = kModulo + { kNoType, kNoType, kNoBias }, // kModuloScalar + { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kMultiply + // kMultiplyInt = kMultiply + { kNoType, kNoType, kNoBias }, // kMultiplyScalar + { kNoType, kNoType, kNoBias }, // kParen + { kInt, kInt, kNoBias }, // kShiftLeft + { kInt, kInt, kNoBias }, // kShiftRight + { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kSubtract + // kSubtractInt = kSubtract + { kNoType, kNoType, kNoBias }, // kSubtractScalar + { kInt, kInt, kNoBias } // kXor +}; + +// Note that the real precedence for () [] is '2' +// but here, precedence means 'while an equal or smaller precedence than the current operator +// is on the stack, process it. This allows 3+5*2 to defer the add until after the multiply +// is preformed, since the add precedence is not smaller than multiply. +// But, (3*4 does not process the '(', since brackets are greater than all other precedences +#define kBracketPrecedence 16 +#define kIfElsePrecedence 15 + +const signed char SkScriptEngine::gPrecedence[] = { + -1, // kUnassigned, + 6, // kAdd, + // kAddInt = kAdd, + 6, // kAddScalar, + 6, // kAddString, // string concat + kBracketPrecedence, // kArrayOp, + 10, // kBitAnd, + 4, // kBitNot, + 12, // kBitOr, + 5, // kDivide, + // kDivideInt = kDivide, + 5, // kDivideScalar, + kIfElsePrecedence, // kElse, + 9, // kEqual, + // kEqualInt = kEqual, + 9, // kEqualScalar, + 9, // kEqualString, + -1, // kFlipOps, + 8, // kGreaterEqual, + // kGreaterEqualInt = kGreaterEqual, + 8, // kGreaterEqualScalar, + 8, // kGreaterEqualString, + kIfElsePrecedence, // kIf, + 13, // kLogicalAnd, + 4, // kLogicalNot, + 14, // kLogicalOr, + 4, // kMinus, + // kMinusInt = kMinus, + 4, // kMinusScalar, + 5, // kModulo, + // kModuloInt = kModulo, + 5, // kModuloScalar, + 5, // kMultiply, + // kMultiplyInt = kMultiply, + 5, // kMultiplyScalar, + kBracketPrecedence, // kParen, + 7, // kShiftLeft, + 7, // kShiftRight, // signed + 6, // kSubtract, + // kSubtractInt = kSubtract, + 6, // kSubtractScalar, + 11, // kXor +}; + +static inline bool is_between(int c, int min, int max) +{ + return (unsigned)(c - min) <= (unsigned)(max - min); +} + +static inline bool is_ws(int c) +{ + return is_between(c, 1, 32); +} + +static int token_length(const char* start) { + char ch = start[0]; + if (! is_between(ch, 'a' , 'z') && ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$') + return -1; + int length = 0; + do + ch = start[++length]; + while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') || + ch == '_' || ch == '$'); + return length; +} + +SkScriptEngine::SkScriptEngine(SkOpType returnType) : + fTokenLength(0), fReturnType(returnType), fError(kNoError) +{ + SkSuppress noInitialSuppress; + noInitialSuppress.fOperator = kUnassigned; + noInitialSuppress.fOpStackDepth = 0; + noInitialSuppress.fSuppress = false; + fSuppressStack.push(noInitialSuppress); + *fOpStack.push() = kParen; + fTrackArray.appendClear(); + fTrackString.appendClear(); +} + +SkScriptEngine::~SkScriptEngine() { + for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++) + delete *stringPtr; + for (SkTypedArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++) + delete *arrayPtr; +} + +int SkScriptEngine::arithmeticOp(char ch, char nextChar, bool lastPush) { + SkOp op = kUnassigned; + bool reverseOperands = false; + bool negateResult = false; + int advance = 1; + switch (ch) { + case '+': + // !!! ignoring unary plus as implemented here has the side effect of + // suppressing errors like +"hi" + if (lastPush == false) // unary plus, don't push an operator + goto returnAdv; + op = kAdd; + break; + case '-': + op = lastPush ? kSubtract : kMinus; + break; + case '*': + op = kMultiply; + break; + case '/': + op = kDivide; + break; + case '>': + if (nextChar == '>') { + op = kShiftRight; + goto twoChar; + } + op = kGreaterEqual; + if (nextChar == '=') + goto twoChar; + reverseOperands = negateResult = true; + break; + case '<': + if (nextChar == '<') { + op = kShiftLeft; + goto twoChar; + } + op = kGreaterEqual; + reverseOperands = nextChar == '='; + negateResult = ! reverseOperands; + advance += reverseOperands; + break; + case '=': + if (nextChar == '=') { + op = kEqual; + goto twoChar; + } + break; + case '!': + if (nextChar == '=') { + op = kEqual; + negateResult = true; +twoChar: + advance++; + break; + } + op = kLogicalNot; + break; + case '?': + op = kIf; + break; + case ':': + op = kElse; + break; + case '^': + op = kXor; + break; + case '(': + *fOpStack.push() = kParen; // push even if eval is suppressed + goto returnAdv; + case '&': + SkASSERT(nextChar != '&'); + op = kBitAnd; + break; + case '|': + SkASSERT(nextChar != '|'); + op = kBitOr; + break; + case '%': + op = kModulo; + break; + case '~': + op = kBitNot; + break; + } + if (op == kUnassigned) + return 0; + if (fSuppressStack.top().fSuppress == false) { + signed char precedence = gPrecedence[op]; + do { + int idx = 0; + SkOp compare; + do { + compare = fOpStack.index(idx); + if ((compare & kArtificialOp) == 0) + break; + idx++; + } while (true); + signed char topPrecedence = gPrecedence[compare]; + SkASSERT(topPrecedence != -1); + if (topPrecedence > precedence || topPrecedence == precedence && + gOpAttributes[op].fLeftType == kNoType) { + break; + } + if (processOp() == false) + return 0; // error + } while (true); + if (negateResult) + *fOpStack.push() = (SkOp) (kLogicalNot | kArtificialOp); + fOpStack.push(op); + if (reverseOperands) + *fOpStack.push() = (SkOp) (kFlipOps | kArtificialOp); + } +returnAdv: + return advance; +} + +void SkScriptEngine::boxCallBack(_boxCallBack func, void* userStorage) { + UserCallBack callBack; + callBack.fBoxCallBack = func; + commonCallBack(kBox, callBack, userStorage); +} + +void SkScriptEngine::commonCallBack(CallBackType type, UserCallBack& callBack, void* userStorage) { + callBack.fCallBackType = type; + callBack.fUserStorage = userStorage; + *fUserCallBacks.prepend() = callBack; +} + +bool SkScriptEngine::convertParams(SkTDArray<SkScriptValue>& params, + const SkFunctionParamType* paramTypes, int paramCount) { + if (params.count() > paramCount) { + fError = kTooManyParameters; + return false; // too many parameters passed + } + for (int index = 0; index < params.count(); index++) { + if (convertTo((SkDisplayTypes) paramTypes[index], ¶ms[index]) == false) + return false; + } + return true; +} + +bool SkScriptEngine::convertTo(SkDisplayTypes toType, SkScriptValue* value ) { + SkDisplayTypes type = value->fType; + if (type == toType) + return true; + if (ToOpType(type) == kObject) { +#if 0 // !!! I want object->string to get string from displaystringtype, not id + if (ToOpType(toType) == kString) { + bool success = handleObjectToString(value->fOperand.fObject); + if (success == false) + return false; + SkOpType type; + fTypeStack.pop(&type); + value->fType = ToDisplayType(type); + fOperandStack.pop(&value->fOperand); + return true; + } +#endif + if (handleUnbox(value) == false) { + fError = kHandleUnboxFailed; + return false; + } + return convertTo(toType, value); + } + return ConvertTo(this, toType, value); +} + +bool SkScriptEngine::evaluateDot(const char*& script, bool suppressed) { + size_t fieldLength = token_length(++script); // skip dot + if (fieldLength == 0) { + fError = kExpectedFieldName; + return false; + } + const char* field = script; + script += fieldLength; + bool success = handleProperty(suppressed); + if (success == false) { + fError = kCouldNotFindReferencedID; // note: never generated by standard animator plugins + return false; + } + return evaluateDotParam(script, suppressed, field, fieldLength); +} + +bool SkScriptEngine::evaluateDotParam(const char*& script, bool suppressed, + const char* field, size_t fieldLength) { + void* object; + if (suppressed) + object = nil; + else { + if (fTypeStack.top() != kObject) { + fError = kDotOperatorExpectsObject; + return false; + } + object = fOperandStack.top().fObject; + fTypeStack.pop(); + fOperandStack.pop(); + } + char ch; // see if it is a simple member or a function + while (is_ws(ch = script[0])) + script++; + bool success = true; + if (ch != '(') { + if (suppressed == false) { + if ((success = handleMember(field, fieldLength, object)) == false) + fError = kHandleMemberFailed; + } + } else { + SkTDArray<SkScriptValue> params; + *fBraceStack.push() = kFunctionBrace; + success = functionParams(&script, params); + if (success && suppressed == false && + (success = handleMemberFunction(field, fieldLength, object, params)) == false) + fError = kHandleMemberFunctionFailed; + } + return success; +} + +bool SkScriptEngine::evaluateScript(const char** scriptPtr, SkScriptValue* value) { +#ifdef SK_DEBUG + const char** original = scriptPtr; +#endif + bool success; + const char* inner; + if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) { + *scriptPtr += sizeof("#script:") - 1; + if (fReturnType == kNoType || fReturnType == kString) { + success = innerScript(scriptPtr, value); + if (success == false) + goto end; + inner = value->fOperand.fString->c_str(); + scriptPtr = &inner; + } + } + { + success = innerScript(scriptPtr, value); + if (success == false) + goto end; + const char* script = *scriptPtr; + char ch; + while (is_ws(ch = script[0])) + script++; + if (ch != '\0') { + // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]" + fError = kPrematureEnd; + success = false; + } + } +end: +#ifdef SK_DEBUG + if (success == false) { + SkDebugf("script failed: %s", *original); + if (fError) + SkDebugf(" %s", errorStrings[fError - 1]); + SkDebugf("\n"); + } +#endif + return success; +} + +void SkScriptEngine::forget(SkTypedArray* array) { + if (array->getType() == SkType_String) { + for (int index = 0; index < array->count(); index++) { + SkString* string = (*array)[index].fString; + int found = fTrackString.find(string); + if (found >= 0) + fTrackString.remove(found); + } + return; + } + if (array->getType() == SkType_Array) { + for (int index = 0; index < array->count(); index++) { + SkTypedArray* child = (*array)[index].fArray; + forget(child); // forgets children of child + int found = fTrackArray.find(child); + if (found >= 0) + fTrackArray.remove(found); + } + } +} + +void SkScriptEngine::functionCallBack(_functionCallBack func, void* userStorage) { + UserCallBack callBack; + callBack.fFunctionCallBack = func; + commonCallBack(kFunction, callBack, userStorage); +} + +bool SkScriptEngine::functionParams(const char** scriptPtr, SkTDArray<SkScriptValue>& params) { + (*scriptPtr)++; // skip open paren + *fOpStack.push() = kParen; + *fBraceStack.push() = kFunctionBrace; + SkBool suppressed = fSuppressStack.top().fSuppress; + do { + SkScriptValue value; + bool success = innerScript(scriptPtr, suppressed ? nil : &value); + if (success == false) { + fError = kErrorInFunctionParameters; + return false; + } + if (suppressed) + continue; + *params.append() = value; + } while ((*scriptPtr)[-1] == ','); + fBraceStack.pop(); + fOpStack.pop(); // pop paren + (*scriptPtr)++; // advance beyond close paren + return true; +} + +#ifdef SK_DEBUG +bool SkScriptEngine::getErrorString(SkString* str) const { + if (fError) + str->set(errorStrings[fError - 1]); + return fError != 0; +} +#endif + +bool SkScriptEngine::innerScript(const char** scriptPtr, SkScriptValue* value) { + const char* script = *scriptPtr; + char ch; + bool lastPush = false; + bool success = true; + int opBalance = fOpStack.count(); + int baseBrace = fBraceStack.count(); + int suppressBalance = fSuppressStack.count(); + while ((ch = script[0]) != '\0') { + if (is_ws(ch)) { + script++; + continue; + } + SkBool suppressed = fSuppressStack.top().fSuppress; + SkOperand operand; + const char* dotCheck; + if (fBraceStack.count() > baseBrace) { +#if 0 // disable support for struct brace + if (ch == ':') { + SkASSERT(fTokenLength > 0); + SkASSERT(fBraceStack.top() == kStructBrace); + ++script; + SkASSERT(fDisplayable); + SkString token(fToken, fTokenLength); + fTokenLength = 0; + const char* tokenName = token.c_str(); + const SkMemberInfo* tokenInfo SK_INIT_TO_AVOID_WARNING; + if (suppressed == false) { + SkDisplayTypes type = fInfo->getType(); + tokenInfo = SkDisplayType::GetMember(type, &tokenName); + SkASSERT(tokenInfo); + } + SkScriptValue tokenValue; + success = innerScript(&script, &tokenValue); // terminate and return on comma, close brace + SkASSERT(success); + if (suppressed == false) { + if (tokenValue.fType == SkType_Displayable) { + SkASSERT(SkDisplayType::IsDisplayable(tokenInfo->getType())); + fDisplayable->setReference(tokenInfo, tokenValue.fOperand.fDisplayable); + } else { + if (tokenValue.fType != tokenInfo->getType()) { + if (convertTo(tokenInfo->getType(), &tokenValue) == false) + return false; + } + tokenInfo->writeValue(fDisplayable, nil, 0, 0, + (void*) ((char*) fInfo->memberData(fDisplayable) + tokenInfo->fOffset + fArrayOffset), + tokenInfo->getType(), tokenValue); + } + } + lastPush = false; + continue; + } else +#endif + if (fBraceStack.top() == kArrayBrace) { + SkScriptValue tokenValue; + success = innerScript(&script, &tokenValue); // terminate and return on comma, close brace + if (success == false) { + fError = kErrorInArrrayIndex; + return false; + } + if (suppressed == false) { +#if 0 // no support for structures for now + if (tokenValue.fType == SkType_Structure) { + fArrayOffset += (int) fInfo->getSize(fDisplayable); + } else +#endif + { + SkDisplayTypes type = ToDisplayType(fReturnType); + if (fReturnType == kNoType) { + // !!! short sighted; in the future, allow each returned array component to carry + // its own type, and let caller do any needed conversions + if (value->fOperand.fArray->count() == 0) + value->fOperand.fArray->setType(type = tokenValue.fType); + else + type = value->fOperand.fArray->getType(); + } + if (tokenValue.fType != type) { + if (convertTo(type, &tokenValue) == false) + return false; + } + *value->fOperand.fArray->append() = tokenValue.fOperand; + } + } + lastPush = false; + continue; + } else { + if (token_length(script) == 0) { + fError = kExpectedToken; + return false; + } + } + } + if (lastPush != false && fTokenLength > 0) { + if (ch == '(') { + *fBraceStack.push() = kFunctionBrace; + if (handleFunction(&script, SkToBool(suppressed)) == false) + return false; + lastPush = true; + continue; + } else if (ch == '[') { + if (handleProperty(SkToBool(suppressed)) == false) + return false; // note: never triggered by standard animator plugins + if (handleArrayIndexer(&script, SkToBool(suppressed)) == false) + return false; + lastPush = true; + continue; + } else if (ch != '.') { + if (handleProperty(SkToBool(suppressed)) == false) + return false; // note: never triggered by standard animator plugins + lastPush = true; + continue; + } + } + if (ch == '0' && (script[1] & ~0x20) == 'X') { + if (lastPush != false) { + fError = kExpectedOperator; + return false; + } + script += 2; + script = SkParse::FindHex(script, (uint32_t*)&operand.fS32); + if (script == nil) { + fError = kExpectedHex; + return false; + } + goto intCommon; + } + if (lastPush == false && ch == '.') + goto scalarCommon; + if (ch >= '0' && ch <= '9') { + if (lastPush != false) { + fError = kExpectedOperator; + return false; + } + dotCheck = SkParse::FindS32(script, &operand.fS32); + if (dotCheck[0] != '.') { + script = dotCheck; +intCommon: + if (suppressed == false) + *fTypeStack.push() = kInt; + } else { +scalarCommon: + script = SkParse::FindScalar(script, &operand.fScalar); + if (suppressed == false) + *fTypeStack.push() = kScalar; + } + if (suppressed == false) + fOperandStack.push(operand); + lastPush = true; + continue; + } + int length = token_length(script); + if (length > 0) { + if (lastPush != false) { + fError = kExpectedOperator; + return false; + } + fToken = script; + fTokenLength = length; + script += length; + lastPush = true; + continue; + } + char startQuote = ch; + if (startQuote == '\'' || startQuote == '\"') { + if (lastPush != false) { + fError = kExpectedOperator; + return false; + } + operand.fString = new SkString(); + track(operand.fString); + ++script; + + // <mrr> this is a lot of calls to append() one char at at time + // how hard to preflight script so we know how much to grow fString by? + do { + if (script[0] == '\\') + ++script; + operand.fString->append(script, 1); + ++script; + if (script[0] == '\0') { + fError = kUnterminatedString; + return false; + } + } while (script[0] != startQuote); + ++script; + if (suppressed == false) { + *fTypeStack.push() = kString; + fOperandStack.push(operand); + } + lastPush = true; + continue; + } + ; + if (ch == '.') { + if (fTokenLength == 0) { + SkScriptValue scriptValue; + SkDEBUGCODE(scriptValue.fOperand.fObject = nil); + int tokenLength = token_length(++script); + const char* token = script; + script += tokenLength; + if (suppressed == false) { + if (fTypeStack.count() == 0) { + fError = kExpectedTokenBeforeDotOperator; + return false; + } + SkOpType topType; + fTypeStack.pop(&topType); + fOperandStack.pop(&scriptValue.fOperand); + scriptValue.fType = ToDisplayType(topType); + handleBox(&scriptValue); + } + success = evaluateDotParam(script, SkToBool(suppressed), token, tokenLength); + if (success == false) + return false; + lastPush = true; + continue; + } + // get next token, and evaluate immediately + success = evaluateDot(script, SkToBool(suppressed)); + if (success == false) + return false; + lastPush = true; + continue; + } + if (ch == '[') { + if (lastPush == false) { + script++; + *fBraceStack.push() = kArrayBrace; + if (suppressed) + continue; + operand.fArray = value->fOperand.fArray = new SkTypedArray(ToDisplayType(fReturnType)); + track(value->fOperand.fArray); + *fTypeStack.push() = (SkOpType) kArray; + fOperandStack.push(operand); + continue; + } + if (handleArrayIndexer(&script, SkToBool(suppressed)) == false) + return false; + lastPush = true; + continue; + } +#if 0 // structs not supported for now + if (ch == '{') { + if (lastPush == false) { + script++; + *fBraceStack.push() = kStructBrace; + if (suppressed) + continue; + operand.fS32 = 0; + *fTypeStack.push() = (SkOpType) kStruct; + fOperandStack.push(operand); + continue; + } + SkASSERT(0); // braces in other contexts aren't supported yet + } +#endif + if (ch == ')' && fBraceStack.count() > 0) { + SkBraceStyle braceStyle = fBraceStack.top(); + if (braceStyle == kFunctionBrace) { + fBraceStack.pop(); + break; + } + } + if (ch == ',' || ch == ']') { + if (ch != ',') { + SkBraceStyle match; + fBraceStack.pop(&match); + if (match != kArrayBrace) { + fError = kMismatchedArrayBrace; + return false; + } + } + script++; + // !!! see if brace or bracket is correct closer + break; + } + char nextChar = script[1]; + int advance = logicalOp(ch, nextChar); + if (advance < 0) // error + return false; + if (advance == 0) + advance = arithmeticOp(ch, nextChar, lastPush); + if (advance == 0) // unknown token + return false; + if (advance > 0) + script += advance; + lastPush = ch == ']' || ch == ')'; + } + bool suppressed = SkToBool(fSuppressStack.top().fSuppress); + if (fTokenLength > 0) { + success = handleProperty(suppressed); + if (success == false) + return false; // note: never triggered by standard animator plugins + } + while (fOpStack.count() > opBalance) { // leave open paren + if ((fError = opError()) != kNoError) + return false; + if (processOp() == false) + return false; + } + SkOpType topType = fTypeStack.count() > 0 ? fTypeStack.top() : kNoType; + if (suppressed == false && topType != fReturnType && + topType == kString && fReturnType != kNoType) { // if result is a string, give handle property a chance to convert it to the property value + SkString* string = fOperandStack.top().fString; + fToken = string->c_str(); + fTokenLength = string->size(); + fOperandStack.pop(); + fTypeStack.pop(); + success = handleProperty(SkToBool(fSuppressStack.top().fSuppress)); + if (success == false) { // if it couldn't convert, return string (error?) + SkOperand operand; + operand.fS32 = 0; + *fTypeStack.push() = kString; + operand.fString = string; + fOperandStack.push(operand); + } + } + if (value) { + if (fOperandStack.count() == 0) + return false; + SkASSERT(fOperandStack.count() >= 1); + SkASSERT(fTypeStack.count() >= 1); + fOperandStack.pop(&value->fOperand); + SkOpType type; + fTypeStack.pop(&type); + value->fType = ToDisplayType(type); +// SkASSERT(value->fType != SkType_Unknown); + if (topType != fReturnType && topType == kObject && fReturnType != kNoType) { + if (convertTo(ToDisplayType(fReturnType), value) == false) + return false; + } + } + while (fSuppressStack.count() > suppressBalance) + fSuppressStack.pop(); + *scriptPtr = script; + return true; // no error +} + +void SkScriptEngine::memberCallBack(_memberCallBack member , void* userStorage) { + UserCallBack callBack; + callBack.fMemberCallBack = member; + commonCallBack(kMember, callBack, userStorage); +} + +void SkScriptEngine::memberFunctionCallBack(_memberFunctionCallBack func, void* userStorage) { + UserCallBack callBack; + callBack.fMemberFunctionCallBack = func; + commonCallBack(kMemberFunction, callBack, userStorage); +} + +#if 0 +void SkScriptEngine::objectToStringCallBack(_objectToStringCallBack func, void* userStorage) { + UserCallBack callBack; + callBack.fObjectToStringCallBack = func; + commonCallBack(kObjectToString, callBack, userStorage); +} +#endif + +bool SkScriptEngine::handleArrayIndexer(const char** scriptPtr, bool suppressed) { + SkScriptValue scriptValue; + (*scriptPtr)++; + *fOpStack.push() = kParen; + *fBraceStack.push() = kArrayBrace; + SkOpType saveType = fReturnType; + fReturnType = kInt; + bool success = innerScript(scriptPtr, suppressed == false ? &scriptValue : nil); + if (success == false) + return false; + fReturnType = saveType; + if (suppressed == false) { + if (convertTo(SkType_Int, &scriptValue) == false) + return false; + int index = scriptValue.fOperand.fS32; + SkScriptValue scriptValue; + SkOpType type; + fTypeStack.pop(&type); + fOperandStack.pop(&scriptValue.fOperand); + scriptValue.fType = ToDisplayType(type); + if (type == kObject) { + success = handleUnbox(&scriptValue); + if (success == false) + return false; + if (ToOpType(scriptValue.fType) != kArray) { + fError = kExpectedArray; + return false; + } + } + *fTypeStack.push() = scriptValue.fOperand.fArray->getOpType(); +// SkASSERT(index >= 0); + if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) { + fError = kArrayIndexOutOfBounds; + return false; + } + scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index]; + fOperandStack.push(scriptValue.fOperand); + } + fOpStack.pop(); // pop paren + return success; +} + +bool SkScriptEngine::handleBox(SkScriptValue* scriptValue) { + bool success = true; + for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { + if (callBack->fCallBackType != kBox) + continue; + success = (*callBack->fBoxCallBack)(callBack->fUserStorage, scriptValue); + if (success) { + fOperandStack.push(scriptValue->fOperand); + *fTypeStack.push() = ToOpType(scriptValue->fType); + goto done; + } + } +done: + return success; +} + +bool SkScriptEngine::handleFunction(const char** scriptPtr, bool suppressed) { + SkScriptValue callbackResult; + SkTDArray<SkScriptValue> params; + SkString functionName(fToken, fTokenLength); + fTokenLength = 0; + bool success = functionParams(scriptPtr, params); + if (success == false) + goto done; + if (suppressed == true) + return true; + { + for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { + if (callBack->fCallBackType != kFunction) + continue; + success = (*callBack->fFunctionCallBack)(functionName.c_str(), functionName.size(), params, + callBack->fUserStorage, &callbackResult); + if (success) { + fOperandStack.push(callbackResult.fOperand); + *fTypeStack.push() = ToOpType(callbackResult.fType); + goto done; + } + } + } + fError = kNoFunctionHandlerFound; + return false; +done: + return success; +} + +bool SkScriptEngine::handleMember(const char* field, size_t len, void* object) { + SkScriptValue callbackResult; + bool success = true; + for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { + if (callBack->fCallBackType != kMember) + continue; + success = (*callBack->fMemberCallBack)(field, len, object, callBack->fUserStorage, &callbackResult); + if (success) { + if (callbackResult.fType == SkType_String) + track(callbackResult.fOperand.fString); + fOperandStack.push(callbackResult.fOperand); + *fTypeStack.push() = ToOpType(callbackResult.fType); + goto done; + } + } + return false; +done: + return success; +} + +bool SkScriptEngine::handleMemberFunction(const char* field, size_t len, void* object, SkTDArray<SkScriptValue>& params) { + SkScriptValue callbackResult; + bool success = true; + for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { + if (callBack->fCallBackType != kMemberFunction) + continue; + success = (*callBack->fMemberFunctionCallBack)(field, len, object, params, + callBack->fUserStorage, &callbackResult); + if (success) { + if (callbackResult.fType == SkType_String) + track(callbackResult.fOperand.fString); + fOperandStack.push(callbackResult.fOperand); + *fTypeStack.push() = ToOpType(callbackResult.fType); + goto done; + } + } + return false; +done: + return success; +} + +#if 0 +bool SkScriptEngine::handleObjectToString(void* object) { + SkScriptValue callbackResult; + bool success = true; + for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { + if (callBack->fCallBackType != kObjectToString) + continue; + success = (*callBack->fObjectToStringCallBack)(object, + callBack->fUserStorage, &callbackResult); + if (success) { + if (callbackResult.fType == SkType_String) + track(callbackResult.fOperand.fString); + fOperandStack.push(callbackResult.fOperand); + *fTypeStack.push() = ToOpType(callbackResult.fType); + goto done; + } + } + return false; +done: + return success; +} +#endif + +bool SkScriptEngine::handleProperty(bool suppressed) { + SkScriptValue callbackResult; + bool success = true; + if (suppressed) + goto done; + success = false; // note that with standard animator-script plugins, callback never returns false + { + for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { + if (callBack->fCallBackType != kProperty) + continue; + success = (*callBack->fPropertyCallBack)(fToken, fTokenLength, + callBack->fUserStorage, &callbackResult); + if (success) { + if (callbackResult.fType == SkType_String && callbackResult.fOperand.fString == nil) { + callbackResult.fOperand.fString = new SkString(fToken, fTokenLength); + track(callbackResult.fOperand.fString); + } + fOperandStack.push(callbackResult.fOperand); + *fTypeStack.push() = ToOpType(callbackResult.fType); + goto done; + } + } + } +done: + fTokenLength = 0; + return success; +} + +bool SkScriptEngine::handleUnbox(SkScriptValue* scriptValue) { + bool success = true; + for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { + if (callBack->fCallBackType != kUnbox) + continue; + success = (*callBack->fUnboxCallBack)(callBack->fUserStorage, scriptValue); + if (success) { + if (scriptValue->fType == SkType_String) + track(scriptValue->fOperand.fString); + goto done; + } + } + return false; +done: + return success; +} + +// note that entire expression is treated as if it were enclosed in parens +// an open paren is always the first thing in the op stack + +int SkScriptEngine::logicalOp(char ch, char nextChar) { + int advance = 1; + SkOp match; + signed char precedence; + switch (ch) { + case ')': + match = kParen; + break; + case ']': + match = kArrayOp; + break; + case '?': + match = kIf; + break; + case ':': + match = kElse; + break; + case '&': + if (nextChar != '&') + goto noMatch; + match = kLogicalAnd; + advance = 2; + break; + case '|': + if (nextChar != '|') + goto noMatch; + match = kLogicalOr; + advance = 2; + break; + default: +noMatch: + return 0; + } + SkSuppress suppress; + precedence = gPrecedence[match]; + if (fSuppressStack.top().fSuppress) { + if (fSuppressStack.top().fOpStackDepth < fOpStack.count()) { + SkOp topOp = fOpStack.top(); + if (gPrecedence[topOp] <= precedence) + fOpStack.pop(); + goto goHome; + } + bool changedPrecedence = gPrecedence[fSuppressStack.top().fOperator] < precedence; + if (changedPrecedence) + fSuppressStack.pop(); + if (precedence == kIfElsePrecedence) { + if (match == kIf) { + if (changedPrecedence) + fOpStack.pop(); + else + *fOpStack.push() = kIf; + } else { + if (fSuppressStack.top().fOpStackDepth == fOpStack.count()) { + goto flipSuppress; + } + fOpStack.pop(); + } + } + if (changedPrecedence == false) + goto goHome; + } + while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence) { + if (processOp() == false) + return false; + } + if (fSuppressStack.top().fOpStackDepth > fOpStack.count()) + fSuppressStack.pop(); + switch (match) { + case kParen: + case kArrayOp: + if (fOpStack.count() <= 1 || fOpStack.top() != match) { + fError = kMismatchedBrackets; + return -1; + } + if (match == kParen) + fOpStack.pop(); + else { + SkOpType indexType; + fTypeStack.pop(&indexType); + if (indexType != kInt && indexType != kScalar) { + fError = kExpectedNumberForArrayIndex; // (although, could permit strings eventually) + return -1; + } + SkOperand indexOperand; + fOperandStack.pop(&indexOperand); + int index = indexType == kScalar ? SkScalarFloor(indexOperand.fScalar) : + indexOperand.fS32; + SkOpType arrayType; + fTypeStack.pop(&arrayType); + if ((unsigned)arrayType != (unsigned)kArray) { + fError = kExpectedArray; + return -1; + } + SkOperand arrayOperand; + fOperandStack.pop(&arrayOperand); + SkTypedArray* array = arrayOperand.fArray; + SkOperand operand; + if (array->getIndex(index, &operand) == false) { + fError = kIndexOutOfRange; + return -1; + } + SkOpType resultType = array->getOpType(); + fTypeStack.push(resultType); + fOperandStack.push(operand); + } + break; + case kIf: { + SkScriptValue ifValue; + SkOpType ifType; + fTypeStack.pop(&ifType); + ifValue.fType = ToDisplayType(ifType); + fOperandStack.pop(&ifValue.fOperand); + if (convertTo(SkType_Int, &ifValue) == false) + return -1; + if (ifValue.fType != SkType_Int) { + fError = kExpectedIntForConditionOperator; + return -1; + } + suppress.fSuppress = ifValue.fOperand.fS32 == 0; + suppress.fOperator = kIf; + suppress.fOpStackDepth = fOpStack.count(); + suppress.fElse = false; + fSuppressStack.push(suppress); + // if left is true, do only up to colon + // if left is false, do only after colon + } break; + case kElse: +flipSuppress: + if (fSuppressStack.top().fElse == true) + fSuppressStack.pop(); + fSuppressStack.top().fElse = true; + fSuppressStack.top().fSuppress ^= true; + // flip last do / don't do consideration from last '?' + break; + case kLogicalAnd: + case kLogicalOr: { + if (fTypeStack.top() != kInt) { + fError = kExpectedBooleanExpression; + return -1; + } + S32 topInt = fOperandStack.top().fS32; + if (fOpStack.top() != kLogicalAnd) + *fOpStack.push() = kLogicalAnd; // really means 'to bool', and is appropriate for 'or' + if (match == kLogicalOr ? topInt != 0 : topInt == 0) { + suppress.fSuppress = true; + suppress.fOperator = match; + suppress.fOpStackDepth = fOpStack.count(); + fSuppressStack.push(suppress); + } else { + fTypeStack.pop(); + fOperandStack.pop(); + } + } break; + default: + SkASSERT(0); + } +goHome: + return advance; +} + +SkScriptEngine::Error SkScriptEngine::opError() { + int opCount = fOpStack.count(); + int operandCount = fOperandStack.count(); + if (opCount == 0) { + if (operandCount != 1) + return kExpectedOperator; + return kNoError; + } + SkOp op = (SkOp) (fOpStack.top() & ~kArtificialOp); + const SkOperatorAttributes* attributes = &gOpAttributes[op]; + if (attributes->fLeftType != kNoType && operandCount < 2) + return kExpectedValue; + if (attributes->fLeftType == kNoType && operandCount < 1) + return kExpectedValue; + return kNoError; +} + +bool SkScriptEngine::processOp() { + SkOp op; + fOpStack.pop(&op); + op = (SkOp) (op & ~kArtificialOp); + const SkOperatorAttributes* attributes = &gOpAttributes[op]; + SkOpType type2; + fTypeStack.pop(&type2); + SkOpType type1 = type2; + SkOperand operand2; + fOperandStack.pop(&operand2); + SkOperand operand1 = operand2; // !!! not really needed, suppresses warning + if (attributes->fLeftType != kNoType) { + fTypeStack.pop(&type1); + fOperandStack.pop(&operand1); + if (op == kFlipOps) { + SkTSwap(type1, type2); + SkTSwap(operand1, operand2); + fOpStack.pop(&op); + op = (SkOp) (op & ~kArtificialOp); + attributes = &gOpAttributes[op]; + } + if (type1 == kObject && (type1 & attributes->fLeftType) == 0) { + SkScriptValue val; + val.fType = ToDisplayType(type1); + val.fOperand = operand1; + bool success = handleUnbox(&val); + if (success == false) + return false; + type1 = ToOpType(val.fType); + operand1 = val.fOperand; + } + } + if (type2 == kObject && (type2 & attributes->fLeftType) == 0) { + SkScriptValue val; + val.fType = ToDisplayType(type2); + val.fOperand = operand2; + bool success = handleUnbox(&val); + if (success == false) + return false; + type2 = ToOpType(val.fType); + operand2 = val.fOperand; + } + if (attributes->fLeftType != kNoType) { + if (type1 != type2) { + if ((attributes->fLeftType & kString) && attributes->fBias & kTowardsString && ((type1 | type2) & kString)) { + if (type1 == kInt || type1 == kScalar) { + convertToString(operand1, type1 == kInt ? SkType_Int : SkType_Float); + type1 = kString; + } + if (type2 == kInt || type2 == kScalar) { + convertToString(operand2, type2 == kInt ? SkType_Int : SkType_Float); + type2 = kString; + } + } else if (attributes->fLeftType & kScalar && ((type1 | type2) & kScalar)) { + if (type1 == kInt) { + operand1.fScalar = IntToScalar(operand1.fS32); + type1 = kScalar; + } + if (type2 == kInt) { + operand2.fScalar = IntToScalar(operand2.fS32); + type2 = kScalar; + } + } + } + if ((type1 & attributes->fLeftType) == 0 || type1 != type2) { + if (type1 == kString) { + const char* result = SkParse::FindScalar(operand1.fString->c_str(), &operand1.fScalar); + if (result == nil) { + fError = kExpectedNumber; + return false; + } + type1 = kScalar; + } + if (type1 == kScalar && (attributes->fLeftType == kInt || type2 == kInt)) { + operand1.fS32 = SkScalarFloor(operand1.fScalar); + type1 = kInt; + } + } + } + if ((type2 & attributes->fRightType) == 0 || type1 != type2) { + if (type2 == kString) { + const char* result = SkParse::FindScalar(operand2.fString->c_str(), &operand2.fScalar); + if (result == nil) { + fError = kExpectedNumber; + return false; + } + type2 = kScalar; + } + if (type2 == kScalar && (attributes->fRightType == kInt || type1 == kInt)) { + operand2.fS32 = SkScalarFloor(operand2.fScalar); + type2 = kInt; + } + } + if (type2 == kScalar) + op = (SkOp) (op + 1); + else if (type2 == kString) + op = (SkOp) (op + 2); + switch(op) { + case kAddInt: + operand2.fS32 += operand1.fS32; + break; + case kAddScalar: + operand2.fScalar += operand1.fScalar; + break; + case kAddString: + if (fTrackString.find(operand1.fString) < 0) { + operand1.fString = SkNEW_ARGS(SkString, (*operand1.fString)); + track(operand1.fString); + } + operand1.fString->append(*operand2.fString); + operand2 = operand1; + break; + case kBitAnd: + operand2.fS32 &= operand1.fS32; + break; + case kBitNot: + operand2.fS32 = ~operand2.fS32; + break; + case kBitOr: + operand2.fS32 |= operand1.fS32; + break; + case kDivideInt: + if (operand2.fS32 == 0) { + operand2.fS32 = operand1.fS32 == 0 ? SK_NaN32 : operand1.fS32 > 0 ? SK_MaxS32 : -SK_MaxS32; + break; + } else { + S32 original = operand2.fS32; + operand2.fS32 = operand1.fS32 / operand2.fS32; + if (original * operand2.fS32 == operand1.fS32) + break; // integer divide was good enough + operand2.fS32 = original; + type2 = kScalar; + } + case kDivideScalar: + if (operand2.fScalar == 0) + operand2.fScalar = operand1.fScalar == 0 ? SK_ScalarNaN : operand1.fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax; + else + operand2.fScalar = SkScalarDiv(operand1.fScalar, operand2.fScalar); + break; + case kEqualInt: + operand2.fS32 = operand1.fS32 == operand2.fS32; + break; + case kEqualScalar: + operand2.fS32 = operand1.fScalar == operand2.fScalar; + type2 = kInt; + break; + case kEqualString: + operand2.fS32 = *operand1.fString == *operand2.fString; + type2 = kInt; + break; + case kGreaterEqualInt: + operand2.fS32 = operand1.fS32 >= operand2.fS32; + break; + case kGreaterEqualScalar: + operand2.fS32 = operand1.fScalar >= operand2.fScalar; + type2 = kInt; + break; + case kGreaterEqualString: + operand2.fS32 = strcmp(operand1.fString->c_str(), operand2.fString->c_str()) >= 0; + type2 = kInt; + break; + case kLogicalAnd: + operand2.fS32 = !! operand2.fS32; // really, ToBool + break; + case kLogicalNot: + operand2.fS32 = ! operand2.fS32; + break; + case kLogicalOr: + SkASSERT(0); // should have already been processed + break; + case kMinusInt: + operand2.fS32 = -operand2.fS32; + break; + case kMinusScalar: + operand2.fScalar = -operand2.fScalar; + break; + case kModuloInt: + operand2.fS32 = operand1.fS32 % operand2.fS32; + break; + case kModuloScalar: + operand2.fScalar = SkScalarMod(operand1.fScalar, operand2.fScalar); + break; + case kMultiplyInt: + operand2.fS32 *= operand1.fS32; + break; + case kMultiplyScalar: + operand2.fScalar = SkScalarMul(operand1.fScalar, operand2.fScalar); + break; + case kShiftLeft: + operand2.fS32 = operand1.fS32 << operand2.fS32; + break; + case kShiftRight: + operand2.fS32 = operand1.fS32 >> operand2.fS32; + break; + case kSubtractInt: + operand2.fS32 = operand1.fS32 - operand2.fS32; + break; + case kSubtractScalar: + operand2.fScalar = operand1.fScalar - operand2.fScalar; + break; + case kXor: + operand2.fS32 ^= operand1.fS32; + break; + default: + SkASSERT(0); + } + fTypeStack.push(type2); + fOperandStack.push(operand2); + return true; +} + +void SkScriptEngine::propertyCallBack(_propertyCallBack prop, void* userStorage) { + UserCallBack callBack; + callBack.fPropertyCallBack = prop; + commonCallBack(kProperty, callBack, userStorage); +} + +void SkScriptEngine::track(SkTypedArray* array) { + SkASSERT(fTrackArray.find(array) < 0); + *(fTrackArray.end() - 1) = array; + fTrackArray.appendClear(); +} + +void SkScriptEngine::track(SkString* string) { + SkASSERT(fTrackString.find(string) < 0); + *(fTrackString.end() - 1) = string; + fTrackString.appendClear(); +} + +void SkScriptEngine::unboxCallBack(_unboxCallBack func, void* userStorage) { + UserCallBack callBack; + callBack.fUnboxCallBack = func; + commonCallBack(kUnbox, callBack, userStorage); +} + +bool SkScriptEngine::ConvertTo(SkScriptEngine* engine, SkDisplayTypes toType, SkScriptValue* value ) { + SkASSERT(value); + if (SkDisplayType::IsEnum(nil /* fMaker */, toType)) + toType = SkType_Int; + if (toType == SkType_Point || toType == SkType_3D_Point) + toType = SkType_Float; + if (toType == SkType_Drawable) + toType = SkType_Displayable; + SkDisplayTypes type = value->fType; + if (type == toType) + return true; + SkOperand& operand = value->fOperand; + bool success = true; + switch (toType) { + case SkType_Int: + if (type == SkType_Boolean) + break; + if (type == SkType_Float) + operand.fS32 = SkScalarFloor(operand.fScalar); + else { + if (type != SkType_String) { + success = false; + break; // error + } + success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != nil; + } + break; + case SkType_Float: + if (type == SkType_Int) { + if ((uint32_t)operand.fS32 == SK_NaN32) + operand.fScalar = SK_ScalarNaN; + else if (SkAbs32(operand.fS32) == SK_MaxS32) + operand.fScalar = SkSign32(operand.fS32) * SK_ScalarMax; + else + operand.fScalar = SkIntToScalar(operand.fS32); + } else { + if (type != SkType_String) { + success = false; + break; // error + } + success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != nil; + } + break; + case SkType_String: { + SkString* strPtr = new SkString(); + SkASSERT(engine); + engine->track(strPtr); + if (type == SkType_Int) + strPtr->appendS32(operand.fS32); + else if (type == SkType_Displayable) + SkASSERT(0); // must call through instance version instead of static version + else { + if (type != SkType_Float) { + success = false; + break; + } + strPtr->appendScalar(operand.fScalar); + } + operand.fString = strPtr; + } break; + case SkType_Array: { + SkTypedArray* array = new SkTypedArray(type); + *array->append() = operand; + engine->track(array); + operand.fArray = array; + } break; + default: + SkASSERT(0); + } + value->fType = toType; + if (success == false) + engine->fError = kTypeConversionFailed; + return success; +} + +SkScalar SkScriptEngine::IntToScalar(S32 s32) { + SkScalar scalar; + if ((uint32_t)s32 == SK_NaN32) + scalar = SK_ScalarNaN; + else if (SkAbs32(s32) == SK_MaxS32) + scalar = SkSign32(s32) * SK_ScalarMax; + else + scalar = SkIntToScalar(s32); + return scalar; +} + +SkDisplayTypes SkScriptEngine::ToDisplayType(SkOpType type) { + int val = type; + switch (val) { + case kNoType: + return SkType_Unknown; + case kInt: + return SkType_Int; + case kScalar: + return SkType_Float; + case kString: + return SkType_String; + case kArray: + return SkType_Array; + case kObject: + return SkType_Displayable; +// case kStruct: +// return SkType_Structure; + default: + SkASSERT(0); + return SkType_Unknown; + } +} + +SkScriptEngine::SkOpType SkScriptEngine::ToOpType(SkDisplayTypes type) { + if (SkDisplayType::IsDisplayable(nil /* fMaker */, type)) + return (SkOpType) kObject; + if (SkDisplayType::IsEnum(nil /* fMaker */, type)) + return kInt; + switch (type) { + case SkType_ARGB: + case SkType_MSec: + case SkType_Int: + return kInt; + case SkType_Float: + case SkType_Point: + case SkType_3D_Point: + return kScalar; + case SkType_Base64: + case SkType_DynamicString: + case SkType_String: + return kString; + case SkType_Array: + return (SkOpType) kArray; + case SkType_Unknown: + return kNoType; + default: + SkASSERT(0); + return kNoType; + } +} + +bool SkScriptEngine::ValueToString(SkScriptValue value, SkString* string) { + switch (value.fType) { + case kInt: + string->reset(); + string->appendS32(value.fOperand.fS32); + break; + case kScalar: + string->reset(); + string->appendScalar(value.fOperand.fScalar); + break; + case kString: + string->set(*value.fOperand.fString); + break; + default: + SkASSERT(0); + return false; + } + return true; // no error +} + +#ifdef SK_SUPPORT_UNITTEST + +#ifdef SK_CAN_USE_FLOAT + #include "SkFloatingPoint.h" +#endif + +#define DEF_SCALAR_ANSWER 0 +#define DEF_STRING_ANSWER NULL + +#define testInt(expression) { #expression, SkType_Int, expression, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER } +#ifdef SK_SCALAR_IS_FLOAT + #define testScalar(expression) { #expression, SkType_Float, 0, (float) expression, DEF_STRING_ANSWER } + #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkType_Float, 0, sk_float_mod(exp1, exp2), DEF_STRING_ANSWER } +#else + #ifdef SK_CAN_USE_FLOAT + #define testScalar(expression) { #expression, SkType_Float, 0, (int) ((expression) * 65536.0f), DEF_STRING_ANSWER } + #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkType_Float, 0, (int) (sk_float_mod(exp1, exp2) * 65536.0f), DEF_STRING_ANSWER } + #endif +#endif +#define testTrue(expression) { #expression, SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER } +#define testFalse(expression) { #expression, SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER } + +#if !defined(SK_BUILD_FOR_BREW) +static const SkScriptNAnswer scriptTests[] = { + testInt(1>1/2), + testInt((6+7)*8), + testInt(0&&1?2:3), + testInt(3*(4+5)), +#ifdef SK_CAN_USE_FLOAT + testScalar(1.0+2.0), + testScalar(1.0+5), + testScalar(3.0-1.0), + testScalar(6-1.0), + testScalar(- -5.5- -1.5), + testScalar(2.5*6.), + testScalar(0.5*4), + testScalar(4.5/.5), + testScalar(9.5/19), + testRemainder(9.5, 0.5), + testRemainder(9.,2), + testRemainder(9,2.5), + testRemainder(-9,2.5), + testTrue(-9==-9.0), + testTrue(-9.==-4.0-5), + testTrue(-9.*1==-4-5), + testFalse(-9!=-9.0), + testFalse(-9.!=-4.0-5), + testFalse(-9.*1!=-4-5), +#endif + testInt(0x123), + testInt(0XABC), + testInt(0xdeadBEEF), + { "'123'+\"456\"", SkType_String, 0, 0, "123456" }, + { "123+\"456\"", SkType_String, 0, 0, "123456" }, + { "'123'+456", SkType_String, 0, 0, "123456" }, + { "'123'|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, + { "123|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, + { "'123'|456", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, + { "'2'<11", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, + { "2<'11'", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, + { "'2'<'11'", SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, + testInt(123), + testInt(-345), + testInt(+678), + testInt(1+2+3), + testInt(3*4+5), + testInt(6+7*8), + testInt(-1-2-8/4), + testInt(-9%4), + testInt(9%-4), + testInt(-9%-4), + testInt(123|978), + testInt(123&978), + testInt(123^978), + testInt(2<<4), + testInt(99>>3), + testInt(~55), + testInt(~~55), + testInt(!55), + testInt(!!55), + // both int + testInt(2<2), + testInt(2<11), + testInt(20<11), + testInt(2<=2), + testInt(2<=11), + testInt(20<=11), + testInt(2>2), + testInt(2>11), + testInt(20>11), + testInt(2>=2), + testInt(2>=11), + testInt(20>=11), + testInt(2==2), + testInt(2==11), + testInt(20==11), + testInt(2!=2), + testInt(2!=11), + testInt(20!=11), +#ifdef SK_CAN_USE_FLOAT + // left int, right scalar + testInt(2<2.), + testInt(2<11.), + testInt(20<11.), + testInt(2<=2.), + testInt(2<=11.), + testInt(20<=11.), + testInt(2>2.), + testInt(2>11.), + testInt(20>11.), + testInt(2>=2.), + testInt(2>=11.), + testInt(20>=11.), + testInt(2==2.), + testInt(2==11.), + testInt(20==11.), + testInt(2!=2.), + testInt(2!=11.), + testInt(20!=11.), + // left scalar, right int + testInt(2.<2), + testInt(2.<11), + testInt(20.<11), + testInt(2.<=2), + testInt(2.<=11), + testInt(20.<=11), + testInt(2.>2), + testInt(2.>11), + testInt(20.>11), + testInt(2.>=2), + testInt(2.>=11), + testInt(20.>=11), + testInt(2.==2), + testInt(2.==11), + testInt(20.==11), + testInt(2.!=2), + testInt(2.!=11), + testInt(20.!=11), + // both scalar + testInt(2.<11.), + testInt(20.<11.), + testInt(2.<=2.), + testInt(2.<=11.), + testInt(20.<=11.), + testInt(2.>2.), + testInt(2.>11.), + testInt(20.>11.), + testInt(2.>=2.), + testInt(2.>=11.), + testInt(20.>=11.), + testInt(2.==2.), + testInt(2.==11.), + testInt(20.==11.), + testInt(2.!=2.), + testInt(2.!=11.), + testInt(20.!=11.), +#endif + // int, string (string is int) + testFalse(2<'2'), + testTrue(2<'11'), + testFalse(20<'11'), + testTrue(2<='2'), + testTrue(2<='11'), + testFalse(20<='11'), + testFalse(2>'2'), + testFalse(2>'11'), + testTrue(20>'11'), + testTrue(2>='2'), + testFalse(2>='11'), + testTrue(20>='11'), + testTrue(2=='2'), + testFalse(2=='11'), + testFalse(2!='2'), + testTrue(2!='11'), + // int, string (string is scalar) + testFalse(2<'2.'), + testTrue(2<'11.'), + testFalse(20<'11.'), + testTrue(2=='2.'), + testFalse(2=='11.'), +#ifdef SK_CAN_USE_FLOAT + // scalar, string + testFalse(2.<'2.'), + testTrue(2.<'11.'), + testFalse(20.<'11.'), + testTrue(2.=='2.'), + testFalse(2.=='11.'), + // string, int + testFalse('2'<2), + testTrue('2'<11), + testFalse('20'<11), + testTrue('2'==2), + testFalse('2'==11), + // string, scalar + testFalse('2'<2.), + testTrue('2'<11.), + testFalse('20'<11.), + testTrue('2'==2.), + testFalse('2'==11.), +#endif + // string, string + testFalse('2'<'2'), + testFalse('2'<'11'), + testFalse('20'<'11'), + testTrue('2'=='2'), + testFalse('2'=='11'), + // logic + testInt(1?2:3), + testInt(0?2:3), + testInt(1&&2||3), + testInt(1&&0||3), + testInt(1&&0||0), + testInt(1||0&&3), + testInt(0||0&&3), + testInt(0||1&&3), + testInt(1?(2?3:4):5), + testInt(0?(2?3:4):5), + testInt(1?(0?3:4):5), + testInt(0?(0?3:4):5), + testInt(1?2?3:4:5), + testInt(0?2?3:4:5), + testInt(1?0?3:4:5), + testInt(0?0?3:4:5), + + testInt(1?2:(3?4:5)), + testInt(0?2:(3?4:5)), + testInt(1?0:(3?4:5)), + testInt(0?0:(3?4:5)), + testInt(1?2:3?4:5), + testInt(0?2:3?4:5), + testInt(1?0:3?4:5), + testInt(0?0:3?4:5) +#ifdef SK_CAN_USE_FLOAT + , { "123.5", SkType_Float, 0, SkIntToScalar(123) + SK_Scalar1/2, DEF_STRING_ANSWER } +#endif +}; +#endif // build for brew + +#define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) + +void SkScriptEngine::UnitTest() { +#if !defined(SK_BUILD_FOR_BREW) + for (unsigned index = 0; index < SkScriptNAnswer_testCount; index++) { + SkScriptEngine engine(SkScriptEngine::ToOpType(scriptTests[index].fType)); + SkScriptValue value; + const char* script = scriptTests[index].fScript; + SkASSERT(engine.evaluateScript(&script, &value) == true); + SkASSERT(value.fType == scriptTests[index].fType); + SkScalar error; + switch (value.fType) { + case SkType_Int: + SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); + break; + case SkType_Float: + error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); + SkASSERT(error < SK_Scalar1 / 10000); + break; + case SkType_String: + SkASSERT(strcmp(value.fOperand.fString->c_str(), scriptTests[index].fStringAnswer) == 0); + break; + default: + SkASSERT(0); + } + } +#endif +} +#endif + diff --git a/libs/graphics/animator/SkScript.h b/libs/graphics/animator/SkScript.h new file mode 100644 index 0000000000..e172c9ed63 --- /dev/null +++ b/libs/graphics/animator/SkScript.h @@ -0,0 +1,257 @@ +#ifndef SkScript_DEFINED +#define SkScript_DEFINED + +#include "SkOperand.h" +#include "SkIntArray.h" +#include "SkTDict.h" +#include "SkTDStack.h" + +class SkAnimateMaker; + +class SkScriptEngine { +public: + enum Error { + kNoError, + kArrayIndexOutOfBounds, + kCouldNotFindReferencedID, + kDotOperatorExpectsObject, + kErrorInArrrayIndex, + kErrorInFunctionParameters, + kExpectedArray, + kExpectedBooleanExpression, + kExpectedFieldName, + kExpectedHex, + kExpectedIntForConditionOperator, + kExpectedNumber, + kExpectedNumberForArrayIndex, + kExpectedOperator, + kExpectedToken, + kExpectedTokenBeforeDotOperator, + kExpectedValue, + kHandleMemberFailed, + kHandleMemberFunctionFailed, + kHandleUnboxFailed, + kIndexOutOfRange, + kMismatchedArrayBrace, + kMismatchedBrackets, + kNoFunctionHandlerFound, + kPrematureEnd, + kTooManyParameters, + kTypeConversionFailed, + kUnterminatedString + }; + + enum SkOpType { + kNoType, + kInt = 1, + kScalar = 2, + kString = 4, + kArray = 8, + kObject = 16 +// kStruct = 32 + }; + + typedef bool (*_boxCallBack)(void* userStorage, SkScriptValue* result); + typedef bool (*_functionCallBack)(const char* func, size_t len, SkTDArray<SkScriptValue>& params, + void* userStorage, SkScriptValue* result); + typedef bool (*_memberCallBack)(const char* member, size_t len, void* object, + void* userStorage, SkScriptValue* result); + typedef bool (*_memberFunctionCallBack)(const char* member, size_t len, void* object, + SkTDArray<SkScriptValue>& params, void* userStorage, SkScriptValue* result); +// typedef bool (*_objectToStringCallBack)(void* object, void* userStorage, SkScriptValue* result); + typedef bool (*_propertyCallBack)(const char* prop, size_t len, void* userStorage, SkScriptValue* result); + typedef bool (*_unboxCallBack)(void* userStorage, SkScriptValue* result); + SkScriptEngine(SkOpType returnType); + ~SkScriptEngine(); + void boxCallBack(_boxCallBack func, void* userStorage); + bool convertTo(SkDisplayTypes , SkScriptValue* ); + bool evaluateScript(const char** script, SkScriptValue* value); + void forget(SkTypedArray* array); + void functionCallBack(_functionCallBack func, void* userStorage); + Error getError() const { return fError; } +#ifdef SK_DEBUG + bool getErrorString(SkString* err) const; +#endif + void memberCallBack(_memberCallBack , void* userStorage); + void memberFunctionCallBack(_memberFunctionCallBack , void* userStorage); +// void objectToStringCallBack(_objectToStringCallBack , void* userStorage); + void propertyCallBack(_propertyCallBack prop, void* userStorage); + void track(SkTypedArray* array); + void track(SkString* string); + void unboxCallBack(_unboxCallBack func, void* userStorage); + static bool ConvertTo(SkScriptEngine* , SkDisplayTypes toType, SkScriptValue* value); + static SkScalar IntToScalar(S32 ); + static SkDisplayTypes ToDisplayType(SkOpType type); + static SkOpType ToOpType(SkDisplayTypes type); + static bool ValueToString(SkScriptValue value, SkString* string); + + enum CallBackType { + kBox, + kFunction, + kMember, + kMemberFunction, + // kObjectToString, + kProperty, + kUnbox + }; + + struct UserCallBack { + CallBackType fCallBackType; + void* fUserStorage; + union { + _boxCallBack fBoxCallBack; + _functionCallBack fFunctionCallBack; + _memberCallBack fMemberCallBack; + _memberFunctionCallBack fMemberFunctionCallBack; + // _objectToStringCallBack fObjectToStringCallBack; + _propertyCallBack fPropertyCallBack; + _unboxCallBack fUnboxCallBack; + }; + }; + + enum SkOp { + kUnassigned, + kAdd, + kAddInt = kAdd, + kAddScalar, + kAddString, // string concat + kArrayOp, + kBitAnd, + kBitNot, + kBitOr, + kDivide, + kDivideInt = kDivide, + kDivideScalar, + kElse, + kEqual, + kEqualInt = kEqual, + kEqualScalar, + kEqualString, + kFlipOps, + kGreaterEqual, + kGreaterEqualInt = kGreaterEqual, + kGreaterEqualScalar, + kGreaterEqualString, + kIf, + kLogicalAnd, + kLogicalNot, + kLogicalOr, + kMinus, + kMinusInt = kMinus, + kMinusScalar, + kModulo, + kModuloInt = kModulo, + kModuloScalar, + kMultiply, + kMultiplyInt = kMultiply, + kMultiplyScalar, + kParen, + kShiftLeft, + kShiftRight, // signed + kSubtract, + kSubtractInt = kSubtract, + kSubtractScalar, + kXor, + kArtificialOp = 0x40 + }; + + enum SkOpBias { + kNoBias, + kTowardsNumber = 0, + kTowardsString + }; + +protected: + + struct SkOperatorAttributes { + unsigned int fLeftType : 3; // SkOpType, but only lower values + unsigned int fRightType : 3; // SkOpType, but only lower values + SkOpBias fBias : 1; + }; + + struct SkSuppress { // !!! could be compressed to a long + SkOp fOperator; // operand which enabled suppression + int fOpStackDepth; // depth when suppression operator was found + SkBool8 fSuppress; // set if suppression happens now, as opposed to later + SkBool8 fElse; // set on the : half of ? : + }; + + static const SkOperatorAttributes gOpAttributes[]; + static const signed char gPrecedence[]; + int arithmeticOp(char ch, char nextChar, bool lastPush); + void commonCallBack(CallBackType type, UserCallBack& callBack, void* userStorage); + bool convertParams(SkTDArray<SkScriptValue>&, const SkFunctionParamType* , + int paramTypeCount); + void convertToString(SkOperand& operand, SkDisplayTypes type) { + SkScriptValue scriptValue; + scriptValue.fOperand = operand; + scriptValue.fType = type; + convertTo(SkType_String, &scriptValue); + operand = scriptValue.fOperand; + } + bool evaluateDot(const char*& script, bool suppressed); + bool evaluateDotParam(const char*& script, bool suppressed, const char* field, size_t fieldLength); + bool functionParams(const char** scriptPtr, SkTDArray<SkScriptValue>& params); + bool handleArrayIndexer(const char** scriptPtr, bool suppressed); + bool handleBox(SkScriptValue* value); + bool handleFunction(const char** scriptPtr, bool suppressed); + bool handleMember(const char* field, size_t len, void* object); + bool handleMemberFunction(const char* field, size_t len, void* object, SkTDArray<SkScriptValue>& params); +// bool handleObjectToString(void* object); + bool handleProperty(bool suppressed); + bool handleUnbox(SkScriptValue* scriptValue); + bool innerScript(const char** scriptPtr, SkScriptValue* value); + int logicalOp(char ch, char nextChar); + Error opError(); + bool processOp(); + void setAnimateMaker(SkAnimateMaker* maker) { fMaker = maker; } + bool setError(Error , const char* pos); + enum SkBraceStyle { + // kStructBrace, + kArrayBrace, + kFunctionBrace + }; + +#if 0 + SkIntArray(SkBraceStyle) fBraceStack; // curly, square, function paren + SkIntArray(SkOp) fOpStack; + SkIntArray(SkOpType) fTypeStack; + SkTDOperandArray fOperandStack; + SkTDArray<SkSuppress> fSuppressStack; +#else + SkTDStack<SkBraceStyle> fBraceStack; // curly, square, function paren + SkTDStack<SkOp> fOpStack; + SkTDStack<SkOpType> fTypeStack; + SkTDStack<SkOperand> fOperandStack; + SkTDStack<SkSuppress> fSuppressStack; +#endif + SkAnimateMaker* fMaker; + SkTDTypedArrayArray fTrackArray; + SkTDStringArray fTrackString; + const char* fToken; // one-deep stack + size_t fTokenLength; + SkTDArray<UserCallBack> fUserCallBacks; + SkOpType fReturnType; + Error fError; + int fErrorPosition; +private: + friend class SkTypedArray; +#ifdef SK_SUPPORT_UNITTEST +public: + static void UnitTest(); +#endif +}; + +#ifdef SK_SUPPORT_UNITTEST + +struct SkScriptNAnswer { + const char* fScript; + SkDisplayTypes fType; + S32 fIntAnswer; + SkScalar fScalarAnswer; + const char* fStringAnswer; +}; + +#endif + +#endif // SkScript_DEFINED diff --git a/libs/graphics/animator/SkScript2.h b/libs/graphics/animator/SkScript2.h new file mode 100755 index 0000000000..2443d822d1 --- /dev/null +++ b/libs/graphics/animator/SkScript2.h @@ -0,0 +1,285 @@ +#ifndef SkScript2_DEFINED +#define SkScript2_DEFINED + +#include "SkOperand2.h" +#include "SkStream.h" +#include "SkTDArray.h" +#include "SkTDArray_Experimental.h" +#include "SkTDict.h" +#include "SkTDStack.h" + +typedef SkLongArray(SkString*) SkTDStringArray; + +class SkAnimateMaker; +class SkScriptCallBack; + +class SkScriptEngine2 { +public: + enum Error { + kNoError, + kArrayIndexOutOfBounds, + kCouldNotFindReferencedID, + kFunctionCallFailed, + kMemberOpFailed, + kPropertyOpFailed + }; + + enum Attrs { + kConstant, + kVariable + }; + + SkScriptEngine2(SkOperand2::OpType returnType); + ~SkScriptEngine2(); + bool convertTo(SkOperand2::OpType , SkScriptValue2* ); + bool evaluateScript(const char** script, SkScriptValue2* value); + void forget(SkOpArray* array); + Error getError() { return fError; } + SkOperand2::OpType getReturnType() { return fReturnType; } + void track(SkOpArray* array) { + SkASSERT(fTrackArray.find(array) < 0); + *fTrackArray.append() = array; } + void track(SkString* string) { + SkASSERT(fTrackString.find(string) < 0); + *fTrackString.append() = string; + } + static bool ConvertTo(SkScriptEngine2* , SkOperand2::OpType toType, SkScriptValue2* value); + static SkScalar IntToScalar(S32 ); + static bool ValueToString(const SkScriptValue2& value, SkString* string); + + enum Op { // used by tokenizer attribute table + kUnassigned, + kAdd, + kBitAnd, + kBitNot, + kBitOr, + kDivide, + kEqual, + kFlipOps, + kGreaterEqual, + kLogicalAnd, + kLogicalNot, + kLogicalOr, + kMinus, + kModulo, + kMultiply, + kShiftLeft, + kShiftRight, // signed + kSubtract, + kXor, +// following not in attribute table + kArrayOp, + kElse, + kIf, + kParen, + kLastLogicalOp, + kArtificialOp = 0x20 + }; + + enum TypeOp { // generated by tokenizer + kNop, // should never get generated + kAccumulatorPop, + kAccumulatorPush, + kAddInt, + kAddScalar, + kAddString, // string concat + kArrayIndex, + kArrayParam, + kArrayToken, + kBitAndInt, + kBitNotInt, + kBitOrInt, + kBoxToken, + kCallback, + kDivideInt, + kDivideScalar, + kDotOperator, + kElseOp, + kEnd, + kEqualInt, + kEqualScalar, + kEqualString, + kFunctionCall, + kFlipOpsOp, + kFunctionToken, + kGreaterEqualInt, + kGreaterEqualScalar, + kGreaterEqualString, + kIfOp, + kIntToScalar, + kIntToScalar2, + kIntToString, + kIntToString2, + kIntegerAccumulator, + kIntegerOperand, + kLogicalAndInt, + kLogicalNotInt, + kLogicalOrInt, + kMemberOp, + kMinusInt, + kMinusScalar, + kModuloInt, + kModuloScalar, + kMultiplyInt, + kMultiplyScalar, + kPropertyOp, + kScalarAccumulator, + kScalarOperand, + kScalarToInt, + kScalarToInt2, + kScalarToString, + kScalarToString2, + kShiftLeftInt, + kShiftRightInt, // signed + kStringAccumulator, + kStringOperand, + kStringToInt, + kStringToScalar, + kStringToScalar2, + kStringTrack, + kSubtractInt, + kSubtractScalar, + kToBool, + kUnboxToken, + kUnboxToken2, + kXorInt, + kLastTypeOp + }; + + enum OpBias { + kNoBias, + kTowardsNumber = 0, + kTowardsString + }; + +protected: + + enum BraceStyle { + // kStructBrace, + kArrayBrace, + kFunctionBrace + }; + + enum AddTokenRegister { + kAccumulator, + kOperand + }; + + enum ResultIsBoolean { + kResultIsNotBoolean, + kResultIsBoolean + }; + + struct OperatorAttributes { + unsigned int fLeftType : 3; // SkOpType union, but only lower values + unsigned int fRightType : 3; // SkOpType union, but only lower values + OpBias fBias : 1; + ResultIsBoolean fResultIsBoolean : 1; + }; + + struct Branch { + Branch() { + } + + Branch(Op op, int depth, unsigned offset) : fOffset(offset), fOpStackDepth(depth), fOperator(op), + fPrimed(kIsNotPrimed), fDone(kIsNotDone) { + } + + enum Primed { + kIsNotPrimed, + kIsPrimed + }; + + enum Done { + kIsNotDone, + kIsDone, + }; + + unsigned fOffset : 16; // offset in generated stream where branch needs to go + int fOpStackDepth : 7; // depth when operator was found + Op fOperator : 6; // operand which generated branch + mutable Primed fPrimed : 1; // mark when next instruction generates branch + Done fDone : 1; // mark when branch is complete + void prime() { fPrimed = kIsPrimed; } + void resolve(SkDynamicMemoryWStream* , size_t offset); + }; + + static const OperatorAttributes gOpAttributes[]; + static const signed char gPrecedence[]; + static const TypeOp gTokens[]; + void addToken(TypeOp ); + void addTokenConst(SkScriptValue2* , AddTokenRegister , SkOperand2::OpType , TypeOp ); + void addTokenInt(int ); + void addTokenScalar(SkScalar ); + void addTokenString(const SkString& ); + void addTokenValue(const SkScriptValue2& , AddTokenRegister ); + int arithmeticOp(char ch, char nextChar, bool lastPush); + bool convertParams(SkTDArray<SkScriptValue2>* , + const SkOperand2::OpType* paramTypes, int paramTypeCount); + void convertToString(SkOperand2* operand, SkOperand2::OpType type) { + SkScriptValue2 scriptValue; + scriptValue.fOperand = *operand; + scriptValue.fType = type; + convertTo(SkOperand2::kString, &scriptValue); + *operand = scriptValue.fOperand; + } + bool evaluateDot(const char*& script); + bool evaluateDotParam(const char*& script, const char* field, size_t fieldLength); + bool functionParams(const char** scriptPtr, SkTDArray<SkScriptValue2>* params); + size_t getTokenOffset(); + SkOperand2::OpType getUnboxType(SkOperand2 scriptValue); + bool handleArrayIndexer(const char** scriptPtr); + bool handleFunction(const char** scriptPtr); + bool handleMember(const char* field, size_t len, void* object); + bool handleMemberFunction(const char* field, size_t len, void* object, + SkTDArray<SkScriptValue2>* params); + bool handleProperty(); + bool handleUnbox(SkScriptValue2* scriptValue); + bool innerScript(const char** scriptPtr, SkScriptValue2* value); + int logicalOp(char ch, char nextChar); + void processLogicalOp(Op op); + bool processOp(); + void resolveBranch(Branch& ); +// void setAnimateMaker(SkAnimateMaker* maker) { fMaker = maker; } + SkDynamicMemoryWStream fStream; + SkDynamicMemoryWStream* fActiveStream; + SkTDStack<BraceStyle> fBraceStack; // curly, square, function paren + SkTDStack<Branch> fBranchStack; // logical operators, slot to store forward branch + SkLongArray(SkScriptCallBack*) fCallBackArray; + SkTDStack<Op> fOpStack; + SkTDStack<SkScriptValue2> fValueStack; +// SkAnimateMaker* fMaker; + SkLongArray(SkOpArray*) fTrackArray; + SkTDStringArray fTrackString; + const char* fToken; // one-deep stack + size_t fTokenLength; + SkOperand2::OpType fReturnType; + Error fError; + SkOperand2::OpType fAccumulatorType; // tracking for code generation + SkBool fBranchPopAllowed; + SkBool fConstExpression; + SkBool fOperandInUse; +private: +#ifdef SK_DEBUG +public: + void decompile(const unsigned char* , size_t ); + static void UnitTest(); + static void ValidateDecompileTable(); +#endif +}; + +#ifdef SK_DEBUG + +struct SkScriptNAnswer2 { + const char* fScript; + SkOperand2::OpType fType; + S32 fIntAnswer; + SkScalar fScalarAnswer; + const char* fStringAnswer; +}; + +#endif + + +#endif // SkScript2_DEFINED + diff --git a/libs/graphics/animator/SkScriptCallBack.h b/libs/graphics/animator/SkScriptCallBack.h new file mode 100755 index 0000000000..4b2510590e --- /dev/null +++ b/libs/graphics/animator/SkScriptCallBack.h @@ -0,0 +1,58 @@ +#ifndef SkScriptCallBack_DEFINED
+#define SkScriptCallBack_DEFINED
+
+#include "SkOperand2.h"
+#include "SkTDArray_Experimental.h"
+
+class SkScriptCallBack {
+public:
+ enum Type {
+ kBox,
+ kFunction,
+ kMember,
+ kMemberFunction,
+ kProperty,
+ kUnbox
+ };
+
+ virtual bool getReference(const char* , size_t len, SkScriptValue2* result) { return false; }
+ virtual SkOperand2::OpType getReturnType(size_t ref, SkOperand2*) {
+ return SkOperand2::kS32; }
+ virtual Type getType() const = 0;
+};
+
+class SkScriptCallBackConvert : public SkScriptCallBack {
+public:
+ virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) = 0;
+};
+
+class SkScriptCallBackFunction : public SkScriptCallBack {
+public:
+ virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) = 0;
+ virtual Type getType() const { return kFunction; }
+ virtual bool invoke(size_t ref, SkOpArray* params, SkOperand2* value) = 0;
+};
+
+class SkScriptCallBackMember: public SkScriptCallBack {
+public:
+ bool getMemberReference(const char* , size_t len, void* object, SkScriptValue2* ref);
+ virtual Type getType() const { return kMember; }
+ virtual bool invoke(size_t ref, void* object, SkOperand2* value) = 0;
+};
+
+class SkScriptCallBackMemberFunction : public SkScriptCallBack {
+public:
+ bool getMemberReference(const char* , size_t len, void* object, SkScriptValue2* ref);
+ virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) = 0;
+ virtual Type getType() const { return kMemberFunction; }
+ virtual bool invoke(size_t ref, void* object, SkOpArray* params, SkOperand2* value) = 0;
+};
+
+class SkScriptCallBackProperty : public SkScriptCallBack {
+public:
+ virtual bool getConstValue(const char* name, size_t len, SkOperand2* value) { return false; }
+ virtual bool getResult(size_t ref, SkOperand2* answer) { return false; }
+ virtual Type getType() const { return kProperty; }
+};
+
+#endif // SkScriptCallBack_DEFINED
diff --git a/libs/graphics/animator/SkScriptDecompile.cpp b/libs/graphics/animator/SkScriptDecompile.cpp new file mode 100644 index 0000000000..a9f25b7ea9 --- /dev/null +++ b/libs/graphics/animator/SkScriptDecompile.cpp @@ -0,0 +1,204 @@ +#include "SkScript2.h" + +#ifdef SK_DEBUG + +#define TypeOpName(op) {SkScriptEngine2::op, #op } + +static const struct OpName { + SkScriptEngine2::TypeOp fOp; + const char* fName; +} gOpNames[] = { + TypeOpName(kNop), // should never get generated + TypeOpName(kAccumulatorPop), + TypeOpName(kAccumulatorPush), + TypeOpName(kAddInt), + TypeOpName(kAddScalar), + TypeOpName(kAddString), // string concat + TypeOpName(kArrayIndex), + TypeOpName(kArrayParam), + TypeOpName(kArrayToken), + TypeOpName(kBitAndInt), + TypeOpName(kBitNotInt), + TypeOpName(kBitOrInt), + TypeOpName(kBoxToken), + TypeOpName(kCallback), + TypeOpName(kDivideInt), + TypeOpName(kDivideScalar), + TypeOpName(kDotOperator), + TypeOpName(kElseOp), + TypeOpName(kEnd), + TypeOpName(kEqualInt), + TypeOpName(kEqualScalar), + TypeOpName(kEqualString), + TypeOpName(kFunctionCall), + TypeOpName(kFlipOpsOp), + TypeOpName(kFunctionToken), + TypeOpName(kGreaterEqualInt), + TypeOpName(kGreaterEqualScalar), + TypeOpName(kGreaterEqualString), + TypeOpName(kIfOp), + TypeOpName(kIntToScalar), + TypeOpName(kIntToScalar2), + TypeOpName(kIntToString), + TypeOpName(kIntToString2), + TypeOpName(kIntegerAccumulator), + TypeOpName(kIntegerOperand), + TypeOpName(kLogicalAndInt), + TypeOpName(kLogicalNotInt), + TypeOpName(kLogicalOrInt), + TypeOpName(kMemberOp), + TypeOpName(kMinusInt), + TypeOpName(kMinusScalar), + TypeOpName(kModuloInt), + TypeOpName(kModuloScalar), + TypeOpName(kMultiplyInt), + TypeOpName(kMultiplyScalar), + TypeOpName(kPropertyOp), + TypeOpName(kScalarAccumulator), + TypeOpName(kScalarOperand), + TypeOpName(kScalarToInt), + TypeOpName(kScalarToInt2), + TypeOpName(kScalarToString), + TypeOpName(kScalarToString2), + TypeOpName(kShiftLeftInt), + TypeOpName(kShiftRightInt), // signed + TypeOpName(kStringAccumulator), + TypeOpName(kStringOperand), + TypeOpName(kStringToInt), + TypeOpName(kStringToScalar), + TypeOpName(kStringToScalar2), + TypeOpName(kStringTrack), + TypeOpName(kSubtractInt), + TypeOpName(kSubtractScalar), + TypeOpName(kToBool), + TypeOpName(kUnboxToken), + TypeOpName(kUnboxToken2), + TypeOpName(kXorInt) +}; + +static size_t gOpNamesSize = sizeof(gOpNames) / sizeof(gOpNames[0]); + +#define OperandName(op) {SkOperand2::op, #op } + +static const struct OperName { + SkOperand2::OpType fType; + const char* fName; +} gOperandNames[] = { + OperandName(kNoType), + OperandName(kS32), + OperandName(kScalar), + OperandName(kString), + OperandName(kArray), + OperandName(kObject) +}; + +static size_t gOperandNamesSize = sizeof(gOperandNames) / sizeof(gOperandNames[0]); + +// check to see that there are no missing or duplicate entries +void SkScriptEngine2::ValidateDecompileTable() { + SkScriptEngine2::TypeOp op = SkScriptEngine2::kNop; + int index; + for (index = 0; index < gOpNamesSize; index++) { + SkASSERT(gOpNames[index].fOp == op); + op = (SkScriptEngine2::TypeOp) (op + 1); + } + index = 0; + SkOperand2::OpType type = SkOperand2::kNoType; + SkASSERT(gOperandNames[index].fType == type); + for (; index < gOperandNamesSize - 1; ) { + type = (SkOperand2::OpType) (1 << index); + SkASSERT(gOperandNames[++index].fType == type); + } +} + +void SkScriptEngine2::decompile(const unsigned char* start, size_t length) { + SkASSERT(length > 0); + const unsigned char* opCode = start; + do { + SkASSERT(opCode - start < length); + SkScriptEngine2::TypeOp op = (SkScriptEngine2::TypeOp) *opCode++; + SkASSERT(op < gOpNamesSize); + SkDebugf("%d: %s", opCode - start - 1, gOpNames[op].fName); + switch (op) { + case SkScriptEngine2::kCallback: { + int index; + memcpy(&index, opCode, sizeof(index)); + opCode += sizeof(index); + SkDebugf(" index: %d", index); + } break; + case SkScriptEngine2::kFunctionCall: + case SkScriptEngine2::kMemberOp: + case SkScriptEngine2::kPropertyOp: { + size_t ref; + memcpy(&ref, opCode, sizeof(ref)); + opCode += sizeof(ref); + SkDebugf(" ref: %d", ref); + } break; + case SkScriptEngine2::kIntegerAccumulator: + case SkScriptEngine2::kIntegerOperand: { + S32 integer; + memcpy(&integer, opCode, sizeof(integer)); + opCode += sizeof(S32); + SkDebugf(" integer: %d", integer); + } break; + case SkScriptEngine2::kScalarAccumulator: + case SkScriptEngine2::kScalarOperand: { + SkScalar scalar; + memcpy(&scalar, opCode, sizeof(scalar)); + opCode += sizeof(SkScalar); +#ifdef SK_CAN_USE_FLOAT + SkDebugf(" scalar: %g", SkScalarToFloat(scalar)); +#else + SkDebugf(" scalar: %x", scalar); +#endif + } break; + case SkScriptEngine2::kStringAccumulator: + case SkScriptEngine2::kStringOperand: { + int size; + SkString* strPtr = new SkString(); + memcpy(&size, opCode, sizeof(size)); + opCode += sizeof(size); + strPtr->set((char*) opCode, size); + opCode += size; + SkDebugf(" string: %s", strPtr->c_str()); + delete strPtr; + } break; + case SkScriptEngine2::kBoxToken: { + SkOperand2::OpType type; + memcpy(&type, opCode, sizeof(type)); + opCode += sizeof(type); + int index = 0; + if (type == 0) + SkDebugf(" type: %s", gOperandNames[index].fName); + else { + while (type != 0) { + SkASSERT(index + 1 < gOperandNamesSize); + if (type & (1 << index)) { + type = (SkOperand2::OpType) (type & ~(1 << index)); + SkDebugf(" type: %s", gOperandNames[index + 1].fName); + } + index++; + } + } + } break; + case SkScriptEngine2::kIfOp: + case SkScriptEngine2::kLogicalAndInt: + case SkScriptEngine2::kElseOp: + case SkScriptEngine2::kLogicalOrInt: { + int size; + memcpy(&size, opCode, sizeof(size)); + opCode += sizeof(size); + SkDebugf(" offset (address): %d (%d)", size, opCode - start + size); + } break; + case SkScriptEngine2::kEnd: + goto done; + case SkScriptEngine2::kNop: + SkASSERT(0); + } + SkDebugf("\n"); + } while (true); +done: + SkDebugf("\n"); +} + +#endif diff --git a/libs/graphics/animator/SkScriptRuntime.cpp b/libs/graphics/animator/SkScriptRuntime.cpp new file mode 100755 index 0000000000..1851b00fd4 --- /dev/null +++ b/libs/graphics/animator/SkScriptRuntime.cpp @@ -0,0 +1,342 @@ +#include "SkScriptRuntime.h" +#include "SkScript2.h" +#include "SkParse.h" +#include "SkScriptCallBack.h" +#include "SkString.h" +#include "SkOpArray.h" + +// script tokenizer + +// turn text into token string +// turn number literals into inline UTF8-style values +// process operators to turn standard notation into stack notation + +// defer processing until the tokens can all be resolved +// then, turn token strings into indices into the appropriate tables / dictionaries + +// consider: const evaluation? + +// replace script string with script tokens preceeded by special value + +// need second version of script plugins that return private index of found value? + // then would need in script index of plugin, private index + +// encode brace stack push/pop as opcodes + +// should token script enocde type where possible? + +// current flow: + // strip whitespace + // if in array brace [ recurse, continue + // if token, handle function, or array, or property (continue) + // parse number, continue + // parse token, continue + // parse string literal, continue + // if dot operator, handle dot, continue + // if [ , handle array literal or accessor, continue + // if ), pop (if function, break) + // if ], pop ; if ',' break + // handle logical ops + // or, handle arithmetic ops + // loop + +// !!! things to do + // add separate processing loop to advance while suppressed + // or, include jump offset to skip suppressed code? + +SkScriptRuntime::~SkScriptRuntime() { + for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++) + delete *stringPtr; + for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++) + delete *arrayPtr; +} + +bool SkScriptRuntime::executeTokens(unsigned char* opCode) { + SkOperand2 operand[2]; // 1=accumulator and 2=operand + SkScriptEngine2::TypeOp op; + size_t ref; + int index, size; + int registerLoad; + SkScriptCallBack* callBack SK_INIT_TO_AVOID_WARNING; + do { + switch ((op = (SkScriptEngine2::TypeOp) *opCode++)) { + case SkScriptEngine2::kArrayToken: // create an array + operand[0].fArray = new SkOpArray(SkOperand2::kNoType /*fReturnType*/); + break; + case SkScriptEngine2::kArrayIndex: // array accessor + index = operand[1].fS32; + if (index >= operand[0].fArray->count()) { + fError = kArrayIndexOutOfBounds; + return false; + } + operand[0] = operand[0].fArray->begin()[index]; + break; + case SkScriptEngine2::kArrayParam: // array initializer, or function param + *operand[0].fArray->append() = operand[1]; + break; + case SkScriptEngine2::kCallback: + memcpy(&index, opCode, sizeof(index)); + opCode += sizeof(index); + callBack = fCallBackArray[index]; + break; + case SkScriptEngine2::kFunctionCall: { + memcpy(&ref, opCode, sizeof(ref)); + opCode += sizeof(ref); + SkScriptCallBackFunction* callBackFunction = (SkScriptCallBackFunction*) callBack; + if (callBackFunction->invoke(ref, operand[0].fArray, /* params */ + &operand[0] /* result */) == false) { + fError = kFunctionCallFailed; + return false; + } + } break; + case SkScriptEngine2::kMemberOp: { + memcpy(&ref, opCode, sizeof(ref)); + opCode += sizeof(ref); + SkScriptCallBackMember* callBackMember = (SkScriptCallBackMember*) callBack; + if (callBackMember->invoke(ref, operand[0].fObject, &operand[0]) == false) { + fError = kMemberOpFailed; + return false; + } + } break; + case SkScriptEngine2::kPropertyOp: { + memcpy(&ref, opCode, sizeof(ref)); + opCode += sizeof(ref); + SkScriptCallBackProperty* callBackProperty = (SkScriptCallBackProperty*) callBack; + if (callBackProperty->getResult(ref, &operand[0])== false) { + fError = kPropertyOpFailed; + return false; + } + } break; + case SkScriptEngine2::kAccumulatorPop: + fRunStack.pop(&operand[0]); + break; + case SkScriptEngine2::kAccumulatorPush: + *fRunStack.push() = operand[0]; + break; + case SkScriptEngine2::kIntegerAccumulator: + case SkScriptEngine2::kIntegerOperand: + registerLoad = op - SkScriptEngine2::kIntegerAccumulator; + memcpy(&operand[registerLoad].fS32, opCode, sizeof(S32)); + opCode += sizeof(S32); + break; + case SkScriptEngine2::kScalarAccumulator: + case SkScriptEngine2::kScalarOperand: + registerLoad = op - SkScriptEngine2::kScalarAccumulator; + memcpy(&operand[registerLoad].fScalar, opCode, sizeof(SkScalar)); + opCode += sizeof(SkScalar); + break; + case SkScriptEngine2::kStringAccumulator: + case SkScriptEngine2::kStringOperand: { + SkString* strPtr = new SkString(); + track(strPtr); + registerLoad = op - SkScriptEngine2::kStringAccumulator; + memcpy(&size, opCode, sizeof(size)); + opCode += sizeof(size); + strPtr->set((char*) opCode, size); + opCode += size; + operand[registerLoad].fString = strPtr; + } break; + case SkScriptEngine2::kStringTrack: // call after kObjectToValue + track(operand[0].fString); + break; + case SkScriptEngine2::kBoxToken: { + SkOperand2::OpType type; + memcpy(&type, opCode, sizeof(type)); + opCode += sizeof(type); + SkScriptCallBackConvert* callBackBox = (SkScriptCallBackConvert*) callBack; + if (callBackBox->convert(type, &operand[0]) == false) + return false; + } break; + case SkScriptEngine2::kUnboxToken: + case SkScriptEngine2::kUnboxToken2: { + SkScriptCallBackConvert* callBackUnbox = (SkScriptCallBackConvert*) callBack; + if (callBackUnbox->convert(SkOperand2::kObject, &operand[0]) == false) + return false; + } break; + case SkScriptEngine2::kIfOp: + case SkScriptEngine2::kLogicalAndInt: + memcpy(&size, opCode, sizeof(size)); + opCode += sizeof(size); + if (operand[0].fS32 == 0) + opCode += size; // skip to else (or end of if predicate) + break; + case SkScriptEngine2::kElseOp: + memcpy(&size, opCode, sizeof(size)); + opCode += sizeof(size); + opCode += size; // if true: after predicate, always skip to end of else + break; + case SkScriptEngine2::kLogicalOrInt: + memcpy(&size, opCode, sizeof(size)); + opCode += sizeof(size); + if (operand[0].fS32 != 0) + opCode += size; // skip to kToBool opcode after || predicate + break; + // arithmetic conversion ops + case SkScriptEngine2::kFlipOpsOp: + SkTSwap(operand[0], operand[1]); + break; + case SkScriptEngine2::kIntToString: + case SkScriptEngine2::kIntToString2: + case SkScriptEngine2::kScalarToString: + case SkScriptEngine2::kScalarToString2:{ + SkString* strPtr = new SkString(); + track(strPtr); + if (op == SkScriptEngine2::kIntToString || op == SkScriptEngine2::kIntToString2) + strPtr->appendS32(operand[op - SkScriptEngine2::kIntToString].fS32); + else + strPtr->appendScalar(operand[op - SkScriptEngine2::kScalarToString].fScalar); + operand[0].fString = strPtr; + } break; + case SkScriptEngine2::kIntToScalar: + case SkScriptEngine2::kIntToScalar2: + operand[0].fScalar = SkScriptEngine2::IntToScalar(operand[op - SkScriptEngine2::kIntToScalar].fS32); + break; + case SkScriptEngine2::kStringToInt: + if (SkParse::FindS32(operand[0].fString->c_str(), &operand[0].fS32) == false) + return false; + break; + case SkScriptEngine2::kStringToScalar: + case SkScriptEngine2::kStringToScalar2: + if (SkParse::FindScalar(operand[0].fString->c_str(), + &operand[op - SkScriptEngine2::kStringToScalar].fScalar) == false) + return false; + break; + case SkScriptEngine2::kScalarToInt: + operand[0].fS32 = SkScalarFloor(operand[0].fScalar); + break; + // arithmetic ops + case SkScriptEngine2::kAddInt: + operand[0].fS32 += operand[1].fS32; + break; + case SkScriptEngine2::kAddScalar: + operand[0].fScalar += operand[1].fScalar; + break; + case SkScriptEngine2::kAddString: +// if (fTrackString.find(operand[1].fString) < 0) { +// operand[1].fString = SkNEW_ARGS(SkString, (*operand[1].fString)); +// track(operand[1].fString); +// } + operand[0].fString->append(*operand[1].fString); + break; + case SkScriptEngine2::kBitAndInt: + operand[0].fS32 &= operand[1].fS32; + break; + case SkScriptEngine2::kBitNotInt: + operand[0].fS32 = ~operand[0].fS32; + break; + case SkScriptEngine2::kBitOrInt: + operand[0].fS32 |= operand[1].fS32; + break; + case SkScriptEngine2::kDivideInt: + SkASSERT(operand[1].fS32 != 0); + if (operand[1].fS32 == 0) + operand[0].fS32 = operand[0].fS32 == 0 ? SK_NaN32 : + operand[0].fS32 > 0 ? SK_MaxS32 : -SK_MaxS32; + else + if (operand[1].fS32 != 0) // throw error on divide by zero? + operand[0].fS32 /= operand[1].fS32; + break; + case SkScriptEngine2::kDivideScalar: + if (operand[1].fScalar == 0) + operand[0].fScalar = operand[0].fScalar == 0 ? SK_ScalarNaN : + operand[0].fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax; + else + operand[0].fScalar = SkScalarDiv(operand[0].fScalar, operand[1].fScalar); + break; + case SkScriptEngine2::kEqualInt: + operand[0].fS32 = operand[0].fS32 == operand[1].fS32; + break; + case SkScriptEngine2::kEqualScalar: + operand[0].fS32 = operand[0].fScalar == operand[1].fScalar; + break; + case SkScriptEngine2::kEqualString: + operand[0].fS32 = *operand[0].fString == *operand[1].fString; + break; + case SkScriptEngine2::kGreaterEqualInt: + operand[0].fS32 = operand[0].fS32 >= operand[1].fS32; + break; + case SkScriptEngine2::kGreaterEqualScalar: + operand[0].fS32 = operand[0].fScalar >= operand[1].fScalar; + break; + case SkScriptEngine2::kGreaterEqualString: + operand[0].fS32 = strcmp(operand[0].fString->c_str(), operand[1].fString->c_str()) >= 0; + break; + case SkScriptEngine2::kToBool: + operand[0].fS32 = !! operand[0].fS32; + break; + case SkScriptEngine2::kLogicalNotInt: + operand[0].fS32 = ! operand[0].fS32; + break; + case SkScriptEngine2::kMinusInt: + operand[0].fS32 = -operand[0].fS32; + break; + case SkScriptEngine2::kMinusScalar: + operand[0].fScalar = -operand[0].fScalar; + break; + case SkScriptEngine2::kModuloInt: + operand[0].fS32 %= operand[1].fS32; + break; + case SkScriptEngine2::kModuloScalar: + operand[0].fScalar = SkScalarMod(operand[0].fScalar, operand[1].fScalar); + break; + case SkScriptEngine2::kMultiplyInt: + operand[0].fS32 *= operand[1].fS32; + break; + case SkScriptEngine2::kMultiplyScalar: + operand[0].fScalar = SkScalarMul(operand[0].fScalar, operand[1].fScalar); + break; + case SkScriptEngine2::kShiftLeftInt: + operand[0].fS32 <<= operand[1].fS32; + break; + case SkScriptEngine2::kShiftRightInt: + operand[0].fS32 >>= operand[1].fS32; + break; + case SkScriptEngine2::kSubtractInt: + operand[0].fS32 -= operand[1].fS32; + break; + case SkScriptEngine2::kSubtractScalar: + operand[0].fScalar -= operand[1].fScalar; + break; + case SkScriptEngine2::kXorInt: + operand[0].fS32 ^= operand[1].fS32; + break; + case SkScriptEngine2::kEnd: + goto done; + case SkScriptEngine2::kNop: + SkASSERT(0); + } + } while (true); +done: + fRunStack.push(operand[0]); + return true; +} + +bool SkScriptRuntime::getResult(SkOperand2* result) { + if (fRunStack.count() == 0) + return false; + fRunStack.pop(result); + return true; +} + +void SkScriptRuntime::track(SkOpArray* array) { + SkASSERT(fTrackArray.find(array) < 0); + *fTrackArray.append() = array; +} + +void SkScriptRuntime::track(SkString* string) { + SkASSERT(fTrackString.find(string) < 0); + *fTrackString.append() = string; +} + +void SkScriptRuntime::untrack(SkOpArray* array) { + int index = fTrackArray.find(array); + SkASSERT(index >= 0); + fTrackArray.begin()[index] = nil; +} + +void SkScriptRuntime::untrack(SkString* string) { + int index = fTrackString.find(string); + SkASSERT(index >= 0); + fTrackString.begin()[index] = nil; +} + diff --git a/libs/graphics/animator/SkScriptRuntime.h b/libs/graphics/animator/SkScriptRuntime.h new file mode 100755 index 0000000000..75bf7db97d --- /dev/null +++ b/libs/graphics/animator/SkScriptRuntime.h @@ -0,0 +1,43 @@ +#ifndef SkScriptRuntime_DEFINED
+#define SkScriptRuntime_DEFINED
+
+#include "SkOperand2.h"
+#include "SkTDArray_Experimental.h"
+#include "SkTDStack.h"
+
+class SkScriptCallBack;
+
+typedef SkLongArray(SkString*) SkTDStringArray;
+typedef SkLongArray(SkScriptCallBack*) SkTDScriptCallBackArray;
+
+class SkScriptRuntime {
+public:
+ enum SkError {
+ kNoError,
+ kArrayIndexOutOfBounds,
+ kCouldNotFindReferencedID,
+ kFunctionCallFailed,
+ kMemberOpFailed,
+ kPropertyOpFailed
+ };
+
+ SkScriptRuntime(SkTDScriptCallBackArray& callBackArray) : fCallBackArray(callBackArray)
+ { }
+ ~SkScriptRuntime();
+ bool executeTokens(unsigned char* opCode);
+ bool getResult(SkOperand2* result);
+ void untrack(SkOpArray* array);
+ void untrack(SkString* string);
+private:
+ void track(SkOpArray* array);
+ void track(SkString* string);
+ SkTDScriptCallBackArray& fCallBackArray;
+ SkError fError;
+ SkTDStack<SkOperand2> fRunStack;
+ SkLongArray(SkOpArray*) fTrackArray;
+ SkTDStringArray fTrackString;
+ // illegal
+ SkScriptRuntime& operator=(const SkScriptRuntime&);
+};
+
+#endif // SkScriptRuntime_DEFINED
\ No newline at end of file diff --git a/libs/graphics/animator/SkScriptTokenizer.cpp b/libs/graphics/animator/SkScriptTokenizer.cpp new file mode 100755 index 0000000000..e8548073e4 --- /dev/null +++ b/libs/graphics/animator/SkScriptTokenizer.cpp @@ -0,0 +1,1513 @@ +#include "SkScript2.h" +#include "SkMath.h" +#include "SkParse.h" +#include "SkScriptCallBack.h" +#include "SkScriptRuntime.h" +#include "SkString.h" +#include "SkOpArray.h" + +const SkScriptEngine2::OperatorAttributes SkScriptEngine2::gOpAttributes[] = { +{ SkOperand2::kNoType }, +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsString }, // kAdd +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kBitAnd +{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias }, // kBitNot +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kBitOr +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kDivide +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar |SkOperand2:: kString), kTowardsNumber, + kResultIsBoolean }, // kEqual +{ SkOperand2::kS32 }, // kFlipOps +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsNumber, + kResultIsBoolean }, // kGreaterEqual +{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias }, // kLogicalAnd (really, ToBool) +{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias }, // kLogicalNot +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kLogicalOr +{ SkOperand2::kNoType, SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kMinus +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), + SkOperand2::OpType(SkOperand2::kS32 |SkOperand2:: kScalar), kNoBias }, // kModulo +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kMultiply +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kShiftLeft +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kShiftRight +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kSubtract +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias } // kXor +}; + +#define kBracketPrecedence 16 +#define kIfElsePrecedence 15 + +const signed char SkScriptEngine2::gPrecedence[] = { + 17, // kUnassigned, + 6, // kAdd, + 10, // kBitAnd, + 4, // kBitNot, + 12, // kBitOr, + 5, // kDivide, + 9, // kEqual, + -1, // kFlipOps, + 8, // kGreaterEqual, + 13, // kLogicalAnd, + 4, // kLogicalNot, + 14, // kLogicalOr, + 4, // kMinus, + 5, // kModulo, + 5, // kMultiply, + 7, // kShiftLeft, + 7, // kShiftRight, // signed + 6, // kSubtract, + 11, // kXor + kBracketPrecedence, // kArrayOp + kIfElsePrecedence, // kElse + kIfElsePrecedence, // kIf + kBracketPrecedence, // kParen +}; + +const SkScriptEngine2::TypeOp SkScriptEngine2::gTokens[] = { + kNop, // unassigned + kAddInt, // kAdd, + kBitAndInt, // kBitAnd, + kBitNotInt, // kBitNot, + kBitOrInt, // kBitOr, + kDivideInt, // kDivide, + kEqualInt, // kEqual, + kFlipOpsOp, // kFlipOps, + kGreaterEqualInt, // kGreaterEqual, + kLogicalAndInt, // kLogicalAnd, + kLogicalNotInt, // kLogicalNot, + kLogicalOrInt, // kLogicalOr, + kMinusInt, // kMinus, + kModuloInt, // kModulo, + kMultiplyInt, // kMultiply, + kShiftLeftInt, // kShiftLeft, + kShiftRightInt, // kShiftRight, // signed + kSubtractInt, // kSubtract, + kXorInt // kXor +}; + +static inline bool is_between(int c, int min, int max) +{ + return (unsigned)(c - min) <= (unsigned)(max - min); +} + +static inline bool is_ws(int c) +{ + return is_between(c, 1, 32); +} + +static int token_length(const char* start) { + char ch = start[0]; + if (! is_between(ch, 'a' , 'z') && ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$') + return -1; + int length = 0; + do + ch = start[++length]; + while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') || + ch == '_' || ch == '$'); + return length; +} + +SkScriptEngine2::SkScriptEngine2(SkOperand2::OpType returnType) : fActiveStream(&fStream), +fTokenLength(0), fReturnType(returnType), fError(kNoError), +fAccumulatorType(SkOperand2::kNoType), +fBranchPopAllowed(true), fConstExpression(true), fOperandInUse(false) +{ + Branch branch(kUnassigned, 0, 0); + fBranchStack.push(branch); + *fOpStack.push() = (Op) kParen; +} + +SkScriptEngine2::~SkScriptEngine2() { + for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++) + delete *stringPtr; + for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++) + delete *arrayPtr; +} + +void SkScriptEngine2::addToken(SkScriptEngine2::TypeOp op) { + int limit = fBranchStack.count() - 1; + for (int index = 0; index < limit; index++) { + Branch& branch = fBranchStack.index(index); + if (branch.fPrimed == Branch::kIsPrimed) + resolveBranch(branch); + } + if (fBranchPopAllowed) { + while (fBranchStack.top().fDone == Branch::kIsDone) + fBranchStack.pop(); + } + unsigned char charOp = (unsigned char) op; + fActiveStream->write(&charOp, sizeof(charOp)); +} + +void SkScriptEngine2::addTokenConst(SkScriptValue2* value, AddTokenRegister reg, + SkOperand2::OpType toType, SkScriptEngine2::TypeOp op) { + if (value->fIsConstant == SkScriptValue2::kConstant && convertTo(toType, value)) + return; + addTokenValue(*value, reg); + addToken(op); + value->fIsWritten = SkScriptValue2::kWritten; + value->fType = toType; +} + +void SkScriptEngine2::addTokenInt(int integer) { + fActiveStream->write(&integer, sizeof(integer)); +} + +void SkScriptEngine2::addTokenScalar(SkScalar scalar) { + fActiveStream->write(&scalar, sizeof(scalar)); +} + +void SkScriptEngine2::addTokenString(const SkString& string) { + int size = string.size(); + addTokenInt(size); + fActiveStream->write(string.c_str(), size); +} + +void SkScriptEngine2::addTokenValue(const SkScriptValue2& value, AddTokenRegister reg) { + if (value.isConstant() == false) { + if (reg == kAccumulator) { + if (fAccumulatorType == SkOperand2::kNoType) + addToken(kAccumulatorPop); + } else { + ; // !!! incomplete? + } + return; + } + if (reg == kAccumulator && fAccumulatorType != SkOperand2::kNoType) + addToken(kAccumulatorPush); + switch (value.fType) { + case SkOperand2::kS32: + addToken(reg == kAccumulator ? kIntegerAccumulator : kIntegerOperand); + addTokenInt(value.fOperand.fS32); + if (reg == kAccumulator) + fAccumulatorType = SkOperand2::kS32; + else + fOperandInUse = true; + break; + case SkOperand2::kScalar: + addToken(reg == kAccumulator ? kScalarAccumulator : kScalarOperand); + addTokenScalar(value.fOperand.fScalar); + if (reg == kAccumulator) + fAccumulatorType = SkOperand2::kScalar; + else + fOperandInUse = true; + break; + case SkOperand2::kString: + addToken(reg == kAccumulator ? kStringAccumulator : kStringOperand); + addTokenString(*value.fOperand.fString); + if (reg == kAccumulator) + fAccumulatorType = SkOperand2::kString; + else + fOperandInUse = true; + break; + default: + SkASSERT(0); //!!! not implemented yet + } +} + +int SkScriptEngine2::arithmeticOp(char ch, char nextChar, bool lastPush) { + Op op = kUnassigned; + bool reverseOperands = false; + bool negateResult = false; + int advance = 1; + switch (ch) { + case '+': + // !!! ignoring unary plus as implemented here has the side effect of + // suppressing errors like +"hi" + if (lastPush == false) // unary plus, don't push an operator + goto returnAdv; + op = kAdd; + break; + case '-': + op = lastPush ? kSubtract : kMinus; + break; + case '*': + op = kMultiply; + break; + case '/': + op = kDivide; + break; + case '>': + if (nextChar == '>') { + op = kShiftRight; + goto twoChar; + } + op = kGreaterEqual; + if (nextChar == '=') + goto twoChar; + reverseOperands = negateResult = true; + break; + case '<': + if (nextChar == '<') { + op = kShiftLeft; + goto twoChar; + } + op = kGreaterEqual; + reverseOperands = nextChar == '='; + negateResult = ! reverseOperands; + advance += reverseOperands; + break; + case '=': + if (nextChar == '=') { + op = kEqual; + goto twoChar; + } + break; + case '!': + if (nextChar == '=') { + op = kEqual; + negateResult = true; +twoChar: + advance++; + break; + } + op = kLogicalNot; + break; + case '?': + op =(Op) kIf; + break; + case ':': + op = (Op) kElse; + break; + case '^': + op = kXor; + break; + case '(': + *fOpStack.push() = (Op) kParen; + goto returnAdv; + case '&': + SkASSERT(nextChar != '&'); + op = kBitAnd; + break; + case '|': + SkASSERT(nextChar != '|'); + op = kBitOr; + break; + case '%': + op = kModulo; + break; + case '~': + op = kBitNot; + break; + } + if (op == kUnassigned) + return 0; + signed char precedence = gPrecedence[op]; + do { + int idx = 0; + Op compare; + do { + compare = fOpStack.index(idx); + if ((compare & kArtificialOp) == 0) + break; + idx++; + } while (true); + signed char topPrecedence = gPrecedence[compare]; + SkASSERT(topPrecedence != -1); + if (topPrecedence > precedence || topPrecedence == precedence && + gOpAttributes[op].fLeftType == SkOperand2::kNoType) { + break; + } + processOp(); + } while (true); + if (negateResult) + *fOpStack.push() = (Op) (kLogicalNot | kArtificialOp); + fOpStack.push(op); + if (reverseOperands) + *fOpStack.push() = (Op) (kFlipOps | kArtificialOp); +returnAdv: + return advance; +} + +bool SkScriptEngine2::convertParams(SkTDArray<SkScriptValue2>* params, + const SkOperand2::OpType* paramTypes, int paramCount) { + int count = params->count(); + if (count > paramCount) { + SkASSERT(0); + return false; // too many parameters passed + } + for (int index = 0; index < count; index++) + convertTo(paramTypes[index], &(*params)[index]); + return true; +} + +bool SkScriptEngine2::convertTo(SkOperand2::OpType toType, SkScriptValue2* value ) { + SkOperand2::OpType type = value->fType; + if (type == toType) + return true; + if (type == SkOperand2::kObject) { + if (handleUnbox(value) == false) + return false; + return convertTo(toType, value); + } + return ConvertTo(this, toType, value); +} + +bool SkScriptEngine2::evaluateDot(const char*& script) { + size_t fieldLength = token_length(++script); // skip dot + SkASSERT(fieldLength > 0); // !!! add error handling + const char* field = script; + script += fieldLength; + bool success = handleProperty(); + if (success == false) { + fError = kCouldNotFindReferencedID; + goto error; + } + return evaluateDotParam(script, field, fieldLength); +error: + return false; +} + +bool SkScriptEngine2::evaluateDotParam(const char*& script, const char* field, size_t fieldLength) { + SkScriptValue2& top = fValueStack.top(); + if (top.fType != SkOperand2::kObject) + return false; + void* object = top.fOperand.fObject; + fValueStack.pop(); + char ch; // see if it is a simple member or a function + while (is_ws(ch = script[0])) + script++; + bool success = true; + if (ch != '(') + success = handleMember(field, fieldLength, object); + else { + SkTDArray<SkScriptValue2> params; + *fBraceStack.push() = kFunctionBrace; + success = functionParams(&script, ¶ms); + if (success) + success = handleMemberFunction(field, fieldLength, object, ¶ms); + } + return success; +} + +bool SkScriptEngine2::evaluateScript(const char** scriptPtr, SkScriptValue2* value) { + // fArrayOffset = 0; // no support for structures for now + bool success; + const char* inner; + if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) { + *scriptPtr += sizeof("#script:") - 1; + if (fReturnType == SkOperand2::kNoType || fReturnType == SkOperand2::kString) { + success = innerScript(scriptPtr, value); + SkASSERT(success); + inner = value->fOperand.fString->c_str(); + scriptPtr = &inner; + } + } + success = innerScript(scriptPtr, value); + const char* script = *scriptPtr; + char ch; + while (is_ws(ch = script[0])) + script++; + if (ch != '\0') { + // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]" + return false; + } + return success; +} + +void SkScriptEngine2::forget(SkOpArray* array) { + if (array->getType() == SkOperand2::kString) { + for (int index = 0; index < array->count(); index++) { + SkString* string = (*array)[index].fString; + int found = fTrackString.find(string); + if (found >= 0) + fTrackString.remove(found); + } + return; + } + if (array->getType() == SkOperand2::kArray) { + for (int index = 0; index < array->count(); index++) { + SkOpArray* child = (*array)[index].fArray; + forget(child); // forgets children of child + int found = fTrackArray.find(child); + if (found >= 0) + fTrackArray.remove(found); + } + } +} + +bool SkScriptEngine2::functionParams(const char** scriptPtr, SkTDArray<SkScriptValue2>* params) { + (*scriptPtr)++; // skip open paren + *fOpStack.push() = (Op) kParen; + *fBraceStack.push() = kFunctionBrace; + do { + SkScriptValue2 value; + bool success = innerScript(scriptPtr, &value); + SkASSERT(success); + if (success == false) + return false; + *params->append() = value; + } while ((*scriptPtr)[-1] == ','); + fBraceStack.pop(); + fOpStack.pop(); // pop paren + (*scriptPtr)++; // advance beyond close paren + return true; +} + +size_t SkScriptEngine2::getTokenOffset() { + return fActiveStream->getOffset(); +} + +SkOperand2::OpType SkScriptEngine2::getUnboxType(SkOperand2 scriptValue) { + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { + if ((*callBack)->getType() != SkScriptCallBack::kUnbox) + continue; + return (*callBack)->getReturnType(0, &scriptValue); + } + return SkOperand2::kObject; +} + +bool SkScriptEngine2::innerScript(const char** scriptPtr, SkScriptValue2* value) { + const char* script = *scriptPtr; + char ch; + bool lastPush = false; + bool success = true; + int opBalance = fOpStack.count(); + int baseBrace = fBraceStack.count(); + int branchBalance = fBranchStack.count(); + while ((ch = script[0]) != '\0') { + if (is_ws(ch)) { + script++; + continue; + } + SkScriptValue2 operand; + const char* dotCheck; + if (fBraceStack.count() > baseBrace) { + if (fBraceStack.top() == kArrayBrace) { + SkScriptValue2 tokenValue; + success = innerScript(&script, &tokenValue); // terminate and return on comma, close brace + SkASSERT(success); + { + SkOperand2::OpType type = fReturnType; + if (fReturnType == SkOperand2::kNoType) { + // !!! short sighted; in the future, allow each returned array component to carry + // its own type, and let caller do any needed conversions + if (value->fOperand.fArray->count() == 0) + value->fOperand.fArray->setType(type = tokenValue.fType); + else + type = value->fOperand.fArray->getType(); + } + if (tokenValue.fType != type) + convertTo(type, &tokenValue); + *value->fOperand.fArray->append() = tokenValue.fOperand; + } + lastPush = false; + continue; + } else + SkASSERT(token_length(script) > 0); + } + if (lastPush != false && fTokenLength > 0) { + if (ch == '(') { + *fBraceStack.push() = kFunctionBrace; + SkString functionName(fToken, fTokenLength); + + if (handleFunction(&script) == false) + return false; + lastPush = true; + continue; + } else if (ch == '[') { + if (handleProperty() == false) { + SkASSERT(0); + return false; + } + if (handleArrayIndexer(&script) == false) + return false; + lastPush = true; + continue; + } else if (ch != '.') { + if (handleProperty() == false) { + SkASSERT(0); + return false; + } + lastPush = true; + continue; + } + } + if (ch == '0' && (script[1] & ~0x20) == 'X') { + SkASSERT(lastPush == false); + script += 2; + script = SkParse::FindHex(script, (uint32_t*) &operand.fOperand.fS32); + SkASSERT(script); + goto intCommon; + } + if (lastPush == false && ch == '.') + goto scalarCommon; + if (ch >= '0' && ch <= '9') { + SkASSERT(lastPush == false); + dotCheck = SkParse::FindS32(script, &operand.fOperand.fS32); + if (dotCheck[0] != '.') { + script = dotCheck; +intCommon: + operand.fType = SkOperand2::kS32; + } else { +scalarCommon: + script = SkParse::FindScalar(script, &operand.fOperand.fScalar); + operand.fType = SkOperand2::kScalar; + } + operand.fIsConstant = SkScriptValue2::kConstant; + fValueStack.push(operand); + lastPush = true; + continue; + } + int length = token_length(script); + if (length > 0) { + SkASSERT(lastPush == false); + fToken = script; + fTokenLength = length; + script += length; + lastPush = true; + continue; + } + char startQuote = ch; + if (startQuote == '\'' || startQuote == '\"') { + SkASSERT(lastPush == false); + operand.fOperand.fString = new SkString(); + ++script; + const char* stringStart = script; + do { // measure string + if (script[0] == '\\') + ++script; + ++script; + SkASSERT(script[0]); // !!! throw an error + } while (script[0] != startQuote); + operand.fOperand.fString->set(stringStart, script - stringStart); + script = stringStart; + char* stringWrite = operand.fOperand.fString->writable_str(); + do { // copy string + if (script[0] == '\\') + ++script; + *stringWrite++ = script[0]; + ++script; + SkASSERT(script[0]); // !!! throw an error + } while (script[0] != startQuote); + ++script; + track(operand.fOperand.fString); + operand.fType = SkOperand2::kString; + operand.fIsConstant = SkScriptValue2::kConstant; + fValueStack.push(operand); + lastPush = true; + continue; + } + if (ch == '.') { + if (fTokenLength == 0) { + SkScriptValue2 scriptValue; + SkDEBUGCODE(scriptValue.fOperand.fObject = nil); + int tokenLength = token_length(++script); + const char* token = script; + script += tokenLength; + SkASSERT(fValueStack.count() > 0); // !!! add error handling + SkScriptValue2 top; + fValueStack.pop(&top); + + addTokenInt(top.fType); + addToken(kBoxToken); + top.fType = SkOperand2::kObject; + top.fIsConstant = SkScriptValue2::kVariable; + fConstExpression = false; + fValueStack.push(top); + success = evaluateDotParam(script, token, tokenLength); + SkASSERT(success); + lastPush = true; + continue; + } + // get next token, and evaluate immediately + success = evaluateDot(script); + if (success == false) { + // SkASSERT(0); + return false; + } + lastPush = true; + continue; + } + if (ch == '[') { + if (lastPush == false) { + script++; + *fBraceStack.push() = kArrayBrace; + operand.fOperand.fArray = value->fOperand.fArray = new SkOpArray(fReturnType); + track(value->fOperand.fArray); + + operand.fType = SkOperand2::kArray; + operand.fIsConstant = SkScriptValue2::kVariable; + fValueStack.push(operand); + continue; + } + if (handleArrayIndexer(&script) == false) + return false; + lastPush = true; + continue; + } +#if 0 // structs not supported for now + if (ch == '{') { + if (lastPush == false) { + script++; + *fBraceStack.push() = kStructBrace; + operand.fS32 = 0; + *fTypeStack.push() = (SkOpType) kStruct; + fOperandStack.push(operand); + continue; + } + SkASSERT(0); // braces in other contexts aren't supported yet + } +#endif + if (ch == ')' && fBraceStack.count() > 0) { + BraceStyle braceStyle = fBraceStack.top(); + if (braceStyle == kFunctionBrace) { + fBraceStack.pop(); + break; + } + } + if (ch == ',' || ch == ']') { + if (ch != ',') { + BraceStyle match; + fBraceStack.pop(&match); + SkASSERT(match == kArrayBrace); + } + script++; + // !!! see if brace or bracket is correct closer + break; + } + char nextChar = script[1]; + int advance = logicalOp(ch, nextChar); + if (advance == 0) + advance = arithmeticOp(ch, nextChar, lastPush); + if (advance == 0) // unknown token + return false; + if (advance > 0) + script += advance; + lastPush = ch == ']' || ch == ')'; + } + if (fTokenLength > 0) { + success = handleProperty(); + SkASSERT(success); + } + int branchIndex = 0; + branchBalance = fBranchStack.count() - branchBalance; + fBranchPopAllowed = false; + while (branchIndex < branchBalance) { + Branch& branch = fBranchStack.index(branchIndex++); + if (branch.fPrimed == Branch::kIsPrimed) + break; + Op branchOp = branch.fOperator; + SkOperand2::OpType lastType = fValueStack.top().fType; + addTokenValue(fValueStack.top(), kAccumulator); + fValueStack.pop(); + if (branchOp == kLogicalAnd || branchOp == kLogicalOr) { + if (branch.fOperator == kLogicalAnd) + branch.prime(); + addToken(kToBool); + } else { + resolveBranch(branch); + SkScriptValue2 operand; + operand.fType = lastType; + // !!! note that many branching expressions could be constant + // today, we always evaluate branches as returning variables + operand.fIsConstant = SkScriptValue2::kVariable; + fValueStack.push(operand); + } + if (branch.fDone == Branch::kIsNotDone) + branch.prime(); + } + fBranchPopAllowed = true; + while (fBranchStack.top().fDone == Branch::kIsDone) + fBranchStack.pop(); + while (fOpStack.count() > opBalance) { // leave open paren + if (processOp() == false) + return false; + } + SkOperand2::OpType topType = fValueStack.count() > 0 ? fValueStack.top().fType : SkOperand2::kNoType; + if (topType != fReturnType && + topType == SkOperand2::kString && fReturnType != SkOperand2::kNoType) { // if result is a string, give handle property a chance to convert it to the property value + SkString* string = fValueStack.top().fOperand.fString; + fToken = string->c_str(); + fTokenLength = string->size(); + fValueStack.pop(); + success = handleProperty(); + if (success == false) { // if it couldn't convert, return string (error?) + SkScriptValue2 operand; + operand.fType = SkOperand2::kString; + operand.fOperand.fString = string; + operand.fIsConstant = SkScriptValue2::kVariable; // !!! ? + fValueStack.push(operand); + } + } + if (fStream.getOffset() > 0) { + addToken(kEnd); +#ifdef SK_DEBUG + decompile((const unsigned char*)fStream.getStream(), fStream.getOffset()); +#endif + SkScriptRuntime runtime(fCallBackArray); + runtime.executeTokens((unsigned char*) fStream.getStream()); + SkScriptValue2 value1; + runtime.getResult(&value1.fOperand); + value1.fType = fReturnType; + fValueStack.push(value1); + } + if (value) { + if (fValueStack.count() == 0) + return false; + fValueStack.pop(value); + if (value->fType != fReturnType && value->fType == SkOperand2::kObject && + fReturnType != SkOperand2::kNoType) + convertTo(fReturnType, value); + } + // if (fBranchStack.top().fOpStackDepth > fOpStack.count()) + // resolveBranch(); + *scriptPtr = script; + return true; // no error +} + +bool SkScriptEngine2::handleArrayIndexer(const char** scriptPtr) { + SkScriptValue2 scriptValue; + (*scriptPtr)++; + *fOpStack.push() = (Op) kParen; + *fBraceStack.push() = kArrayBrace; + SkOperand2::OpType saveType = fReturnType; + fReturnType = SkOperand2::kS32; + bool success = innerScript(scriptPtr, &scriptValue); + fReturnType = saveType; + SkASSERT(success); + success = convertTo(SkOperand2::kS32, &scriptValue); + SkASSERT(success); + int index = scriptValue.fOperand.fS32; + fValueStack.pop(&scriptValue); + if (scriptValue.fType == SkOperand2::kObject) { + success = handleUnbox(&scriptValue); + SkASSERT(success); + SkASSERT(scriptValue.fType == SkOperand2::kArray); + } + scriptValue.fType = scriptValue.fOperand.fArray->getType(); + // SkASSERT(index >= 0); + if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) { + fError = kArrayIndexOutOfBounds; + return false; + } + scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index]; + scriptValue.fIsConstant = SkScriptValue2::kVariable; + fValueStack.push(scriptValue); + fOpStack.pop(); // pop paren + return success; +} + +bool SkScriptEngine2::handleFunction(const char** scriptPtr) { + const char* functionName = fToken; + size_t functionNameLen = fTokenLength; + fTokenLength = 0; + SkTDArray<SkScriptValue2> params; + bool success = functionParams(scriptPtr, ¶ms); + if (success == false) + goto done; + { + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { + if ((*callBack)->getType() != SkScriptCallBack::kFunction) + continue; + SkScriptValue2 callbackResult; + success = (*callBack)->getReference(functionName, functionNameLen, &callbackResult); + if (success) { + callbackResult.fType = (*callBack)->getReturnType(callbackResult.fOperand.fReference, nil); + callbackResult.fIsConstant = SkScriptValue2::kVariable; + fValueStack.push(callbackResult); + goto done; + } + } + } + return false; +done: + fOpStack.pop(); + return success; +} + +bool SkScriptEngine2::handleMember(const char* field, size_t len, void* object) { + bool success = true; + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { + if ((*callBack)->getType() != SkScriptCallBack::kMember) + continue; + SkScriptValue2 callbackResult; + success = (*callBack)->getReference(field, len, &callbackResult); + if (success) { + if (callbackResult.fType == SkOperand2::kString) + track(callbackResult.fOperand.fString); + callbackResult.fIsConstant = SkScriptValue2::kVariable; + fValueStack.push(callbackResult); + goto done; + } + } + return false; +done: + return success; +} + +bool SkScriptEngine2::handleMemberFunction(const char* field, size_t len, void* object, + SkTDArray<SkScriptValue2>* params) { + bool success = true; + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { + if ((*callBack)->getType() != SkScriptCallBack::kMemberFunction) + continue; + SkScriptValue2 callbackResult; + success = (*callBack)->getReference(field, len, &callbackResult); + if (success) { + if (callbackResult.fType == SkOperand2::kString) + track(callbackResult.fOperand.fString); + callbackResult.fIsConstant = SkScriptValue2::kVariable; + fValueStack.push(callbackResult); + goto done; + } + } + return false; +done: + return success; +} + +bool SkScriptEngine2::handleProperty() { + bool success = true; + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { + if ((*callBack)->getType() != SkScriptCallBack::kProperty) + continue; + SkScriptValue2 callbackResult; + success = (*callBack)->getReference(fToken, fTokenLength, &callbackResult); + if (success) { + if (callbackResult.fType == SkOperand2::kString && callbackResult.fOperand.fString == nil) { + callbackResult.fOperand.fString = new SkString(fToken, fTokenLength); + track(callbackResult.fOperand.fString); + } + callbackResult.fIsConstant = SkScriptValue2::kVariable; + fValueStack.push(callbackResult); + goto done; + } + } +done: + fTokenLength = 0; + return success; +} + +bool SkScriptEngine2::handleUnbox(SkScriptValue2* scriptValue) { + bool success = true; + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { + if ((*callBack)->getType() != SkScriptCallBack::kUnbox) + continue; + SkScriptCallBackConvert* callBackConvert = (SkScriptCallBackConvert*) *callBack; + success = callBackConvert->convert(scriptValue->fType, &scriptValue->fOperand); + if (success) { + if (scriptValue->fType == SkOperand2::kString) + track(scriptValue->fOperand.fString); + goto done; + } + } + return false; +done: + return success; +} + +// note that entire expression is treated as if it were enclosed in parens +// an open paren is always the first thing in the op stack + +int SkScriptEngine2::logicalOp(char ch, char nextChar) { + int advance = 1; + Op op; + signed char precedence; + switch (ch) { + case ')': + op = (Op) kParen; + break; + case ']': + op = (Op) kArrayOp; + break; + case '?': + op = (Op) kIf; + break; + case ':': + op = (Op) kElse; + break; + case '&': + if (nextChar != '&') + goto noMatch; + op = kLogicalAnd; + advance = 2; + break; + case '|': + if (nextChar != '|') + goto noMatch; + op = kLogicalOr; + advance = 2; + break; + default: + noMatch: + return 0; + } + precedence = gPrecedence[op]; + int branchIndex = 0; + fBranchPopAllowed = false; + do { + while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence) + processOp(); + Branch& branch = fBranchStack.index(branchIndex++); + Op branchOp = branch.fOperator; + if (gPrecedence[branchOp] >= precedence) + break; + addTokenValue(fValueStack.top(), kAccumulator); + fValueStack.pop(); + if (branchOp == kLogicalAnd || branchOp == kLogicalOr) { + if (branch.fOperator == kLogicalAnd) + branch.prime(); + addToken(kToBool); + } else + resolveBranch(branch); + if (branch.fDone == Branch::kIsNotDone) + branch.prime(); + } while (true); + fBranchPopAllowed = true; + while (fBranchStack.top().fDone == Branch::kIsDone) + fBranchStack.pop(); + processLogicalOp(op); + return advance; +} + +void SkScriptEngine2::processLogicalOp(Op op) { + switch (op) { + case kParen: + case kArrayOp: + SkASSERT(fOpStack.count() > 1 && fOpStack.top() == op); // !!! add error handling + if (op == kParen) + fOpStack.pop(); + else { + SkScriptValue2 value; + fValueStack.pop(&value); + SkASSERT(value.fType == SkOperand2::kS32 || value.fType == SkOperand2::kScalar); // !!! add error handling (although, could permit strings eventually) + int index = value.fType == SkOperand2::kScalar ? SkScalarFloor(value.fOperand.fScalar) : + value.fOperand.fS32; + SkScriptValue2 arrayValue; + fValueStack.pop(&arrayValue); + SkASSERT(arrayValue.fType == SkOperand2::kArray); // !!! add error handling + SkOpArray* array = arrayValue.fOperand.fArray; + SkOperand2 operand; + bool success = array->getIndex(index, &operand); + SkASSERT(success); // !!! add error handling + SkScriptValue2 resultValue; + resultValue.fType = array->getType(); + resultValue.fOperand = operand; + resultValue.fIsConstant = SkScriptValue2::kVariable; + fValueStack.push(resultValue); + } + break; + case kIf: { + if (fAccumulatorType == SkOperand2::kNoType) { + addTokenValue(fValueStack.top(), kAccumulator); + fValueStack.pop(); + } + SkASSERT(fAccumulatorType != SkOperand2::kString); // !!! add error handling + addToken(kIfOp); + Branch branch(op, fOpStack.count(), getTokenOffset()); + *fBranchStack.push() = branch; + addTokenInt(0); // placeholder for future branch + fAccumulatorType = SkOperand2::kNoType; + } break; + case kElse: { + addTokenValue(fValueStack.top(), kAccumulator); + fValueStack.pop(); + addToken(kElseOp); + size_t newOffset = getTokenOffset(); + addTokenInt(0); // placeholder for future branch + Branch& branch = fBranchStack.top(); + resolveBranch(branch); + branch.fOperator = op; + branch.fDone = Branch::kIsNotDone; + SkASSERT(branch.fOpStackDepth == fOpStack.count()); + branch.fOffset = newOffset; + fAccumulatorType = SkOperand2::kNoType; + } break; + case kLogicalAnd: + case kLogicalOr: { + Branch& oldTop = fBranchStack.top(); + Branch::Primed wasPrime = oldTop.fPrimed; + Branch::Done wasDone = oldTop.fDone; + oldTop.fPrimed = Branch::kIsNotPrimed; + oldTop.fDone = Branch::kIsNotDone; + if (fAccumulatorType == SkOperand2::kNoType) { + SkASSERT(fValueStack.top().fType == SkOperand2::kS32); // !!! add error handling, and conversion to int? + addTokenValue(fValueStack.top(), kAccumulator); + fValueStack.pop(); + } else + SkASSERT(fAccumulatorType == SkOperand2::kS32); + // if 'and', write beq goto opcode after end of predicate (after to bool) + // if 'or', write bne goto to bool + addToken(op == kLogicalAnd ? kLogicalAndInt : kLogicalOrInt); + Branch branch(op, fOpStack.count(), getTokenOffset()); + addTokenInt(0); // placeholder for future branch + oldTop.fPrimed = wasPrime; + oldTop.fDone = wasDone; + *fBranchStack.push() = branch; + fAccumulatorType = SkOperand2::kNoType; + } break; + default: + SkASSERT(0); + } +} + +bool SkScriptEngine2::processOp() { + Op op; + fOpStack.pop(&op); + op = (Op) (op & ~kArtificialOp); + const OperatorAttributes* attributes = &gOpAttributes[op]; + SkScriptValue2 value1 = { 0 }; + SkScriptValue2 value2; + fValueStack.pop(&value2); + value2.fIsWritten = SkScriptValue2::kUnwritten; + // SkScriptEngine2::SkTypeOp convert1[3]; + // SkScriptEngine2::SkTypeOp convert2[3]; + // SkScriptEngine2::SkTypeOp* convert2Ptr = convert2; + bool constantOperands = value2.fIsConstant == SkScriptValue2::kConstant; + if (attributes->fLeftType != SkOperand2::kNoType) { + fValueStack.pop(&value1); + constantOperands &= value1.fIsConstant == SkScriptValue2::kConstant; + value1.fIsWritten = SkScriptValue2::kUnwritten; + if (op == kFlipOps) { + SkTSwap(value1, value2); + fOpStack.pop(&op); + op = (Op) (op & ~kArtificialOp); + attributes = &gOpAttributes[op]; + if (constantOperands == false) + addToken(kFlipOpsOp); + } + if (value1.fType == SkOperand2::kObject && (value1.fType & attributes->fLeftType) == 0) { + value1.fType = getUnboxType(value1.fOperand); + addToken(kUnboxToken); + } + } + if (value2.fType == SkOperand2::kObject && (value2.fType & attributes->fLeftType) == 0) { + value1.fType = getUnboxType(value2.fOperand); + addToken(kUnboxToken2); + } + if (attributes->fLeftType != SkOperand2::kNoType) { + if (value1.fType != value2.fType) { + if ((attributes->fLeftType & SkOperand2::kString) && attributes->fBias & kTowardsString && + ((value1.fType | value2.fType) & SkOperand2::kString)) { + if (value1.fType == SkOperand2::kS32 || value1.fType == SkOperand2::kScalar) { + addTokenConst(&value1, kAccumulator, SkOperand2::kString, + value1.fType == SkOperand2::kS32 ? kIntToString : kScalarToString); + } + if (value2.fType == SkOperand2::kS32 || value2.fType == SkOperand2::kScalar) { + addTokenConst(&value2, kOperand, SkOperand2::kString, + value2.fType == SkOperand2::kS32 ? kIntToString2 : kScalarToString2); + } + } else if (attributes->fLeftType & SkOperand2::kScalar && ((value1.fType | value2.fType) & + SkOperand2::kScalar)) { + if (value1.fType == SkOperand2::kS32) + addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kIntToScalar); + if (value2.fType == SkOperand2::kS32) + addTokenConst(&value2, kOperand, SkOperand2::kScalar, kIntToScalar2); + } + } + if ((value1.fType & attributes->fLeftType) == 0 || value1.fType != value2.fType) { + if (value1.fType == SkOperand2::kString) + addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kStringToScalar); + if (value1.fType == SkOperand2::kScalar && (attributes->fLeftType == SkOperand2::kS32 || + value2.fType == SkOperand2::kS32)) + addTokenConst(&value1, kAccumulator, SkOperand2::kS32, kScalarToInt); + } + } + AddTokenRegister rhRegister = attributes->fLeftType != SkOperand2::kNoType ? + kOperand : kAccumulator; + if ((value2.fType & attributes->fRightType) == 0 || value1.fType != value2.fType) { + if (value2.fType == SkOperand2::kString) + addTokenConst(&value2, rhRegister, SkOperand2::kScalar, kStringToScalar2); + if (value2.fType == SkOperand2::kScalar && (attributes->fRightType == SkOperand2::kS32 || + value1.fType == SkOperand2::kS32)) + addTokenConst(&value2, rhRegister, SkOperand2::kS32, kScalarToInt2); + } + TypeOp typeOp = gTokens[op]; + if (value2.fType == SkOperand2::kScalar) + typeOp = (TypeOp) (typeOp + 1); + else if (value2.fType == SkOperand2::kString) + typeOp = (TypeOp) (typeOp + 2); + SkDynamicMemoryWStream stream; + SkOperand2::OpType saveType; + SkBool saveOperand; + if (constantOperands) { + fActiveStream = &stream; + saveType = fAccumulatorType; + saveOperand = fOperandInUse; + fAccumulatorType = SkOperand2::kNoType; + fOperandInUse = false; + } + if (attributes->fLeftType != SkOperand2::kNoType) { // two operands + if (value1.fIsWritten == SkScriptValue2::kUnwritten) + addTokenValue(value1, kAccumulator); + } + if (value2.fIsWritten == SkScriptValue2::kUnwritten) + addTokenValue(value2, rhRegister); + addToken(typeOp); + if (constantOperands) { + addToken(kEnd); +#ifdef SK_DEBUG + decompile((const unsigned char*) stream.getStream(), stream.getOffset()); +#endif + SkScriptRuntime runtime(fCallBackArray); + runtime.executeTokens((unsigned char*) stream.getStream()); + runtime.getResult(&value1.fOperand); + if (attributes->fResultIsBoolean == kResultIsBoolean) + value1.fType = SkOperand2::kS32; + else if (attributes->fLeftType == SkOperand2::kNoType) // unary operand + value1.fType = value2.fType; + fValueStack.push(value1); + if (value1.fType == SkOperand2::kString) + runtime.untrack(value1.fOperand.fString); + else if (value1.fType == SkOperand2::kArray) + runtime.untrack(value1.fOperand.fArray); + fActiveStream = &fStream; + fAccumulatorType = saveType; + fOperandInUse = saveOperand; + return true; + } + value2.fIsConstant = SkScriptValue2::kVariable; + fValueStack.push(value2); + return true; +} + +void SkScriptEngine2::Branch::resolve(SkDynamicMemoryWStream* stream, size_t off) { + SkASSERT(fDone == kIsNotDone); + fPrimed = kIsNotPrimed; + fDone = kIsDone; + SkASSERT(off > fOffset + sizeof(size_t)); + size_t offset = off - fOffset - sizeof(offset); + stream->write(&offset, fOffset, sizeof(offset)); +} + +void SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) { + branch.resolve(fActiveStream, getTokenOffset()); +} + +bool SkScriptEngine2::ConvertTo(SkScriptEngine2* engine, SkOperand2::OpType toType, SkScriptValue2* value ) { + SkASSERT(value); + SkOperand2::OpType type = value->fType; + if (type == toType) + return true; + SkOperand2& operand = value->fOperand; + bool success = true; + switch (toType) { + case SkOperand2::kS32: + if (type == SkOperand2::kScalar) + operand.fS32 = SkScalarFloor(operand.fScalar); + else { + SkASSERT(type == SkOperand2::kString); + success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != nil; + } + break; + case SkOperand2::kScalar: + if (type == SkOperand2::kS32) + operand.fScalar = IntToScalar(operand.fS32); + else { + SkASSERT(type == SkOperand2::kString); + success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != nil; + } + break; + case SkOperand2::kString: { + SkString* strPtr = new SkString(); + SkASSERT(engine); + engine->track(strPtr); + if (type == SkOperand2::kS32) + strPtr->appendS32(operand.fS32); + else { + SkASSERT(type == SkOperand2::kScalar); + strPtr->appendScalar(operand.fScalar); + } + operand.fString = strPtr; + } break; + case SkOperand2::kArray: { + SkOpArray* array = new SkOpArray(type); + *array->append() = operand; + engine->track(array); + operand.fArray = array; + } break; + default: + SkASSERT(0); + } + value->fType = toType; + return success; +} + +SkScalar SkScriptEngine2::IntToScalar(S32 s32) { + SkScalar scalar; + if (s32 == SK_NaN32) + scalar = SK_ScalarNaN; + else if (SkAbs32(s32) == SK_MaxS32) + scalar = SkSign32(s32) * SK_ScalarMax; + else + scalar = SkIntToScalar(s32); + return scalar; +} + +bool SkScriptEngine2::ValueToString(const SkScriptValue2& value, SkString* string) { + switch (value.fType) { + case SkOperand2::kS32: + string->reset(); + string->appendS32(value.fOperand.fS32); + break; + case SkOperand2::kScalar: + string->reset(); + string->appendScalar(value.fOperand.fScalar); + break; + case SkOperand2::kString: + string->set(*value.fOperand.fString); + break; + default: + SkASSERT(0); + return false; + } + return true; // no error +} + +#ifdef SK_DEBUG + +#define testInt(expression) { #expression, SkOperand2::kS32, expression } +#ifdef SK_SCALAR_IS_FLOAT +#define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (float) expression } +#define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmodf(exp1, exp2) } +#else +#ifdef SK_CAN_USE_FLOAT +#define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (int) ((expression) * 65536.0f) } +#define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, (int) (fmod(exp1, exp2) * 65536.0f) } +#endif +#endif +#define testTrue(expression) { #expression, SkOperand2::kS32, 1 } +#define testFalse(expression) { #expression, SkOperand2::kS32, 0 } + +#if !defined(SK_BUILD_FOR_BREW) +static const SkScriptNAnswer2 scriptTests[] = { + testInt(1||0&&3), +#ifdef SK_CAN_USE_FLOAT + testScalar(- -5.5- -1.5), + testScalar(1.0+5), +#endif + testInt((6+7)*8), + testInt(3*(4+5)), +#ifdef SK_CAN_USE_FLOAT + testScalar(1.0+2.0), + testScalar(3.0-1.0), + testScalar(6-1.0), + testScalar(2.5*6.), + testScalar(0.5*4), + testScalar(4.5/.5), + testScalar(9.5/19), + testRemainder(9.5, 0.5), + testRemainder(9.,2), + testRemainder(9,2.5), + testRemainder(-9,2.5), + testTrue(-9==-9.0), + testTrue(-9.==-4.0-5), + testTrue(-9.*1==-4-5), + testFalse(-9!=-9.0), + testFalse(-9.!=-4.0-5), + testFalse(-9.*1!=-4-5), +#endif + testInt(0x123), + testInt(0XABC), + testInt(0xdeadBEEF), + { "'123'+\"456\"", SkOperand2::kString, 0, 0, "123456" }, + { "123+\"456\"", SkOperand2::kString, 0, 0, "123456" }, + { "'123'+456", SkOperand2::kString, 0, 0, "123456" }, + { "'123'|\"456\"", SkOperand2::kS32, 123|456 }, + { "123|\"456\"", SkOperand2::kS32, 123|456 }, + { "'123'|456", SkOperand2::kS32, 123|456 }, + { "'2'<11", SkOperand2::kS32, 1 }, + { "2<'11'", SkOperand2::kS32, 1 }, + { "'2'<'11'", SkOperand2::kS32, 0 }, + testInt(123), + testInt(-345), + testInt(+678), + testInt(1+2+3), + testInt(3*4+5), + testInt(6+7*8), + testInt(-1-2-8/4), + testInt(-9%4), + testInt(9%-4), + testInt(-9%-4), + testInt(123|978), + testInt(123&978), + testInt(123^978), + testInt(2<<4), + testInt(99>>3), + testInt(~55), + testInt(~~55), + testInt(!55), + testInt(!!55), + // both int + testInt(2<2), + testInt(2<11), + testInt(20<11), + testInt(2<=2), + testInt(2<=11), + testInt(20<=11), + testInt(2>2), + testInt(2>11), + testInt(20>11), + testInt(2>=2), + testInt(2>=11), + testInt(20>=11), + testInt(2==2), + testInt(2==11), + testInt(20==11), + testInt(2!=2), + testInt(2!=11), + testInt(20!=11), +#ifdef SK_CAN_USE_FLOAT + // left int, right scalar + testInt(2<2.), + testInt(2<11.), + testInt(20<11.), + testInt(2<=2.), + testInt(2<=11.), + testInt(20<=11.), + testInt(2>2.), + testInt(2>11.), + testInt(20>11.), + testInt(2>=2.), + testInt(2>=11.), + testInt(20>=11.), + testInt(2==2.), + testInt(2==11.), + testInt(20==11.), + testInt(2!=2.), + testInt(2!=11.), + testInt(20!=11.), + // left scalar, right int + testInt(2.<2), + testInt(2.<11), + testInt(20.<11), + testInt(2.<=2), + testInt(2.<=11), + testInt(20.<=11), + testInt(2.>2), + testInt(2.>11), + testInt(20.>11), + testInt(2.>=2), + testInt(2.>=11), + testInt(20.>=11), + testInt(2.==2), + testInt(2.==11), + testInt(20.==11), + testInt(2.!=2), + testInt(2.!=11), + testInt(20.!=11), + // both scalar + testInt(2.<11.), + testInt(20.<11.), + testInt(2.<=2.), + testInt(2.<=11.), + testInt(20.<=11.), + testInt(2.>2.), + testInt(2.>11.), + testInt(20.>11.), + testInt(2.>=2.), + testInt(2.>=11.), + testInt(20.>=11.), + testInt(2.==2.), + testInt(2.==11.), + testInt(20.==11.), + testInt(2.!=2.), + testInt(2.!=11.), + testInt(20.!=11.), +#endif + // int, string (string is int) + testFalse(2<'2'), + testTrue(2<'11'), + testFalse(20<'11'), + testTrue(2<='2'), + testTrue(2<='11'), + testFalse(20<='11'), + testFalse(2>'2'), + testFalse(2>'11'), + testTrue(20>'11'), + testTrue(2>='2'), + testFalse(2>='11'), + testTrue(20>='11'), + testTrue(2=='2'), + testFalse(2=='11'), + testFalse(2!='2'), + testTrue(2!='11'), + // int, string (string is scalar) + testFalse(2<'2.'), + testTrue(2<'11.'), + testFalse(20<'11.'), + testTrue(2=='2.'), + testFalse(2=='11.'), +#ifdef SK_CAN_USE_FLOAT + // scalar, string + testFalse(2.<'2.'), + testTrue(2.<'11.'), + testFalse(20.<'11.'), + testTrue(2.=='2.'), + testFalse(2.=='11.'), + // string, int + testFalse('2'<2), + testTrue('2'<11), + testFalse('20'<11), + testTrue('2'==2), + testFalse('2'==11), + // string, scalar + testFalse('2'<2.), + testTrue('2'<11.), + testFalse('20'<11.), + testTrue('2'==2.), + testFalse('2'==11.), +#endif + // string, string + testFalse('2'<'2'), + testFalse('2'<'11'), + testFalse('20'<'11'), + testTrue('2'=='2'), + testFalse('2'=='11'), + // logic + testInt(1?2:3), + testInt(0?2:3), + testInt(1&&2||3), + testInt(1&&0||3), + testInt(1&&0||0), + testInt(1||0&&3), + testInt(0||0&&3), + testInt(0||1&&3), + testInt(0&&1?2:3) +#ifdef SK_CAN_USE_FLOAT + , { "123.5", SkOperand2::kScalar, 0, SkIntToScalar(123) + SK_Scalar1/2 } +#endif +}; +#endif // build for brew + +#define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) + +void SkScriptEngine2::UnitTest() { +#if !defined(SK_BUILD_FOR_BREW) && defined(SK_SUPPORT_UNITTEST) + ValidateDecompileTable(); + for (int index = 0; index < SkScriptNAnswer_testCount; index++) { + SkScriptEngine2 engine(scriptTests[index].fType); + SkScriptValue2 value; + const char* script = scriptTests[index].fScript; + const char* scriptPtr = script; + SkASSERT(engine.evaluateScript(&scriptPtr, &value) == true); + SkASSERT(value.fType == scriptTests[index].fType); + SkScalar error; + switch (value.fType) { + case SkOperand2::kS32: + if (value.fOperand.fS32 != scriptTests[index].fIntAnswer) + SkDEBUGF(("script '%s' == value %d != expected answer %d\n", script, value.fOperand.fS32, scriptTests[index].fIntAnswer)); + SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); + break; + case SkOperand2::kScalar: + error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); +#ifdef SK_CAN_USE_FLOAT + if (error >= SK_Scalar1 / 10000) + SkDEBUGF(("script '%s' == value %g != expected answer %g\n", script, value.fOperand.fScalar / (1.0f * SK_Scalar1), scriptTests[index].fScalarAnswer / (1.0f * SK_Scalar1))); +#endif + SkASSERT(error < SK_Scalar1 / 10000); + break; + case SkOperand2::kString: + SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer)); + break; + default: + SkASSERT(0); + } + } +#endif +} +#endif diff --git a/libs/graphics/animator/SkSnapshot.cpp b/libs/graphics/animator/SkSnapshot.cpp new file mode 100644 index 0000000000..9bb74e604e --- /dev/null +++ b/libs/graphics/animator/SkSnapshot.cpp @@ -0,0 +1,54 @@ +#include "SkTypes.h" + +#ifdef SK_SUPPORT_IMAGE_ENCODE + +#include "SkSnapshot.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkSnapshot::fInfo[] = { + SK_MEMBER(filename, String), + SK_MEMBER(quality, Float), + SK_MEMBER(sequence, Boolean), + SK_MEMBER(type, BitmapEncoding) +}; + +#endif + +DEFINE_GET_MEMBER(SkSnapshot); + +SkSnapshot::SkSnapshot() +{ + quality = 100 * SK_Scalar1; + type = (SkImageEncoder::Type) -1; + sequence = false; + fSeqVal = 0; +} + +bool SkSnapshot::draw(SkAnimateMaker& maker) { + SkASSERT(type >= 0); + SkASSERT(filename.size() > 0); + SkImageEncoder* encoder = SkImageEncoder::Create((SkImageEncoder::Type) type); + SkBitmap bitmap; + maker.fCanvas->getPixels(&bitmap); + SkString name(filename); + if (sequence) { + char num[4] = "000"; + num[0] = (char) (num[0] + fSeqVal / 100); + num[1] = (char) (num[1] + fSeqVal / 10 % 10); + num[2] = (char) (num[2] + fSeqVal % 10); + name.append(num); + if (++fSeqVal > 999) + sequence = false; + } + if (type == SkImageEncoder::kJPEG_Type) + name.append(".jpg"); + else if (type == SkImageEncoder::kPNG_Type) + name.append(".png"); + encoder->encodeFile(name.c_str(), bitmap, SkScalarFloor(quality)); + return false; +} + +#endif diff --git a/libs/graphics/animator/SkSnapshot.h b/libs/graphics/animator/SkSnapshot.h new file mode 100644 index 0000000000..941df79215 --- /dev/null +++ b/libs/graphics/animator/SkSnapshot.h @@ -0,0 +1,25 @@ +#ifndef SkSnapShot_DEFINED +#define SkSnapShot_DEFINED + +#ifdef SK_SUPPORT_IMAGE_ENCODE + +#include "SkDrawable.h" +#include "SkImageDecoder.h" +#include "SkMemberInfo.h" +#include "SkString.h" + +class SkSnapshot: public SkDrawable { + DECLARE_MEMBER_INFO(Snapshot); + SkSnapshot(); + virtual bool draw(SkAnimateMaker& ); + private: + SkString filename; + SkScalar quality; + SkBool sequence; + int /*SkImageEncoder::Type*/ type; + int fSeqVal; +}; + +#endif // SK_SUPPORT_IMAGE_ENCODE +#endif // SkSnapShot_DEFINED + diff --git a/libs/graphics/animator/SkTDArray_Experimental.h b/libs/graphics/animator/SkTDArray_Experimental.h new file mode 100644 index 0000000000..9511d4ed52 --- /dev/null +++ b/libs/graphics/animator/SkTDArray_Experimental.h @@ -0,0 +1,133 @@ +#ifndef SkTDArray_Experimental_DEFINED +#define SkTDArray_Experimental_DEFINED + +#include "SkTypes.h" + +#ifdef SK_BUILD_FOR_UNIX +#define SK_BUILD_FOR_ADS_12 +#endif + +#ifndef SK_BUILD_FOR_ADS_12 +#define SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT 1 +#else +#define SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT 0 +#endif + +#if SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT == 0 +#include "SkTDArray.h" +#define SkIntArray(type) SkTDArray<type> +#define SkLongArray(type) SkTDArray<type> +#else + +class SkDS32Array { +protected: + SkDS32Array(); + SkDS32Array(const SkDS32Array& src); + SkDS32Array(const int32_t src[], U16CPU count); + SkDS32Array& operator=(const SkDS32Array& src); + friend int operator==(const SkDS32Array& a, const SkDS32Array& b); + int32_t* append() { return this->append(1, nil); } + int32_t* append(U16CPU count, const int32_t* src = nil); + + int32_t* appendClear() + { + int32_t* result = this->append(); + *result = 0; + return result; + } + + int find(const int32_t& elem) const; + int32_t* insert(U16CPU index, U16CPU count, const int32_t* src); + int rfind(const int32_t& elem) const; + void swap(SkDS32Array& other); +public: + bool isEmpty() const { return fCount == 0; } + int count() const { return fCount; } + + void remove(U16CPU index, U16CPU count = 1) + { + SkASSERT(index + count <= fCount); + fCount = SkToU16(fCount - count); + memmove(fArray + index, fArray + index + count, sizeof(int32_t) * (fCount - index)); + } + + void reset() + { + if (fArray) + { + sk_free(fArray); + fArray = nil; +#ifdef SK_DEBUG + fData = nil; +#endif + fReserve = fCount = 0; + } + else + { + SkASSERT(fReserve == 0 && fCount == 0); + } + } + + void setCount(U16CPU count) + { + if (count > fReserve) + this->growBy(count - fCount); + else + fCount = SkToU16(count); + } +protected: +#ifdef SK_DEBUG + enum { + kDebugArraySize = 24 + }; + int32_t(* fData)[kDebugArraySize]; +#endif + int32_t* fArray; + uint16_t fReserve, fCount; + void growBy(U16CPU extra); +}; + +#ifdef SK_DEBUG + #define SYNC() fTData = (T (*)[kDebugArraySize]) fArray +#else + #define SYNC() +#endif + +template <typename T> class SkTDS32Array : public SkDS32Array { +public: + SkTDS32Array() { SkDEBUGCODE(fTData=nil); SkASSERT(sizeof(T) == sizeof(int32_t)); } + SkTDS32Array(const SkTDS32Array<T>& src) : SkDS32Array(src) {} + ~SkTDS32Array() { sk_free(fArray); } + T& operator[](int index) const { SYNC(); SkASSERT((unsigned)index < fCount); return ((T*) fArray)[index]; } + SkTDS32Array<T>& operator=(const SkTDS32Array<T>& src) { + return (SkTDS32Array<T>&) SkDS32Array::operator=(src); } + friend int operator==(const SkTDS32Array<T>& a, const SkTDS32Array<T>& b) { + return operator==((const SkDS32Array&) a, (const SkDS32Array&) b); } + T* append() { return (T*) SkDS32Array::append(); } + T* appendClear() { return (T*) SkDS32Array::appendClear(); } + T* append(U16CPU count, const T* src = nil) { return (T*) SkDS32Array::append(count, (const int32_t*) src); } + T* begin() const { SYNC(); return (T*) fArray; } + T* end() const { return (T*) (fArray ? fArray + fCount : nil); } + int find(const T& elem) const { return SkDS32Array::find((const int32_t&) elem); } + T* insert(U16CPU index) { return this->insert(index, 1, nil); } + T* insert(U16CPU index, U16CPU count, const T* src = nil) { + return (T*) SkDS32Array::insert(index, count, (const int32_t*) src); } + int rfind(const T& elem) const { return SkDS32Array::rfind((const int32_t&) elem); } + T* push() { return this->append(); } + void push(T& elem) { *this->append() = elem; } + const T& top() const { return (*this)[fCount - 1]; } + T& top() { return (*this)[fCount - 1]; } + void pop(T* elem) { if (elem) *elem = (*this)[fCount - 1]; --fCount; } + void pop() { --fCount; } +private: +#ifdef SK_DEBUG + mutable T(* fTData)[kDebugArraySize]; +#endif +}; + +#define SkIntArray(type) SkTDS32Array<type> // holds 32 bit data types +#define SkLongArray(type) SkTDS32Array<type> // holds 32/64 bit data types depending on pointer size + +#endif // SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT + +#endif // SkTDArray_Experimental_DEFINED diff --git a/libs/graphics/animator/SkTextOnPath.cpp b/libs/graphics/animator/SkTextOnPath.cpp new file mode 100644 index 0000000000..c0e991775b --- /dev/null +++ b/libs/graphics/animator/SkTextOnPath.cpp @@ -0,0 +1,30 @@ +#include "SkTextOnPath.h" +#include "SkAnimateMaker.h" +#include "SkCanvas.h" +#include "SkDrawPath.h" +#include "SkDrawText.h" +#include "SkPaint.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkTextOnPath::fInfo[] = { + SK_MEMBER(offset, Float), + SK_MEMBER(path, Path), + SK_MEMBER(text, Text) +}; + +#endif + +DEFINE_GET_MEMBER(SkTextOnPath); + +SkTextOnPath::SkTextOnPath() : offset(0), path(nil), text(nil) { +} + +bool SkTextOnPath::draw(SkAnimateMaker& maker) { + SkASSERT(text); + SkASSERT(path); + SkBoundableAuto boundable(this, maker); + maker.fCanvas->drawTextOnPath(text->getText(), text->getSize(), + path->getPath(), offset, *maker.fPaint); + return false; +} diff --git a/libs/graphics/animator/SkTextOnPath.h b/libs/graphics/animator/SkTextOnPath.h new file mode 100644 index 0000000000..c818aed727 --- /dev/null +++ b/libs/graphics/animator/SkTextOnPath.h @@ -0,0 +1,21 @@ +#ifndef SkTextOnPath_DEFINED +#define SkTextOnPath_DEFINED + +#include "SkBoundable.h" +#include "SkMemberInfo.h" + +class SkDrawPath; +class SkText; + +class SkTextOnPath : public SkBoundable { + DECLARE_MEMBER_INFO(TextOnPath); + SkTextOnPath(); + virtual bool draw(SkAnimateMaker& ); +private: + SkScalar offset; + SkDrawPath* path; + SkText* text; + typedef SkBoundable INHERITED; +}; + +#endif // SkTextOnPath_DEFINED diff --git a/libs/graphics/animator/SkTextToPath.cpp b/libs/graphics/animator/SkTextToPath.cpp new file mode 100644 index 0000000000..d259c698f6 --- /dev/null +++ b/libs/graphics/animator/SkTextToPath.cpp @@ -0,0 +1,39 @@ +#include "SkTextToPath.h" +#include "SkAnimateMaker.h" +#include "SkDrawPaint.h" +#include "SkDrawPath.h" +#include "SkDrawText.h" +#include "SkPaint.h" + +#if SK_USE_CONDENSED_INFO == 0 + +const SkMemberInfo SkTextToPath::fInfo[] = { + SK_MEMBER(paint, Paint), + SK_MEMBER(path, Path), + SK_MEMBER(text, Text) +}; + +#endif + +DEFINE_GET_MEMBER(SkTextToPath); + +SkTextToPath::SkTextToPath() : paint(nil), path(nil), text(nil) { +} + +bool SkTextToPath::draw(SkAnimateMaker& maker) { + path->draw(maker); + return false; +} + +void SkTextToPath::onEndElement(SkAnimateMaker& maker) { + if (paint == nil || path == nil || text == nil) { + // !!! add error message here + maker.setErrorCode(SkDisplayXMLParserError::kErrorInAttributeValue); + return; + } + SkPaint realPaint; + paint->setupPaint(&realPaint); + realPaint.getTextPath(text->getText(), text->getSize(), text->x, + text->y, &path->getPath()); +} + diff --git a/libs/graphics/animator/SkTextToPath.h b/libs/graphics/animator/SkTextToPath.h new file mode 100644 index 0000000000..e36083f585 --- /dev/null +++ b/libs/graphics/animator/SkTextToPath.h @@ -0,0 +1,23 @@ +#ifndef SkTextToPath_DEFINED +#define SkTextToPath_DEFINED + +#include "SkDrawPath.h" +#include "SkMemberInfo.h" + +class SkDrawPaint; +class SkDrawPath; +class SkText; + +class SkTextToPath : public SkDrawable { + DECLARE_MEMBER_INFO(TextToPath); + SkTextToPath(); + virtual bool draw(SkAnimateMaker& ); + virtual void onEndElement(SkAnimateMaker& ); +private: + SkDrawPaint* paint; + SkDrawPath* path; + SkText* text; +}; + +#endif // SkTextToPath_DEFINED + diff --git a/libs/graphics/animator/SkTime.cpp b/libs/graphics/animator/SkTime.cpp new file mode 100644 index 0000000000..928480f550 --- /dev/null +++ b/libs/graphics/animator/SkTime.cpp @@ -0,0 +1,72 @@ +#include "SkTime.h" + +#ifdef SK_BUILD_FOR_WIN + +#ifdef SK_DEBUG +SkMSec gForceTickCount = (SkMSec) -1; +#endif + +void SkTime::GetDateTime(DateTime* t) +{ + if (t) + { + SYSTEMTIME syst; + + ::GetLocalTime(&syst); + t->fYear = SkToU16(syst.wYear); + t->fMonth = SkToU8(syst.wMonth); + t->fDayOfWeek = SkToU8(syst.wDayOfWeek); + t->fDay = SkToU8(syst.wDay); + t->fHour = SkToU8(syst.wHour); + t->fMinute = SkToU8(syst.wMinute); + t->fSecond = SkToU8(syst.wSecond); + } +} + +SkMSec SkTime::GetMSecs() +{ +#ifdef SK_DEBUG + if (gForceTickCount != (SkMSec) -1) + return gForceTickCount; +#endif + return ::GetTickCount(); +} + +#elif defined(xSK_BUILD_FOR_MAC) + +#include <time.h> + +void SkTime::GetDateTime(DateTime* t) +{ + if (t) + { + tm syst; + time_t tm; + + time(&tm); + localtime_r(&tm, &syst); + t->fYear = SkToU16(syst.tm_year); + t->fMonth = SkToU8(syst.tm_mon + 1); + t->fDayOfWeek = SkToU8(syst.tm_wday); + t->fDay = SkToU8(syst.tm_mday); + t->fHour = SkToU8(syst.tm_hour); + t->fMinute = SkToU8(syst.tm_min); + t->fSecond = SkToU8(syst.tm_sec); + } +} + +#include "Sk64.h" + +SkMSec SkTime::GetMSecs() +{ + UnsignedWide wide; + Sk64 s; + + ::Microseconds(&wide); + s.set(wide.hi, wide.lo); + s.div(1000, Sk64::kRound_DivOption); + return s.get32(); +} + +#endif + diff --git a/libs/graphics/animator/SkTypedArray.cpp b/libs/graphics/animator/SkTypedArray.cpp new file mode 100644 index 0000000000..f73d8aa324 --- /dev/null +++ b/libs/graphics/animator/SkTypedArray.cpp @@ -0,0 +1,170 @@ +#include "SkTypedArray.h" + +SkTypedArray::SkTypedArray() : fType(SkType_Unknown) { +} + +SkTypedArray::SkTypedArray(SkDisplayTypes type) : fType(type) { +} + +bool SkTypedArray::getIndex(int index, SkOperand* operand) { + if (index >= count()) { + SkASSERT(0); + return false; + } + *operand = begin()[index]; + return true; +} + + +#if SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT == 1 +SkDS32Array::SkDS32Array() +{ + fReserve = fCount = 0; + fArray = nil; +#ifdef SK_DEBUG + fData = nil; +#endif +} + +SkDS32Array::SkDS32Array(const SkDS32Array& src) +{ + fReserve = fCount = 0; + fArray = nil; +#ifdef SK_DEBUG + fData = nil; +#endif + SkDS32Array tmp(src.fArray, src.fCount); + this->swap(tmp); +} + +SkDS32Array::SkDS32Array(const S32 src[], U16CPU count) +{ + SkASSERT(src || count == 0); + + fReserve = fCount = 0; + fArray = nil; +#ifdef SK_DEBUG + fData = nil; +#endif + if (count) + { + fArray = (S32*)sk_malloc_throw(count * sizeof(S32)); +#ifdef SK_DEBUG + fData = (S32 (*)[kDebugArraySize]) fArray; +#endif + memcpy(fArray, src, sizeof(S32) * count); + fReserve = fCount = SkToU16(count); + } +} + +SkDS32Array& SkDS32Array::operator=(const SkDS32Array& src) +{ + if (this != &src) + { + if (src.fCount > fReserve) + { + SkDS32Array tmp(src.fArray, src.fCount); + this->swap(tmp); + } + else + { + memcpy(fArray, src.fArray, sizeof(S32) * src.fCount); + fCount = src.fCount; + } + } + return *this; +} + +int operator==(const SkDS32Array& a, const SkDS32Array& b) +{ + return a.fCount == b.fCount && + (a.fCount == 0 || !memcmp(a.fArray, b.fArray, a.fCount * sizeof(S32))); +} + +void SkDS32Array::swap(SkDS32Array& other) +{ + SkTSwap(fArray, other.fArray); +#ifdef SK_DEBUG + SkTSwap(fData, other.fData); +#endif + SkTSwap(fReserve, other.fReserve); + SkTSwap(fCount, other.fCount); +} + +S32* SkDS32Array::append(U16CPU count, const S32* src) +{ + unsigned oldCount = fCount; + if (count) + { + SkASSERT(src == nil || fArray == nil || + src + count <= fArray || fArray + count <= src); + + this->growBy(count); + if (src) + memcpy(fArray + oldCount, src, sizeof(S32) * count); + } + return fArray + oldCount; +} + +int SkDS32Array::find(const S32& elem) const +{ + const S32* iter = fArray; + const S32* stop = fArray + fCount; + + for (; iter < stop; iter++) + { + if (*iter == elem) + return (int) (iter - fArray); + } + return -1; +} + +void SkDS32Array::growBy(U16CPU extra) +{ + SkASSERT(extra); + SkASSERT(fCount + extra <= 0xFFFF); + + if (fCount + extra > fReserve) + { + size_t size = fCount + extra + 4; + size += size >> 2; + S32* array = (S32*)sk_malloc_throw(size * sizeof(S32)); + memcpy(array, fArray, fCount * sizeof(S32)); + + sk_free(fArray); + fArray = array; +#ifdef SK_DEBUG + fData = (S32 (*)[kDebugArraySize]) fArray; +#endif + fReserve = SkToU16((U16CPU)size); + } + fCount = SkToU16(fCount + extra); +} + +S32* SkDS32Array::insert(U16CPU index, U16CPU count, const S32* src) +{ + SkASSERT(count); + int oldCount = fCount; + this->growBy(count); + S32* dst = fArray + index; + memmove(dst + count, dst, sizeof(S32) * (oldCount - index)); + if (src) + memcpy(dst, src, sizeof(S32) * count); + return dst; +} + + + int SkDS32Array::rfind(const S32& elem) const + { + const S32* iter = fArray + fCount; + const S32* stop = fArray; + + while (iter > stop) + { + if (*--iter == elem) + return (int) (iter - stop); + } + return -1; + } + +#endif diff --git a/libs/graphics/animator/SkTypedArray.h b/libs/graphics/animator/SkTypedArray.h new file mode 100644 index 0000000000..96b42acfa1 --- /dev/null +++ b/libs/graphics/animator/SkTypedArray.h @@ -0,0 +1,22 @@ +#ifndef SkTypedArray_DEFINED +#define SkTypedArray_DEFINED + +#include "SkScript.h" +#include "SkTDArray_Experimental.h" + +class SkTypedArray : public SkTDOperandArray { +public: + SkTypedArray(); + SkTypedArray(SkDisplayTypes type); + bool getIndex(int index, SkOperand* operand); + SkDisplayTypes getType() { return fType; } + SkScriptEngine::SkOpType getOpType() { return SkScriptEngine::ToOpType(fType); } + void setType(SkDisplayTypes type) { + // SkASSERT(count() == 0); + fType = type; + } +protected: + SkDisplayTypes fType; +}; + +#endif // SkTypedArray_DEFINED diff --git a/libs/graphics/animator/SkXMLAnimatorWriter.cpp b/libs/graphics/animator/SkXMLAnimatorWriter.cpp new file mode 100644 index 0000000000..8045fdea40 --- /dev/null +++ b/libs/graphics/animator/SkXMLAnimatorWriter.cpp @@ -0,0 +1,74 @@ +#include "SkXMLAnimatorWriter.h" +#include "SkAnimator.h" +#include "SkAnimateMaker.h" +#include "SkDisplayXMLParser.h" + +SkXMLAnimatorWriter::SkXMLAnimatorWriter(SkAnimator* animator) : fAnimator(animator) +{ + fParser = new SkDisplayXMLParser(*fAnimator->fMaker); +} + +SkXMLAnimatorWriter::~SkXMLAnimatorWriter() { + delete fParser; +} + +void SkXMLAnimatorWriter::onAddAttributeLen(const char name[], const char value[], size_t length) +{ + fParser->onAddAttributeLen(name, value, length); +} + +void SkXMLAnimatorWriter::onEndElement() +{ + Elem* elem = getEnd(); + fParser->onEndElement(elem->fName.c_str()); + doEnd(elem); +} + +void SkXMLAnimatorWriter::onStartElementLen(const char name[], size_t length) +{ + doStart(name, length); + fParser->onStartElementLen(name, length); +} + +void SkXMLAnimatorWriter::writeHeader() +{ +} + +#ifdef SK_DEBUG +#include "SkCanvas.h" +#include "SkPaint.h" + +void SkXMLAnimatorWriter::UnitTest(SkCanvas* canvas) +{ + SkAnimator s; + SkXMLAnimatorWriter w(&s); + w.startElement("screenplay"); + w.startElement("animateField"); + w.addAttribute("field", "x1"); + w.addAttribute("id", "to100"); + w.addAttribute("from", "0"); + w.addAttribute("to", "100"); + w.addAttribute("dur", "1"); + w.endElement(); + w.startElement("event"); + w.addAttribute("kind", "onLoad"); + w.startElement("line"); + w.addAttribute("id", "line"); + w.addAttribute("x1", "-1"); + w.addAttribute("y1", "20"); + w.addAttribute("x2", "150"); + w.addAttribute("y2", "40"); + w.endElement(); + w.startElement("apply"); + w.addAttribute("animator", "to100"); + w.addAttribute("scope", "line"); + w.endElement(); + w.endElement(); + w.endElement(); + SkPaint paint; + canvas->drawRGB(255, 255, 255); + s.draw(canvas, &paint, 0); +} + +#endif + diff --git a/libs/graphics/animator/SkXMLAnimatorWriter.h b/libs/graphics/animator/SkXMLAnimatorWriter.h new file mode 100644 index 0000000000..7180dbda0d --- /dev/null +++ b/libs/graphics/animator/SkXMLAnimatorWriter.h @@ -0,0 +1,25 @@ +#ifndef SkXMLAnimatorWriter_DEFINED +#define SkXMLAnimatorWriter_DEFINED + +#include "SkXMLWriter.h" + +class SkAnimator; +class SkDisplayXMLParser; + +class SkXMLAnimatorWriter : public SkXMLWriter { +public: + SkXMLAnimatorWriter(SkAnimator*); + virtual ~SkXMLAnimatorWriter(); + virtual void writeHeader(); + SkDEBUGCODE(static void UnitTest(class SkCanvas* canvas);) +protected: + virtual void onAddAttributeLen(const char name[], const char value[], size_t length); + virtual void onEndElement(); + virtual void onStartElementLen(const char elem[], size_t length); +private: + SkAnimator* fAnimator; + SkDisplayXMLParser* fParser; +}; + +#endif // SkXMLAnimatorWriter_DEFINED + diff --git a/libs/graphics/animator/thingstodo.txt b/libs/graphics/animator/thingstodo.txt new file mode 100644 index 0000000000..8d0d47a02d --- /dev/null +++ b/libs/graphics/animator/thingstodo.txt @@ -0,0 +1,21 @@ +things to do: + figure out where endless or very deep recursion is possible + at these points, generate an error if actual physical stack gets too large + candidates are scripts + eval(eval(eval... user callouts + ((((( operator precedence or similar making stack deep + groups within groups + very large apply create or apply immediate steps + + write tests for math functions + looks like random takes a parameter when it should take zero parameters + + add Math, Number files to perforce for docs + alphabetize attributes in docs + + manually modified tools/screenplayDocs/xmlToJPEG.cpp + + fix docs where lines are stitched together (insert space) + + naked <data> outside of <post> asserts on name + handle errors for all element not contained by correct parents
\ No newline at end of file |