grab from latest android



git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/animator/SkAnimate.h b/src/animator/SkAnimate.h
new file mode 100644
index 0000000..a4281d3
--- /dev/null
+++ b/src/animator/SkAnimate.h
@@ -0,0 +1,43 @@
+/* libs/graphics/animator/SkAnimate.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkAnimate3DSchema.xsd b/src/animator/SkAnimate3DSchema.xsd
new file mode 100644
index 0000000..5063b75
--- /dev/null
+++ b/src/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/src/animator/SkAnimate3DSchema.xsx b/src/animator/SkAnimate3DSchema.xsx
new file mode 100644
index 0000000..ceb7d89
--- /dev/null
+++ b/src/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/src/animator/SkAnimateActive.cpp b/src/animator/SkAnimateActive.cpp
new file mode 100644
index 0000000..4ee7ded
--- /dev/null
+++ b/src/animator/SkAnimateActive.cpp
@@ -0,0 +1,509 @@
+/* libs/graphics/animator/SkAnimateActive.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL, 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, NULL, 
+                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, NULL, 
+                    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 == NULL) // 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/src/animator/SkAnimateActive.h b/src/animator/SkAnimateActive.h
new file mode 100644
index 0000000..b0c4483
--- /dev/null
+++ b/src/animator/SkAnimateActive.h
@@ -0,0 +1,87 @@
+/* libs/graphics/animator/SkAnimateActive.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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;
+        int32_t 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/src/animator/SkAnimateBase.cpp b/src/animator/SkAnimateBase.cpp
new file mode 100644
index 0000000..10a3b5b
--- /dev/null
+++ b/src/animator/SkAnimateBase.cpp
@@ -0,0 +1,247 @@
+/* libs/graphics/animator/SkAnimateBase.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL), fFieldInfo(NULL), fFieldOffset(0), fStart((SkMSec) -1), fTarget(NULL), 
+        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 == NULL)
+                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 == NULL)
+            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/src/animator/SkAnimateBase.h b/src/animator/SkAnimateBase.h
new file mode 100644
index 0000000..64b9722
--- /dev/null
+++ b/src/animator/SkAnimateBase.h
@@ -0,0 +1,91 @@
+/* libs/graphics/animator/SkAnimateBase.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkAnimateField.cpp b/src/animator/SkAnimateField.cpp
new file mode 100644
index 0000000..f1439a2
--- /dev/null
+++ b/src/animator/SkAnimateField.cpp
@@ -0,0 +1,130 @@
+/* libs/graphics/animator/SkAnimateField.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 == NULL) // if NULL, 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 == NULL) {
+        maker.setErrorNoun(field);
+        maker.setErrorCode(SkDisplayXMLParserError::kFieldNotInTarget);
+    }
+    if (resolved == false || fFieldInfo == NULL)
+        return;
+    SkDisplayTypes outType = fFieldInfo->getType();
+    if (fHasValues) {
+        SkASSERT(to.size() > 0);
+        fFieldInfo->setValue(maker, &fValues, 0, 0, NULL, 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/src/animator/SkAnimateMaker.cpp b/src/animator/SkAnimateMaker.cpp
new file mode 100644
index 0000000..8a78678
--- /dev/null
+++ b/src/animator/SkAnimateMaker.cpp
@@ -0,0 +1,376 @@
+/* libs/graphics/animator/SkAnimateMaker.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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);
+    SkStream* stream = new SkFILEStream(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 = *(int32_t*) stepPtr;
+        value->fType = SkType_Int;
+        return true;
+    }
+    return false;
+}
diff --git a/src/animator/SkAnimateMaker.h b/src/animator/SkAnimateMaker.h
new file mode 100644
index 0000000..dae8caf
--- /dev/null
+++ b/src/animator/SkAnimateMaker.h
@@ -0,0 +1,169 @@
+/* libs/graphics/animator/SkAnimateMaker.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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;
+    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/src/animator/SkAnimateProperties.h b/src/animator/SkAnimateProperties.h
new file mode 100644
index 0000000..9e3da9a
--- /dev/null
+++ b/src/animator/SkAnimateProperties.h
@@ -0,0 +1,29 @@
+/* libs/graphics/animator/SkAnimateProperties.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkAnimateSchema.xsd b/src/animator/SkAnimateSchema.xsd
new file mode 100644
index 0000000..2c75eb4
--- /dev/null
+++ b/src/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 &lt;random&gt; 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/src/animator/SkAnimateSchema.xsx b/src/animator/SkAnimateSchema.xsx
new file mode 100644
index 0000000..ceb7d89
--- /dev/null
+++ b/src/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/src/animator/SkAnimateSet.cpp b/src/animator/SkAnimateSet.cpp
new file mode 100644
index 0000000..dd636da
--- /dev/null
+++ b/src/animator/SkAnimateSet.cpp
@@ -0,0 +1,98 @@
+/* libs/graphics/animator/SkAnimateSet.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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, NULL, 
+        fFieldInfo->getType(), to);
+}
+
+void SkSet::onEndElement(SkAnimateMaker& maker) {
+    if (resolveCommon(maker) == false)
+        return;
+    if (fFieldInfo == NULL) {
+        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/src/animator/SkAnimateSet.h b/src/animator/SkAnimateSet.h
new file mode 100644
index 0000000..9f9ecfb
--- /dev/null
+++ b/src/animator/SkAnimateSet.h
@@ -0,0 +1,36 @@
+/* libs/graphics/animator/SkAnimateSet.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkAnimator.cpp b/src/animator/SkAnimator.cpp
new file mode 100644
index 0000000..242398b
--- /dev/null
+++ b/src/animator/SkAnimator.cpp
@@ -0,0 +1,724 @@
+/* libs/graphics/animator/SkAnimator.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL) {
+    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);
+    SkStream* stream = new SkFILEStream(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 == NULL)
+        return draw(canvas, time);
+    fMaker->fScreenplay.time = time;
+    fMaker->fCanvas = canvas;
+    fMaker->fPaint = paint;
+    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 NULL;
+    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 NULL;
+    return (const SkDisplayable*) element;
+}
+
+SkElementType SkAnimator::getElementType(const SkDisplayable* ae) {
+    SkDisplayable* element = (SkDisplayable*) ae;
+    const SkMemberInfo* info = SkDisplayType::GetMembers(fMaker, element->getType(), NULL);
+    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 == NULL)
+        return SK_NaN32;
+    const SkMemberInfo* field = getField(element, fieldID);
+    if (field == NULL)
+        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 == NULL)
+        return SK_ScalarNaN;
+    const SkMemberInfo* field = getField(element, fieldID);
+    if (field == NULL)
+        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() : NULL;
+}
+
+const char* SkAnimator::getArrayString(const char* id, const char* fieldID, int index) {
+    const SkDisplayable* element = getElement(id);
+    if (element == NULL)
+        return NULL;
+    const SkMemberInfo* field = getField(element, fieldID);
+    if (field == NULL)
+        return NULL;
+    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 == NULL)
+        return SK_NaN32;
+    const SkMemberInfo* field = getField(element, fieldID);
+    if (field == NULL)
+        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 == NULL)
+        return SK_ScalarNaN;
+    const SkMemberInfo* field = getField(element, fieldID);
+    if (field == NULL)
+        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 == NULL)
+        return NULL;
+    const SkMemberInfo* field = getField(element, fieldID);
+    if (field == NULL)
+        return NULL;
+    return getString(element, field);
+}
+
+const char* SkAnimator::getURIBase() {
+    return fMaker->fPrefix.c_str();
+}
+
+void SkAnimator::initialize() {
+    SkDELETE(fMaker);
+    fMaker = SkNEW_ARGS(SkAnimateMaker, (this, NULL, NULL));
+    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 == NULL)
+        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 == NULL)
+            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 'NULL's to 'NULL'?
+    if (element == NULL)
+        return false;
+    const SkMemberInfo* field = getField(element, fieldID);
+    if (field == NULL)
+        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 == NULL)
+        return false;
+    const SkMemberInfo* field = getField(element, fieldID);
+    if (field == NULL)
+        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 == NULL)
+        return false;
+    const SkMemberInfo* field = getField(element, fieldID);
+    if (field == NULL)
+        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, NULL, 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 == NULL)
+        return false;
+    const SkMemberInfo* field = getField(element, fieldID);
+    if (field == NULL)
+        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 (uri[0] != '.' /*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/src/animator/SkAnimatorScript.cpp b/src/animator/SkAnimatorScript.cpp
new file mode 100644
index 0000000..eafe1db
--- /dev/null
+++ b/src/animator/SkAnimatorScript.cpp
@@ -0,0 +1,607 @@
+/* libs/graphics/animator/SkAnimatorScript.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkAnimatorScript.h b/src/animator/SkAnimatorScript.h
new file mode 100644
index 0000000..2fdb029
--- /dev/null
+++ b/src/animator/SkAnimatorScript.h
@@ -0,0 +1,84 @@
+/* libs/graphics/animator/SkAnimatorScript.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkAnimatorScript2.cpp b/src/animator/SkAnimatorScript2.cpp
new file mode 100644
index 0000000..08dbf16
--- /dev/null
+++ b/src/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 == NULL)
+			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 == NULL || 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) != NULL;
+	}
+};
+
+
+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(NULL /* fMaker */, type))
+		return SkOperand2::kObject;
+	if (SkDisplayType::IsEnum(NULL /* 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 == 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;
+}
+
+#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, NULL, 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/src/animator/SkAnimatorScript2.h b/src/animator/SkAnimatorScript2.h
new file mode 100644
index 0000000..61261e9
--- /dev/null
+++ b/src/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/src/animator/SkBase64.cpp b/src/animator/SkBase64.cpp
new file mode 100644
index 0000000..e192a52
--- /dev/null
+++ b/src/animator/SkBase64.cpp
@@ -0,0 +1,188 @@
+/* libs/graphics/animator/SkBase64.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL) {
+}
+
+#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 = (uint8_t) (bytes[0] << 2);
+            two = bytes[1];
+            one |= two >> 4;
+            two = (uint8_t) (two << 4);
+            three = bytes[2];
+            two |= three >> 2;
+            three = (uint8_t) (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 = (uint8_t) *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, NULL);
+        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/src/animator/SkBase64.h b/src/animator/SkBase64.h
new file mode 100644
index 0000000..12ccf8c
--- /dev/null
+++ b/src/animator/SkBase64.h
@@ -0,0 +1,47 @@
+/* libs/graphics/animator/SkBase64.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkBoundable.cpp b/src/animator/SkBoundable.cpp
new file mode 100644
index 0000000..f2125ea
--- /dev/null
+++ b/src/animator/SkBoundable.cpp
@@ -0,0 +1,64 @@
+/* libs/graphics/animator/SkBoundable.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 == (int16_t)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(NULL);
+    fBoundable->setBounds(fMaker.fDisplayList.fBounds);
+}
+
diff --git a/src/animator/SkBoundable.h b/src/animator/SkBoundable.h
new file mode 100644
index 0000000..67f5a12
--- /dev/null
+++ b/src/animator/SkBoundable.h
@@ -0,0 +1,50 @@
+/* libs/graphics/animator/SkBoundable.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 != (int16_t)0x8000U; }
+    void setBounds(SkIRect& bounds) { fBounds = bounds; }
+protected:
+    void clearBounds() { fBounds.fLeft = (int16_t) SkToU16(0x8000); }; // mark bounds as unset
+    SkIRect 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/src/animator/SkBuildCondensedInfo.cpp b/src/animator/SkBuildCondensedInfo.cpp
new file mode 100644
index 0000000..5e4eedc
--- /dev/null
+++ b/src/animator/SkBuildCondensedInfo.cpp
@@ -0,0 +1,292 @@
+/* libs/graphics/animator/SkBuildCondensedInfo.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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] == NULL);
+    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 == NULL)
+            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, NULL);
+                    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 == NULL)
+            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 == NULL)
+            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 == NULL)
+            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 == NULL)
+            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/src/animator/SkCondensedDebug.cpp b/src/animator/SkCondensedDebug.cpp
new file mode 100644
index 0000000..e7b7ff1
--- /dev/null
+++ b/src/animator/SkCondensedDebug.cpp
@@ -0,0 +1,1397 @@
+/* libs/graphics/animator/SkCondensedDebug.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkCondensedRelease.cpp b/src/animator/SkCondensedRelease.cpp
new file mode 100644
index 0000000..a493cb3
--- /dev/null
+++ b/src/animator/SkCondensedRelease.cpp
@@ -0,0 +1,1374 @@
+/* libs/graphics/animator/SkCondensedRelease.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayAdd.cpp b/src/animator/SkDisplayAdd.cpp
new file mode 100644
index 0000000..8a97a06
--- /dev/null
+++ b/src/animator/SkDisplayAdd.cpp
@@ -0,0 +1,254 @@
+/* libs/graphics/animator/SkDisplayAdd.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL), where(NULL) {
+}
+
+SkDisplayable* SkAdd::deepCopy(SkAnimateMaker* maker) {
+    SkDrawable* saveUse = use;
+    SkDrawable* saveWhere = where;
+    use = NULL;
+    where = NULL;
+    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 == NULL) // not set in apply yet
+            return true;
+    }
+    bool skipAddToParent = true;
+    SkASSERT(type != SkType_Replace || where);
+    SkTDDrawableArray* grandList SK_INIT_TO_AVOID_WARNING;
+    SkGroup* parentGroup = NULL;
+    SkGroup* thisGroup = NULL;
+    int index = where ? displayList.findGroup(where, &parentList, &parentGroup,
+        &thisGroup, &grandList) : 0;
+    if (index < 0)
+        return true;
+    int max = parentList->count();
+    if (where == NULL && 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 == NULL)
+        index += max + 1;
+    switch (type) {
+        case SkType_Add:
+            if (offset == SK_MaxS32 && where == NULL) {
+                if (use->isDrawable()) {
+                    skipAddToParent = mode == kMode_immediate;
+                    if (skipAddToParent) {
+                        if (where == NULL) {
+                            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 == NULL && use != NULL && 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/src/animator/SkDisplayAdd.h b/src/animator/SkDisplayAdd.h
new file mode 100644
index 0000000..0f3edc9
--- /dev/null
+++ b/src/animator/SkDisplayAdd.h
@@ -0,0 +1,81 @@
+/* libs/graphics/animator/SkDisplayAdd.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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;
+        int32_t offset;
+        SkDrawable* use;
+        SkDrawable* where;  // if NULL, 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/src/animator/SkDisplayApply.cpp b/src/animator/SkDisplayApply.cpp
new file mode 100644
index 0000000..b9e65f7
--- /dev/null
+++ b/src/animator/SkDisplayApply.cpp
@@ -0,0 +1,814 @@
+/* libs/graphics/animator/SkDisplayApply.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL), steps(-1), transition((Transition) -1), fActive(NULL), /*fCurrentScope(NULL),*/
+    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 != NULL) {
+        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 == NULL)
+        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 != NULL);
+    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(), NULL);
+        } 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 = NULL;
+    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 ==NULL)
+        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 != NULL;
+    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 == NULL)
+        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 != NULL) {
+        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 == NULL || 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 != NULL && 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 == NULL)
+                apply->activate(maker);
+            apply->append(this);
+            parentGroup = NULL;
+        } 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 = NULL;
+                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(), NULL))
+            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 = NULL, * found = NULL;
+        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 != NULL) {
+                    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 = NULL;
+}
+
+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 == NULL)
+        return false;
+    maker.removeActive(fActive);
+    delete fActive;
+    fActive = NULL;
+    return true;
+}
+
+#ifdef SK_DEBUG
+SkMSec lastTime = (SkMSec) -1;
+#endif
+
+bool SkApply::interpolate(SkAnimateMaker& maker, SkMSec rawTime) {
+    if (fActive == NULL)
+        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 != NULL && 
+        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, NULL, 
+                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 == NULL)
+        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 != NULL && 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 == NULL || 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 != NULL && 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] == NULL) {
+        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/src/animator/SkDisplayApply.h b/src/animator/SkDisplayApply.h
new file mode 100644
index 0000000..d51e467
--- /dev/null
+++ b/src/animator/SkDisplayApply.h
@@ -0,0 +1,116 @@
+/* libs/graphics/animator/SkDisplayApply.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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;
+    int32_t 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/src/animator/SkDisplayBounds.cpp b/src/animator/SkDisplayBounds.cpp
new file mode 100644
index 0000000..d0499ce
--- /dev/null
+++ b/src/animator/SkDisplayBounds.cpp
@@ -0,0 +1,54 @@
+/* libs/graphics/animator/SkDisplayBounds.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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) {
+        SkIRect& rect = maker.fDisplayList.fInvalBounds;
+        maker.fDisplayList.fHasUnion = true;
+        if (rect.isEmpty())
+            rect = fBounds;
+        else 
+            rect.join(fBounds);
+    }
+    return result;
+}
+
+
+
diff --git a/src/animator/SkDisplayBounds.h b/src/animator/SkDisplayBounds.h
new file mode 100644
index 0000000..6fcd09c
--- /dev/null
+++ b/src/animator/SkDisplayBounds.h
@@ -0,0 +1,33 @@
+/* libs/graphics/animator/SkDisplayBounds.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayEvent.cpp b/src/animator/SkDisplayEvent.cpp
new file mode 100644
index 0000000..6253cdf
--- /dev/null
+++ b/src/animator/SkDisplayEvent.cpp
@@ -0,0 +1,339 @@
+/* libs/graphics/animator/SkDisplayEvent.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL) {
+}
+
+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 NULL;
+}
+
+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 != NULL) {
+        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)) != NULL) {
+        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;
+}
+
+#ifdef ANDROID
+
+#include "SkMetaData.h"
+#include "SkParse.h"
+#include "SkTextBox.h"
+#include "SkXMLWriter.h"
+
+void SkMetaData::setPtr(char const*, void* ) {}
+void SkMetaData::setS32(char const*, int ) {}
+bool SkEventSink::doEvent(SkEvent const& ) { return false; }
+bool SkXMLParser::parse(SkStream& ) { return false; }
+SkXMLParserError::SkXMLParserError( ) {}
+void SkEvent::setType(char const*, unsigned long ) {}
+bool SkEvent::PostTime(SkEvent*, unsigned int, unsigned int ) { return false; }
+SkEvent::SkEvent(char const* ) {}
+SkEvent::SkEvent(SkEvent const& ) {}
+SkEvent::SkEvent( ) {}
+SkEvent::~SkEvent( ) {}
+bool SkEventSink::onQuery(SkEvent* ) { return false; }
+SkEventSink::SkEventSink( ) {}
+SkEventSink::~SkEventSink( ) {}
+bool SkXMLParser::parse(char const*, unsigned long ) { return false; }
+bool SkXMLParser::parse(SkDOM const&, SkDOMNode const* ) { return false; }
+bool SkEvent::Post(SkEvent*, unsigned int, unsigned int ) { return false; }
+void SkParse::UnitTest( ) {}
+const char* SkMetaData::findString(char const*) const {return 0;}
+bool SkMetaData::findPtr(char const*, void**) const {return false;}
+bool SkMetaData::findS32(char const*, int*) const {return false;}
+bool SkEvent::isType(char const*, unsigned long) const { return false; }
+void SkMetaData::setString(char const*, char const* ) {}
+const char* SkParse::FindNamedColor(char const*, unsigned long, unsigned int* ) {return false; }
+const char* SkMetaData::Iter::next(SkMetaData::Type*, int* ) { return false; }
+SkMetaData::Iter::Iter(SkMetaData const& ) {}
+bool SkMetaData::findScalar(char const*, int*) const {return false;}
+void SkMetaData::reset( ) {}
+void SkEvent::setType(SkString const& ) {}
+bool SkMetaData::findBool(char const*, bool*) const {return false;}
+void SkEvent::getType(SkString*) const {}
+bool SkXMLParser::endElement(char const* ) { return false; }
+bool SkXMLParser::addAttribute(char const*, char const* ) { return false;}
+bool SkXMLParser::startElement(char const* ) { return false;}
+bool SkXMLParser::text(char const*, int ) { return false;}
+bool SkXMLParser::onText(char const*, int ) { return false;}
+SkXMLParser::SkXMLParser(SkXMLParserError* ) {}
+SkXMLParser::~SkXMLParser( ) {}
+SkXMLParserError::~SkXMLParserError( ) {}
+void SkXMLParserError::getErrorString(SkString*) const {}
+void SkTextBox::setSpacing(int, int ) {}
+void SkTextBox::setSpacingAlign(SkTextBox::SpacingAlign ) {}
+void SkTextBox::draw(SkCanvas*, char const*, unsigned long, SkPaint const& ) {}
+void SkTextBox::setBox(SkRect const& ) {}
+void SkTextBox::setMode(SkTextBox::Mode ) {}
+SkTextBox::SkTextBox( ) {}
+void SkMetaData::setScalar(char const*, int ) {}
+const char* SkParse::FindScalar(char const*, int* ) {return 0; }
+const char* SkParse::FindScalars(char const*, int*, int ) {return 0; }
+const char* SkParse::FindHex(char const*, unsigned int* ) {return 0; }
+const char* SkParse::FindS32(char const*, int* ) {return 0; }
+void SkXMLWriter::addAttribute(char const*, char const* ) {}
+void SkXMLWriter::startElement(char const* ) {}
+void SkXMLWriter::doEnd(SkXMLWriter::Elem* ) {}
+SkXMLWriter::Elem* SkXMLWriter::getEnd( ) { return 0; }
+bool SkXMLWriter::doStart(char const*, unsigned long ) { return false; }
+SkXMLWriter::SkXMLWriter(bool ) {}
+SkXMLWriter::~SkXMLWriter( ) {}
+SkMetaData::SkMetaData() {}
+SkMetaData::~SkMetaData() {}
+bool SkEventSink::onEvent(SkEvent const&) {return false;}
+bool SkXMLParser::onEndElement(char const*) {return false;}
+bool SkXMLParser::onAddAttribute(char const*, char const*) {return false;}
+bool SkXMLParser::onStartElement(char const*) {return false;}
+void SkXMLWriter::writeHeader() {}
+
+#endif
diff --git a/src/animator/SkDisplayEvent.h b/src/animator/SkDisplayEvent.h
new file mode 100644
index 0000000..837cfec
--- /dev/null
+++ b/src/animator/SkDisplayEvent.h
@@ -0,0 +1,75 @@
+/* libs/graphics/animator/SkDisplayEvent.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayEvents.cpp b/src/animator/SkDisplayEvents.cpp
new file mode 100644
index 0000000..e6a01ba
--- /dev/null
+++ b/src/animator/SkDisplayEvents.cpp
@@ -0,0 +1,121 @@
+/* libs/graphics/animator/SkDisplayEvents.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 : NULL;
+    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 != NULL && evt->fTarget != displayable)
+            continue;
+        if (state == NULL || 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 : NULL;
+    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 != NULL && evt->fTarget != displayable)
+            continue;
+        int index = fEvents.find(evt);
+        fEvents.remove(index);
+    }
+}
diff --git a/src/animator/SkDisplayEvents.h b/src/animator/SkDisplayEvents.h
new file mode 100644
index 0000000..73721d4
--- /dev/null
+++ b/src/animator/SkDisplayEvents.h
@@ -0,0 +1,51 @@
+/* libs/graphics/animator/SkDisplayEvents.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayInclude.cpp b/src/animator/SkDisplayInclude.cpp
new file mode 100644
index 0000000..26b1e69
--- /dev/null
+++ b/src/animator/SkDisplayInclude.cpp
@@ -0,0 +1,67 @@
+/* libs/graphics/animator/SkDisplayInclude.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayInclude.h b/src/animator/SkDisplayInclude.h
new file mode 100644
index 0000000..81ad76a
--- /dev/null
+++ b/src/animator/SkDisplayInclude.h
@@ -0,0 +1,34 @@
+/* libs/graphics/animator/SkDisplayInclude.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayInput.cpp b/src/animator/SkDisplayInput.cpp
new file mode 100644
index 0000000..3688930
--- /dev/null
+++ b/src/animator/SkDisplayInput.cpp
@@ -0,0 +1,63 @@
+/* libs/graphics/animator/SkDisplayInput.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 : NULL;
+}
+
+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/src/animator/SkDisplayInput.h b/src/animator/SkDisplayInput.h
new file mode 100644
index 0000000..ac7c7c1
--- /dev/null
+++ b/src/animator/SkDisplayInput.h
@@ -0,0 +1,42 @@
+/* libs/graphics/animator/SkDisplayInput.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayList.cpp b/src/animator/SkDisplayList.cpp
new file mode 100644
index 0000000..57f29f7
--- /dev/null
+++ b/src/animator/SkDisplayList.cpp
@@ -0,0 +1,168 @@
+/* libs/graphics/animator/SkDisplayList.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 = NULL;
+    *list = &fDrawList;
+    *grandList = &fDrawList;
+    return SearchForMatch(match, list, parent, found, grandList);
+}
+
+void SkDisplayList::hardReset() {
+    fDrawList.reset();
+    fActiveList.reset();
+}
+
+bool SkDisplayList::onIRect(const SkIRect& r) {
+    fBounds = r;
+    return fDrawBounds;
+}
+
+int SkDisplayList::SearchForMatch(SkDrawable* match, SkTDDrawableArray** list,
+        SkGroup** parent, SkGroup** found, SkTDDrawableArray**grandList) { 
+    *found = NULL;
+    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/src/animator/SkDisplayList.h b/src/animator/SkDisplayList.h
new file mode 100644
index 0000000..3743e35
--- /dev/null
+++ b/src/animator/SkDisplayList.h
@@ -0,0 +1,79 @@
+/* libs/graphics/animator/SkDisplayList.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 SkIRect& 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:
+    SkIRect fBounds;
+    SkIRect fInvalBounds;
+    bool fDrawBounds;
+    bool fHasUnion;
+    bool fUnionBounds;
+private:
+    SkTDDrawableArray fDrawList;
+    SkTDActiveArray fActiveList;
+    SkMSec fInTime;
+    friend class SkEvents;
+};
+
+#endif // SkDisplayList_DEFINED
+
diff --git a/src/animator/SkDisplayMath.cpp b/src/animator/SkDisplayMath.cpp
new file mode 100644
index 0000000..66bd1f8
--- /dev/null
+++ b/src/animator/SkDisplayMath.cpp
@@ -0,0 +1,248 @@
+/* libs/graphics/animator/SkDisplayMath.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 == NULL)
+        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/src/animator/SkDisplayMath.h b/src/animator/SkDisplayMath.h
new file mode 100644
index 0000000..de26319
--- /dev/null
+++ b/src/animator/SkDisplayMath.h
@@ -0,0 +1,40 @@
+/* libs/graphics/animator/SkDisplayMath.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayMovie.cpp b/src/animator/SkDisplayMovie.cpp
new file mode 100644
index 0000000..ed74329
--- /dev/null
+++ b/src/animator/SkDisplayMovie.cpp
@@ -0,0 +1,138 @@
+/* libs/graphics/animator/SkDisplayMovie.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 == NULL)
+        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, NULL);
+    movieMaker->fEvents.removeEvent(SkDisplayEvent::kOnload, NULL);
+    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/src/animator/SkDisplayMovie.h b/src/animator/SkDisplayMovie.h
new file mode 100644
index 0000000..2b8a893
--- /dev/null
+++ b/src/animator/SkDisplayMovie.h
@@ -0,0 +1,60 @@
+/* libs/graphics/animator/SkDisplayMovie.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayNumber.cpp b/src/animator/SkDisplayNumber.cpp
new file mode 100644
index 0000000..3bb96d7
--- /dev/null
+++ b/src/animator/SkDisplayNumber.cpp
@@ -0,0 +1,67 @@
+/* libs/graphics/animator/SkDisplayNumber.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayNumber.h b/src/animator/SkDisplayNumber.h
new file mode 100644
index 0000000..515c35b
--- /dev/null
+++ b/src/animator/SkDisplayNumber.h
@@ -0,0 +1,30 @@
+/* libs/graphics/animator/SkDisplayNumber.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayPost.cpp b/src/animator/SkDisplayPost.cpp
new file mode 100644
index 0000000..17e7c76
--- /dev/null
+++ b/src/animator/SkDisplayPost.cpp
@@ -0,0 +1,315 @@
+/* libs/graphics/animator/SkDisplayPost.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL),
+    fSinkID(0), fTargetMaker(NULL), 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)) != NULL) {
+        //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") != NULL;
+        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 = NULL;
+        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 == NULL || displayable->getType() != SkType_Movie) {
+                fTargetMaker->setErrorCode(SkDisplayXMLParserError::kExpectedMovie);
+                return;
+            }
+            SkDisplayMovie* movie = (SkDisplayMovie*) displayable;
+            fTargetMaker = movie->fMovie.fMaker;
+        }
+        if (end == NULL)
+            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/src/animator/SkDisplayPost.h b/src/animator/SkDisplayPost.h
new file mode 100644
index 0000000..4b75b07
--- /dev/null
+++ b/src/animator/SkDisplayPost.h
@@ -0,0 +1,67 @@
+/* libs/graphics/animator/SkDisplayPost.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayRandom.cpp b/src/animator/SkDisplayRandom.cpp
new file mode 100644
index 0000000..ab078cd
--- /dev/null
+++ b/src/animator/SkDisplayRandom.cpp
@@ -0,0 +1,80 @@
+/* libs/graphics/animator/SkDisplayRandom.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 = SkUnitCubicInterp(random, SK_Scalar1 - blend, 0, 0, SK_Scalar1 - 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/src/animator/SkDisplayRandom.h b/src/animator/SkDisplayRandom.h
new file mode 100644
index 0000000..b40907e
--- /dev/null
+++ b/src/animator/SkDisplayRandom.h
@@ -0,0 +1,49 @@
+/* libs/graphics/animator/SkDisplayRandom.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayScreenplay.cpp b/src/animator/SkDisplayScreenplay.cpp
new file mode 100644
index 0000000..58180e7
--- /dev/null
+++ b/src/animator/SkDisplayScreenplay.cpp
@@ -0,0 +1,30 @@
+/* libs/graphics/animator/SkDisplayScreenplay.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayScreenplay.h b/src/animator/SkDisplayScreenplay.h
new file mode 100644
index 0000000..cb8103d
--- /dev/null
+++ b/src/animator/SkDisplayScreenplay.h
@@ -0,0 +1,29 @@
+/* libs/graphics/animator/SkDisplayScreenplay.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayType.cpp b/src/animator/SkDisplayType.cpp
new file mode 100644
index 0000000..90fcd89
--- /dev/null
+++ b/src/animator/SkDisplayType.cpp
@@ -0,0 +1,774 @@
+/* libs/graphics/animator/SkDisplayType.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayType.h b/src/animator/SkDisplayType.h
new file mode 100644
index 0000000..a29b285
--- /dev/null
+++ b/src/animator/SkDisplayType.h
@@ -0,0 +1,216 @@
+/* libs/graphics/animator/SkDisplayType.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#ifndef SkDisplayType_DEFINED
+#define SkDisplayType_DEFINED
+
+#include "SkMath.h"
+#include "SkScalar.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/src/animator/SkDisplayTypes.cpp b/src/animator/SkDisplayTypes.cpp
new file mode 100644
index 0000000..b5bc573
--- /dev/null
+++ b/src/animator/SkDisplayTypes.cpp
@@ -0,0 +1,229 @@
+/* libs/graphics/animator/SkDisplayTypes.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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
+
+// int32_t
+#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 == NULL)
+        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 = (int32_t) 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/src/animator/SkDisplayTypes.h b/src/animator/SkDisplayTypes.h
new file mode 100644
index 0000000..0ac57ba
--- /dev/null
+++ b/src/animator/SkDisplayTypes.h
@@ -0,0 +1,115 @@
+/* libs/graphics/animator/SkDisplayTypes.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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:
+    int32_t 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/src/animator/SkDisplayXMLParser.cpp b/src/animator/SkDisplayXMLParser.cpp
new file mode 100644
index 0000000..d2775e8
--- /dev/null
+++ b/src/animator/SkDisplayXMLParser.cpp
@@ -0,0 +1,318 @@
+/* libs/graphics/animator/SkDisplayXMLParser.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL)
+{
+}
+
+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 == NULL)    // 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, NULL)) {
+            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 == NULL) {
+        fError->setNoun(name);
+        fError->setCode(SkXMLParserError::kUnknownAttributeName);
+        return true;
+    }
+    if (info->setValue(fMaker, NULL, 0, info->getCount(), displayable, info->getType(), attrValue,
+            attrValueLen))
+        return false;
+    if (fMaker.fError.hasError()) {
+        fError->setNoun(attrValue, attrValueLen);
+        return true;
+    }
+    SkDisplayable* ref = NULL;
+    if (fMaker.find(attrValue, attrValueLen, &ref) == false) {
+        ref = fMaker.createInstance(attrValue, attrValueLen);
+        if (ref == NULL) {
+            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)) != NULL) {
+                    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 = NULL;
+    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, NULL);
+            if (fMaker.fError.hasError()) 
+                return true;
+            fMaker.fEvents.removeEvent(SkDisplayEvent::kOnload, NULL);
+
+        }
+        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 = NULL; // 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 == NULL) {
+        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 = NULL;
+    const SkMemberInfo* lastResort = NULL;
+    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 != NULL)
+                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 NULL;
+}
+
+
diff --git a/src/animator/SkDisplayXMLParser.h b/src/animator/SkDisplayXMLParser.h
new file mode 100644
index 0000000..2c2bec1
--- /dev/null
+++ b/src/animator/SkDisplayXMLParser.h
@@ -0,0 +1,101 @@
+/* libs/graphics/animator/SkDisplayXMLParser.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDisplayable.cpp b/src/animator/SkDisplayable.cpp
new file mode 100644
index 0000000..e50e1ab
--- /dev/null
+++ b/src/animator/SkDisplayable.cpp
@@ -0,0 +1,566 @@
+/* libs/graphics/animator/SkDisplayable.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 NULL;
+}
+
+SkDisplayable* SkDisplayable::deepCopy(SkAnimateMaker* maker) {
+    SkDisplayTypes type = getType();
+    if (type == SkType_Unknown) {
+        SkASSERT(0);
+        return NULL;
+    }
+    SkDisplayable* copy = SkDisplayType::CreateInstance(maker, type);
+    int index = -1;
+    int propIndex = 0;
+    const SkMemberInfo* info;
+    do {
+        info = copy->getMember(++index);
+        if (info == NULL)
+            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 == NULL || (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 == NULL || *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 (NULL == 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 == NULL || (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 (NULL == info) {
+            break;
+        }
+        if (SkDisplayType::IsDisplayable(maker, info->fType)) {
+            SkDisplayable** displayable = (SkDisplayable**) info->memberData(this);
+            if (*displayable == NULL || *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 NULL;
+}
+
+const SkMemberInfo* SkDisplayable::getMember(int index) { 
+    return NULL; 
+}
+
+const SkMemberInfo* SkDisplayable::getMember(const char name[]) { 
+    return NULL; 
+}
+
+const SkFunctionParamType* SkDisplayable::getParameters(const SkMemberInfo* info, 
+        int* paramCount) {
+    const SkFunctionParamType* params = getFunctionsParameters();
+    SkASSERT(params != NULL);
+    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 &params[offset - count];
+}
+
+SkDisplayable* SkDisplayable::getParent() const {
+    return NULL;
+}
+
+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 NULL;
+}
+
+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/src/animator/SkDisplayable.h b/src/animator/SkDisplayable.h
new file mode 100644
index 0000000..cbc96de
--- /dev/null
+++ b/src/animator/SkDisplayable.h
@@ -0,0 +1,120 @@
+/* libs/graphics/animator/SkDisplayable.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDraw3D.cpp b/src/animator/SkDraw3D.cpp
new file mode 100644
index 0000000..137de9f
--- /dev/null
+++ b/src/animator/SkDraw3D.cpp
@@ -0,0 +1,117 @@
+/* libs/graphics/animator/SkDraw3D.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL) {
+}
+
+Sk3D_Camera::~Sk3D_Camera() {
+}
+
+bool Sk3D_Camera::draw(SkAnimateMaker& maker) {
+    fCamera.update();
+    SkMatrix matrix;
+    fCamera.patchToMatrix(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/src/animator/SkDraw3D.h b/src/animator/SkDraw3D.h
new file mode 100644
index 0000000..5ab61cd
--- /dev/null
+++ b/src/animator/SkDraw3D.h
@@ -0,0 +1,59 @@
+/* libs/graphics/animator/SkDraw3D.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawBitmap.cpp b/src/animator/SkDrawBitmap.cpp
new file mode 100644
index 0000000..25355be
--- /dev/null
+++ b/src/animator/SkDrawBitmap.cpp
@@ -0,0 +1,206 @@
+/* libs/graphics/animator/SkDrawBitmap.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL) {
+    base64.fData = NULL;
+    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());
+        SkStream* stream = new SkFILEStream(src.c_str());
+
+        SkAutoTDelete<SkStream> autoDel(stream);
+        SkImageDecoder::DecodeStream(stream, &fBitmap);
+    }   
+}
diff --git a/src/animator/SkDrawBitmap.h b/src/animator/SkDrawBitmap.h
new file mode 100644
index 0000000..f846193
--- /dev/null
+++ b/src/animator/SkDrawBitmap.h
@@ -0,0 +1,82 @@
+/* libs/graphics/animator/SkDrawBitmap.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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;
+    int32_t height;
+    int32_t rowBytes;
+    int32_t 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/src/animator/SkDrawBlur.cpp b/src/animator/SkDrawBlur.cpp
new file mode 100644
index 0000000..0ebabce
--- /dev/null
+++ b/src/animator/SkDrawBlur.cpp
@@ -0,0 +1,40 @@
+/* libs/graphics/animator/SkDrawBlur.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 NULL;
+    return SkBlurMaskFilter::Create(radius, (SkBlurMaskFilter::BlurStyle) blurStyle);
+}
+
diff --git a/src/animator/SkDrawBlur.h b/src/animator/SkDrawBlur.h
new file mode 100644
index 0000000..14ceba0
--- /dev/null
+++ b/src/animator/SkDrawBlur.h
@@ -0,0 +1,34 @@
+/* libs/graphics/animator/SkDrawBlur.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawClip.cpp b/src/animator/SkDrawClip.cpp
new file mode 100644
index 0000000..1c01c6a
--- /dev/null
+++ b/src/animator/SkDrawClip.cpp
@@ -0,0 +1,48 @@
+/* libs/graphics/animator/SkDrawClip.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL), path(NULL) {
+}
+
+bool SkDrawClip::draw(SkAnimateMaker& maker ) {
+    if (rect != NULL)
+        maker.fCanvas->clipRect(rect->fRect);
+    else {
+        SkASSERT(path != NULL);
+        maker.fCanvas->clipPath(path->fPath);
+    }
+    return false;
+}
+
diff --git a/src/animator/SkDrawClip.h b/src/animator/SkDrawClip.h
new file mode 100644
index 0000000..2fed99a
--- /dev/null
+++ b/src/animator/SkDrawClip.h
@@ -0,0 +1,37 @@
+/* libs/graphics/animator/SkDrawClip.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawColor.cpp b/src/animator/SkDrawColor.cpp
new file mode 100644
index 0000000..009ca10
--- /dev/null
+++ b/src/animator/SkDrawColor.cpp
@@ -0,0 +1,278 @@
+/* libs/graphics/animator/SkDrawColor.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 != NULL)
+        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 != NULL);
+    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):
+            uint8_t 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/src/animator/SkDrawColor.h b/src/animator/SkDrawColor.h
new file mode 100644
index 0000000..89b87cc
--- /dev/null
+++ b/src/animator/SkDrawColor.h
@@ -0,0 +1,50 @@
+/* libs/graphics/animator/SkDrawColor.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawDash.cpp b/src/animator/SkDrawDash.cpp
new file mode 100644
index 0000000..bdac9cd
--- /dev/null
+++ b/src/animator/SkDrawDash.cpp
@@ -0,0 +1,44 @@
+/* libs/graphics/animator/SkDrawDash.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 NULL;
+    return new SkDashPathEffect(intervals.begin(), count, phase);
+}
+
diff --git a/src/animator/SkDrawDash.h b/src/animator/SkDrawDash.h
new file mode 100644
index 0000000..c2108c1
--- /dev/null
+++ b/src/animator/SkDrawDash.h
@@ -0,0 +1,35 @@
+/* libs/graphics/animator/SkDrawDash.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawDiscrete.cpp b/src/animator/SkDrawDiscrete.cpp
new file mode 100644
index 0000000..e1089c2
--- /dev/null
+++ b/src/animator/SkDrawDiscrete.cpp
@@ -0,0 +1,43 @@
+/* libs/graphics/animator/SkDrawDiscrete.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 NULL;
+    else
+        return new SkDiscretePathEffect(segLength, deviation);
+}
+
diff --git a/src/animator/SkDrawDiscrete.h b/src/animator/SkDrawDiscrete.h
new file mode 100644
index 0000000..78485ee
--- /dev/null
+++ b/src/animator/SkDrawDiscrete.h
@@ -0,0 +1,32 @@
+/* libs/graphics/animator/SkDrawDiscrete.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawEmboss.cpp b/src/animator/SkDrawEmboss.cpp
new file mode 100644
index 0000000..77f6dfd
--- /dev/null
+++ b/src/animator/SkDrawEmboss.cpp
@@ -0,0 +1,42 @@
+/* libs/graphics/animator/SkDrawEmboss.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 NULL;
+    return SkBlurMaskFilter::CreateEmboss(direction.begin(), ambient, specular, radius);
+}
+
diff --git a/src/animator/SkDrawEmboss.h b/src/animator/SkDrawEmboss.h
new file mode 100644
index 0000000..fe6911b
--- /dev/null
+++ b/src/animator/SkDrawEmboss.h
@@ -0,0 +1,33 @@
+/* libs/graphics/animator/SkDrawEmboss.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawExtraPathEffect.cpp b/src/animator/SkDrawExtraPathEffect.cpp
new file mode 100644
index 0000000..4cca738
--- /dev/null
+++ b/src/animator/SkDrawExtraPathEffect.cpp
@@ -0,0 +1,519 @@
+/* libs/graphics/animator/SkDrawExtraPathEffect.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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, NULL, 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(SkPath* dst, SkScalar distance, SkPathMeasure& )
+    {
+        fMaker->setExtraPropertyCallBack(fDraw->fType, GetDistance, &distance);
+        SkDrawPath* drawPath = NULL;
+        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;
+        m.reset();
+        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, NULL, fDraw->spacing.c_str(), &result);
+        if (drawPath)
+            dst->addPath(drawPath->getPath(), m);
+        fMaker->clearExtraPropertyCallBack(fDraw->fType);
+        return result;
+    }
+
+private:
+    virtual void flatten(SkFlattenableWriteBuffer& ) {}
+    virtual Factory getFactory() { return NULL; }
+
+    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(NULL), addMatrix(NULL), path(NULL), fPathEffect(NULL) {
+}
+
+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 == NULL || (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 SkIRect& 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 == NULL)
+            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;
+    int32_t fU;
+    int32_t 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 == NULL || (addPath->isPath() == false && addPath->isApply() == false) ||
+            matrix == NULL)
+        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(NULL), effect2(NULL) {
+}
+
+SkDrawComposePathEffect::~SkDrawComposePathEffect() {
+    delete effect1;
+    delete effect2;
+}
+
+bool SkDrawComposePathEffect::add(SkAnimateMaker& , SkDisplayable* child) {
+    if (effect1 == NULL)
+        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 = NULL;
+        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 = NULL;
+        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 = NULL;
+        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(NULL), fExtraStorage(NULL) {
+}
diff --git a/src/animator/SkDrawFull.cpp b/src/animator/SkDrawFull.cpp
new file mode 100644
index 0000000..c6568db
--- /dev/null
+++ b/src/animator/SkDrawFull.cpp
@@ -0,0 +1,27 @@
+/* libs/graphics/animator/SkDrawFull.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawFull.h b/src/animator/SkDrawFull.h
new file mode 100644
index 0000000..cfbb643
--- /dev/null
+++ b/src/animator/SkDrawFull.h
@@ -0,0 +1,30 @@
+/* libs/graphics/animator/SkDrawFull.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawGradient.cpp b/src/animator/SkDrawGradient.cpp
new file mode 100644
index 0000000..e9061b5
--- /dev/null
+++ b/src/animator/SkDrawGradient.cpp
@@ -0,0 +1,235 @@
+/* libs/graphics/animator/SkDrawGradient.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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) {
+    }
+    
+    // overrides for SkFlattenable
+    virtual Factory getFactory() { return NULL; }
+    
+protected:
+    virtual uint16_t mapUnit16(uint16_t x) {
+        fUnit = SkUnitToScalar(x);
+        SkScriptValue value;
+        SkAnimatorScript engine(*fMaker, NULL, 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(NULL) {
+}
+
+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 NULL;
+    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 NULL;
+    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/src/animator/SkDrawGradient.h b/src/animator/SkDrawGradient.h
new file mode 100644
index 0000000..30a86df
--- /dev/null
+++ b/src/animator/SkDrawGradient.h
@@ -0,0 +1,76 @@
+/* libs/graphics/animator/SkDrawGradient.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawGroup.cpp b/src/animator/SkDrawGroup.cpp
new file mode 100644
index 0000000..aa53564
--- /dev/null
+++ b/src/animator/SkDrawGroup.cpp
@@ -0,0 +1,331 @@
+/* libs/graphics/animator/SkDrawGroup.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL), fOriginal(NULL) {
+}
+
+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 == NULL);
+        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/src/animator/SkDrawGroup.h b/src/animator/SkDrawGroup.h
new file mode 100644
index 0000000..0009a4c
--- /dev/null
+++ b/src/animator/SkDrawGroup.h
@@ -0,0 +1,80 @@
+/* libs/graphics/animator/SkDrawGroup.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 != NULL; }
+    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/src/animator/SkDrawLine.cpp b/src/animator/SkDrawLine.cpp
new file mode 100644
index 0000000..166cbbc
--- /dev/null
+++ b/src/animator/SkDrawLine.cpp
@@ -0,0 +1,43 @@
+/* libs/graphics/animator/SkDrawLine.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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) {
+    SkBoundableAuto boundable(this, maker);
+    maker.fCanvas->drawLine(x1, y1, x2, y2, *maker.fPaint);
+    return false;
+}
diff --git a/src/animator/SkDrawLine.h b/src/animator/SkDrawLine.h
new file mode 100644
index 0000000..8f771cf
--- /dev/null
+++ b/src/animator/SkDrawLine.h
@@ -0,0 +1,37 @@
+/* libs/graphics/animator/SkDrawLine.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawMatrix.cpp b/src/animator/SkDrawMatrix.cpp
new file mode 100644
index 0000000..dbdbf19
--- /dev/null
+++ b/src/animator/SkDrawMatrix.cpp
@@ -0,0 +1,290 @@
+/* libs/graphics/animator/SkDrawMatrix.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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[SkMatrix::kMScaleX];
+    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/src/animator/SkDrawMatrix.h b/src/animator/SkDrawMatrix.h
new file mode 100644
index 0000000..8339d8c
--- /dev/null
+++ b/src/animator/SkDrawMatrix.h
@@ -0,0 +1,82 @@
+/* libs/graphics/animator/SkDrawMatrix.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawOval.cpp b/src/animator/SkDrawOval.cpp
new file mode 100644
index 0000000..0e3a9ae
--- /dev/null
+++ b/src/animator/SkDrawOval.cpp
@@ -0,0 +1,37 @@
+/* libs/graphics/animator/SkDrawOval.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawOval.h b/src/animator/SkDrawOval.h
new file mode 100644
index 0000000..0e7ae3f
--- /dev/null
+++ b/src/animator/SkDrawOval.h
@@ -0,0 +1,31 @@
+/* libs/graphics/animator/SkDrawOval.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawPaint.cpp b/src/animator/SkDrawPaint.cpp
new file mode 100644
index 0000000..68caa5a
--- /dev/null
+++ b/src/animator/SkDrawPaint.cpp
@@ -0,0 +1,277 @@
+/* libs/graphics/animator/SkDrawPaint.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(filterBitmap, Boolean),
+    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), filterBitmap(-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 {
+    SkPaint::FontMetrics    metrics;
+    SkPaint paint;
+    setupPaint(&paint);
+    paint.getFontMetrics(&metrics);
+    switch (index) {
+        case SK_PROPERTY(ascent):
+            value->fOperand.fScalar = metrics.fAscent;
+            break;
+        case SK_PROPERTY(descent):
+            value->fOperand.fScalar = metrics.fDescent;
+            break;
+        // should consider returning fLeading as well (or roll it into ascent/descent somehow 
+        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->setAntiAlias(SkToBool(antiAlias));
+    if (color != NULL)
+        paint->setColor(color->getColor());
+    if (fakeBold != -1)
+        paint->setFakeBoldText(SkToBool(fakeBold));
+    if (filterBitmap != -1)
+        paint->setFilterBitmap(SkToBool(filterBitmap));
+    //  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->setLinearText(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->setStrikeThruText(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->setUnderlineText(SkToBool(underline));
+    if (xfermode != (SkPorterDuff::Mode) -1) 
+        paint->setPorterDuffXfermode((SkPorterDuff::Mode) xfermode);
+}
diff --git a/src/animator/SkDrawPaint.h b/src/animator/SkDrawPaint.h
new file mode 100644
index 0000000..ea77acd
--- /dev/null
+++ b/src/animator/SkDrawPaint.h
@@ -0,0 +1,88 @@
+/* libs/graphics/animator/SkDrawPaint.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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;
+    SkBool filterBitmap;
+    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/src/animator/SkDrawPath.cpp b/src/animator/SkDrawPath.cpp
new file mode 100644
index 0000000..895e597
--- /dev/null
+++ b/src/animator/SkDrawPath.cpp
@@ -0,0 +1,229 @@
+/* libs/graphics/animator/SkDrawPath.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 = NULL;
+    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/src/animator/SkDrawPath.h b/src/animator/SkDrawPath.h
new file mode 100644
index 0000000..673051a
--- /dev/null
+++ b/src/animator/SkDrawPath.h
@@ -0,0 +1,77 @@
+/* libs/graphics/animator/SkDrawPath.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawPoint.cpp b/src/animator/SkDrawPoint.cpp
new file mode 100644
index 0000000..383a599
--- /dev/null
+++ b/src/animator/SkDrawPoint.cpp
@@ -0,0 +1,54 @@
+/* libs/graphics/animator/SkDrawPoint.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawPoint.h b/src/animator/SkDrawPoint.h
new file mode 100644
index 0000000..d06e5b7
--- /dev/null
+++ b/src/animator/SkDrawPoint.h
@@ -0,0 +1,41 @@
+/* libs/graphics/animator/SkDrawPoint.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawRectangle.cpp b/src/animator/SkDrawRectangle.cpp
new file mode 100644
index 0000000..f2054bd
--- /dev/null
+++ b/src/animator/SkDrawRectangle.cpp
@@ -0,0 +1,153 @@
+/* libs/graphics/animator/SkDrawRectangle.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL) { 
+    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/src/animator/SkDrawRectangle.h b/src/animator/SkDrawRectangle.h
new file mode 100644
index 0000000..9f8bc0a
--- /dev/null
+++ b/src/animator/SkDrawRectangle.h
@@ -0,0 +1,64 @@
+/* libs/graphics/animator/SkDrawRectangle.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawSaveLayer.cpp b/src/animator/SkDrawSaveLayer.cpp
new file mode 100644
index 0000000..bc2288f
--- /dev/null
+++ b/src/animator/SkDrawSaveLayer.cpp
@@ -0,0 +1,86 @@
+/* libs/graphics/animator/SkDrawSaveLayer.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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, SkCanvas::kHasAlphaLayer_SaveFlag);
+    }
+    else
+        maker.fCanvas->saveLayer(&bounds->fRect, save, SkCanvas::kHasAlphaLayer_SaveFlag);
+    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);
+}
+
+
diff --git a/src/animator/SkDrawSaveLayer.h b/src/animator/SkDrawSaveLayer.h
new file mode 100644
index 0000000..52a36a4
--- /dev/null
+++ b/src/animator/SkDrawSaveLayer.h
@@ -0,0 +1,44 @@
+/* libs/graphics/animator/SkDrawSaveLayer.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawShader.cpp b/src/animator/SkDrawShader.cpp
new file mode 100644
index 0000000..b38718e
--- /dev/null
+++ b/src/animator/SkDrawShader.cpp
@@ -0,0 +1,91 @@
+/* libs/graphics/animator/SkDrawShader.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL), 
+    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(filterBitmap, Boolean),
+    SK_MEMBER(image, BaseBitmap)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawBitmapShader);
+
+SkDrawBitmapShader::SkDrawBitmapShader() : filterBitmap(-1), image(NULL) {}
+
+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")
+    // 
+    // oops, bitmapshader no longer takes filterBitmap, but deduces it at
+    // draw-time from the paint 
+    SkShader* shader  = SkShader::CreateBitmapShader(image->fBitmap, 
+                                                    (SkShader::TileMode) tileMode,
+                                                    (SkShader::TileMode) tileMode);
+    SkAutoTDelete<SkShader> autoDel(shader);
+    addPostlude(shader);
+    (void)autoDel.detach();
+    return shader;
+}
diff --git a/src/animator/SkDrawShader.h b/src/animator/SkDrawShader.h
new file mode 100644
index 0000000..35ca419
--- /dev/null
+++ b/src/animator/SkDrawShader.h
@@ -0,0 +1,38 @@
+/* libs/graphics/animator/SkDrawShader.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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:
+    SkBool filterBitmap;
+    SkBaseBitmap* image;
+private:
+    typedef SkDrawShader INHERITED;
+};
+
+#endif // SkDrawShader_DEFINED
diff --git a/src/animator/SkDrawText.cpp b/src/animator/SkDrawText.cpp
new file mode 100644
index 0000000..dcc3a75
--- /dev/null
+++ b/src/animator/SkDrawText.cpp
@@ -0,0 +1,64 @@
+/* libs/graphics/animator/SkDrawText.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 = (int32_t) text.size();
+    return true;
+}
+
diff --git a/src/animator/SkDrawText.h b/src/animator/SkDrawText.h
new file mode 100644
index 0000000..cb1d1b9
--- /dev/null
+++ b/src/animator/SkDrawText.h
@@ -0,0 +1,44 @@
+/* libs/graphics/animator/SkDrawText.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawTextBox.cpp b/src/animator/SkDrawTextBox.cpp
new file mode 100644
index 0000000..4c4ac76
--- /dev/null
+++ b/src/animator/SkDrawTextBox.cpp
@@ -0,0 +1,90 @@
+/* libs/graphics/animator/SkDrawTextBox.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawTextBox.h b/src/animator/SkDrawTextBox.h
new file mode 100644
index 0000000..ee97c22
--- /dev/null
+++ b/src/animator/SkDrawTextBox.h
@@ -0,0 +1,47 @@
+/* libs/graphics/animator/SkDrawTextBox.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawTo.cpp b/src/animator/SkDrawTo.cpp
new file mode 100644
index 0000000..342f7d4
--- /dev/null
+++ b/src/animator/SkDrawTo.cpp
@@ -0,0 +1,64 @@
+/* libs/graphics/animator/SkDrawTo.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL), 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/src/animator/SkDrawTo.h b/src/animator/SkDrawTo.h
new file mode 100644
index 0000000..0ad78e8
--- /dev/null
+++ b/src/animator/SkDrawTo.h
@@ -0,0 +1,42 @@
+/* libs/graphics/animator/SkDrawTo.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawTransparentShader.cpp b/src/animator/SkDrawTransparentShader.cpp
new file mode 100644
index 0000000..c1da687
--- /dev/null
+++ b/src/animator/SkDrawTransparentShader.cpp
@@ -0,0 +1,24 @@
+/* libs/graphics/animator/SkDrawTransparentShader.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include "SkDrawTransparentShader.h"
+#include "SkTransparentShader.h"
+
+SkShader* SkDrawTransparentShader::getShader() {
+    return new SkTransparentShader();
+}
+
diff --git a/src/animator/SkDrawTransparentShader.h b/src/animator/SkDrawTransparentShader.h
new file mode 100644
index 0000000..e831883
--- /dev/null
+++ b/src/animator/SkDrawTransparentShader.h
@@ -0,0 +1,29 @@
+/* libs/graphics/animator/SkDrawTransparentShader.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawable.cpp b/src/animator/SkDrawable.cpp
new file mode 100644
index 0000000..6968fe1
--- /dev/null
+++ b/src/animator/SkDrawable.cpp
@@ -0,0 +1,33 @@
+/* libs/graphics/animator/SkDrawable.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDrawable.h b/src/animator/SkDrawable.h
new file mode 100644
index 0000000..7284a25
--- /dev/null
+++ b/src/animator/SkDrawable.h
@@ -0,0 +1,36 @@
+/* libs/graphics/animator/SkDrawable.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkDump.cpp b/src/animator/SkDump.cpp
new file mode 100644
index 0000000..eac956c
--- /dev/null
+++ b/src/animator/SkDump.cpp
@@ -0,0 +1,158 @@
+/* libs/graphics/animator/SkDump.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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, NULL, 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 == NULL) {
+            result->reset();
+            result->appendS32(badEnum);
+            return;
+        }
+        str += 1;
+    }
+    const char* end = strchr(str, '|');
+    if (end == NULL)
+        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/src/animator/SkDump.h b/src/animator/SkDump.h
new file mode 100644
index 0000000..73a6957
--- /dev/null
+++ b/src/animator/SkDump.h
@@ -0,0 +1,51 @@
+/* libs/graphics/animator/SkDump.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkExtraPathEffects.xsd b/src/animator/SkExtraPathEffects.xsd
new file mode 100644
index 0000000..9592443
--- /dev/null
+++ b/src/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/src/animator/SkExtras.h b/src/animator/SkExtras.h
new file mode 100644
index 0000000..88e9b2d
--- /dev/null
+++ b/src/animator/SkExtras.h
@@ -0,0 +1,42 @@
+/* libs/graphics/animator/SkExtras.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkGetCondensedInfo.cpp b/src/animator/SkGetCondensedInfo.cpp
new file mode 100644
index 0000000..ee91caa
--- /dev/null
+++ b/src/animator/SkGetCondensedInfo.cpp
@@ -0,0 +1,130 @@
+/* libs/graphics/animator/SkGetCondensedInfo.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 NULL;
+    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 != NULL)
+            return result;
+        if (--count == 0)
+            return NULL;
+        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 NULL;
+    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 != NULL)
+            return result;
+        if (--count == 0)
+            return NULL;
+        info++;
+    }
+    SkASSERT(info->fType != SkType_BaseClassInfo);
+    if (*index >= count) {
+        *index -= count;
+        return NULL;
+    }
+    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/src/animator/SkHitClear.cpp b/src/animator/SkHitClear.cpp
new file mode 100644
index 0000000..e7e301d
--- /dev/null
+++ b/src/animator/SkHitClear.cpp
@@ -0,0 +1,41 @@
+/* libs/graphics/animator/SkHitClear.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkHitClear.h b/src/animator/SkHitClear.h
new file mode 100644
index 0000000..f2b50c0
--- /dev/null
+++ b/src/animator/SkHitClear.h
@@ -0,0 +1,33 @@
+/* libs/graphics/animator/SkHitClear.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkHitTest.cpp b/src/animator/SkHitTest.cpp
new file mode 100644
index 0000000..585249a
--- /dev/null
+++ b/src/animator/SkHitTest.cpp
@@ -0,0 +1,83 @@
+/* libs/graphics/animator/SkHitTest.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 == (int16_t)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/src/animator/SkHitTest.h b/src/animator/SkHitTest.h
new file mode 100644
index 0000000..b3a9d85
--- /dev/null
+++ b/src/animator/SkHitTest.h
@@ -0,0 +1,38 @@
+/* libs/graphics/animator/SkHitTest.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkIntArray.h b/src/animator/SkIntArray.h
new file mode 100644
index 0000000..b2a49c1
--- /dev/null
+++ b/src/animator/SkIntArray.h
@@ -0,0 +1,66 @@
+/* libs/graphics/animator/SkIntArray.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkMatrixParts.cpp b/src/animator/SkMatrixParts.cpp
new file mode 100644
index 0000000..56bb2d0
--- /dev/null
+++ b/src/animator/SkMatrixParts.cpp
@@ -0,0 +1,302 @@
+/* libs/graphics/animator/SkMatrixParts.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include "SkMatrixParts.h"
+#include "SkAnimateMaker.h"
+#include "SkDrawMatrix.h"
+#include "SkDrawRectangle.h"
+#include "SkDrawPath.h"
+
+SkMatrixPart::SkMatrixPart() : fMatrix(NULL) {
+}
+
+void SkMatrixPart::dirty() { 
+    fMatrix->dirty(); 
+}
+
+SkDisplayable* SkMatrixPart::getParent() const {
+    return fMatrix;
+}
+
+bool SkMatrixPart::setParent(SkDisplayable* parent) {
+    SkASSERT(parent != NULL);
+    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(NULL) {
+}
+
+SkFromPath::~SkFromPath() {
+}
+
+bool SkFromPath::add() {
+    if (path == NULL)
+        return true;
+    static const uint8_t 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(NULL), destination(NULL) {
+}
+
+SkRectToRect::~SkRectToRect() {
+}
+
+bool SkRectToRect::add() {
+    if (source == NULL || destination == NULL)
+        return true;
+    SkMatrix temp;
+    temp.setRectToRect(source->fRect, destination->fRect,
+                       SkMatrix::kFill_ScaleToFit);
+    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 == NULL)
+        return getMember("source"); // !!! cwap! need to refer to member through enum like kScope instead
+    else {
+        SkASSERT(destination == NULL);
+        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(NULL), destination(NULL) {
+}
+
+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(src, dst, 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 == NULL)
+        return getMember("source"); // !!! cwap! need to refer to member through enum like kScope instead
+    else {
+        SkASSERT(destination == NULL);
+        return getMember("destination");
+    }
+}
+
+
diff --git a/src/animator/SkMatrixParts.h b/src/animator/SkMatrixParts.h
new file mode 100644
index 0000000..d97d9fb
--- /dev/null
+++ b/src/animator/SkMatrixParts.h
@@ -0,0 +1,127 @@
+/* libs/graphics/animator/SkMatrixParts.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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();
+    int32_t 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/src/animator/SkMemberInfo.cpp b/src/animator/SkMemberInfo.cpp
new file mode 100644
index 0000000..50536c2
--- /dev/null
+++ b/src/animator/SkMemberInfo.cpp
@@ -0,0 +1,568 @@
+/* libs/graphics/animator/SkMemberInfo.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(int32_t);
+            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 == NULL)
+                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 = NULL;
+    bool success = true;
+    void* untypedStorage = NULL;
+    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(), '#')) != NULL) {
+            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() : NULL;
+    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, NULL);
+        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 != NULL &&
+            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(NULL /* !!! 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 != NULL)
+            return result;
+        if (--count == 0)
+            return NULL;
+        info++;
+    }
+    SkASSERT(info->fName);
+    SkASSERT(info->fType != SkType_BaseClassInfo);
+    if (*index >= count) {
+        *index -= count;
+        return NULL;
+    }
+    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 != NULL)
+            return result;
+        if (--count == 0)
+            return NULL;
+        info++;
+    }
+    SkASSERT(info->fName);
+    SkASSERT(info->fType != SkType_BaseClassInfo);
+    int index = SkStrSearch(&info->fName, count, match, sizeof(*info));
+    if (index < 0 || index >= count)
+        return NULL;
+    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/src/animator/SkMemberInfo.h b/src/animator/SkMemberInfo.h
new file mode 100644
index 0000000..e45994e
--- /dev/null
+++ b/src/animator/SkMemberInfo.h
@@ -0,0 +1,283 @@
+/* libs/graphics/animator/SkMemberInfo.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 NULL 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(NULL, SkType_##_type, &index); } \
+    virtual const SkMemberInfo* getMember(const char name[]) { \
+        return SkDisplayType::GetMember(NULL, 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(NULL, SkType_##_type, &index); } \
+    virtual const SkMemberInfo* getMember(const char name[]) { \
+        return SkDisplayType::GetMember(NULL, 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(NULL, SkType_##_type, &index); } \
+    virtual const SkMemberInfo* getMember(const char name[]) { \
+        return SkDisplayType::GetMember(NULL, 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(NULL, SkType_##_type, &index); } \
+    virtual const SkMemberInfo* getMember(const char name[]) { \
+        return SkDisplayType::GetMember(NULL, 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/src/animator/SkOpArray.cpp b/src/animator/SkOpArray.cpp
new file mode 100644
index 0000000..eb3fcec
--- /dev/null
+++ b/src/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/src/animator/SkOpArray.h b/src/animator/SkOpArray.h
new file mode 100644
index 0000000..5c511c0
--- /dev/null
+++ b/src/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/src/animator/SkOperand.h b/src/animator/SkOperand.h
new file mode 100644
index 0000000..2c7e93b
--- /dev/null
+++ b/src/animator/SkOperand.h
@@ -0,0 +1,54 @@
+/* libs/graphics/animator/SkOperand.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkOperand2.h b/src/animator/SkOperand2.h
new file mode 100644
index 0000000..f482e66
--- /dev/null
+++ b/src/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/src/animator/SkOperandInterpolator.h b/src/animator/SkOperandInterpolator.h
new file mode 100644
index 0000000..f155276
--- /dev/null
+++ b/src/animator/SkOperandInterpolator.h
@@ -0,0 +1,56 @@
+/* libs/graphics/animator/SkOperandInterpolator.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkOperandIterpolator.cpp b/src/animator/SkOperandIterpolator.cpp
new file mode 100644
index 0000000..2bddd34
--- /dev/null
+++ b/src/animator/SkOperandIterpolator.cpp
@@ -0,0 +1,159 @@
+/* libs/graphics/animator/SkOperandIterpolator.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 != NULL);
+    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[0] = SK_Scalar1 - blend;
+        timeCode->fBlend[1] = 0;
+        timeCode->fBlend[2] = 0;
+        timeCode->fBlend[3] = SK_Scalar1 - 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) {
+                    int32_t a = prevSrc[i].fS32;
+                    int32_t 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/src/animator/SkPaintParts.cpp b/src/animator/SkPaintParts.cpp
new file mode 100644
index 0000000..48799c6
--- /dev/null
+++ b/src/animator/SkPaintParts.cpp
@@ -0,0 +1,111 @@
+/* libs/graphics/animator/SkPaintParts.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include "SkPaintParts.h"
+#include "SkDrawPaint.h"
+#ifdef SK_DUMP_ENABLED
+#include "SkDisplayList.h"
+#include "SkDump.h"
+#endif
+
+SkPaintPart::SkPaintPart() : fPaint(NULL) {
+}
+
+SkDisplayable* SkPaintPart::getParent() const {
+    return fPaint;
+}
+
+bool SkPaintPart::setParent(SkDisplayable* parent) {
+    SkASSERT(parent != NULL);
+    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 NULL;
+}
+
+
+// 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*) NULL, this);
+    return false;
+}
+
+SkPathEffect* SkDrawPathEffect::getPathEffect() {
+    return NULL;
+}
+
+
+// SkDrawShader
+SkShader* SkDrawShader::getShader() {
+    return NULL;
+}
+
+
+// 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/src/animator/SkPaintParts.h b/src/animator/SkPaintParts.h
new file mode 100644
index 0000000..a8bb8bd
--- /dev/null
+++ b/src/animator/SkPaintParts.h
@@ -0,0 +1,83 @@
+/* libs/graphics/animator/SkPaintParts.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkPathParts.cpp b/src/animator/SkPathParts.cpp
new file mode 100644
index 0000000..46d2232
--- /dev/null
+++ b/src/animator/SkPathParts.cpp
@@ -0,0 +1,328 @@
+/* libs/graphics/animator/SkPathParts.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#include "SkPathParts.h"
+#include "SkAnimateMaker.h"
+#include "SkDrawMatrix.h"
+#include "SkDrawRectangle.h"
+#include "SkDrawPath.h"
+
+SkPathPart::SkPathPart() : fPath(NULL) {
+}
+
+void SkPathPart::dirty() { 
+    fPath->dirty(); 
+}
+
+SkDisplayable* SkPathPart::getParent() const {
+    return fPath;
+}
+
+bool SkPathPart::setParent(SkDisplayable* parent) {
+    SkASSERT(parent != NULL);
+    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(NULL), path(NULL) {
+}
+
+bool SkAddPath::add() {
+    SkASSERT (path != NULL); 
+    if (matrix)
+        fPath->fPath.addPath(path->fPath, matrix->getMatrix());
+    else
+        fPath->fPath.addPath(path->fPath);
+    return false;
+}
+
+
diff --git a/src/animator/SkPathParts.h b/src/animator/SkPathParts.h
new file mode 100644
index 0000000..72e4185
--- /dev/null
+++ b/src/animator/SkPathParts.h
@@ -0,0 +1,173 @@
+/* libs/graphics/animator/SkPathParts.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkPostParts.cpp b/src/animator/SkPostParts.cpp
new file mode 100644
index 0000000..254b17d
--- /dev/null
+++ b/src/animator/SkPostParts.cpp
@@ -0,0 +1,65 @@
+/* libs/graphics/animator/SkPostParts.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL) {}
+
+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/src/animator/SkPostParts.h b/src/animator/SkPostParts.h
new file mode 100644
index 0000000..ef41fe5
--- /dev/null
+++ b/src/animator/SkPostParts.h
@@ -0,0 +1,39 @@
+/* libs/graphics/animator/SkPostParts.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkSVGPath.cpp b/src/animator/SkSVGPath.cpp
new file mode 100644
index 0000000..86eeee8
--- /dev/null
+++ b/src/animator/SkSVGPath.cpp
@@ -0,0 +1,243 @@
+/* libs/graphics/animator/SkSVGPath.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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, NULL);
+                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/src/animator/SkScript.cpp b/src/animator/SkScript.cpp
new file mode 100644
index 0000000..3b67d7b
--- /dev/null
+++ b/src/animator/SkScript.cpp
@@ -0,0 +1,1918 @@
+/* libs/graphics/animator/SkScript.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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], &params[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 = NULL;
+    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 ? NULL : &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, NULL, 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 == NULL) {
+                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 = NULL);
+                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 : NULL);
+    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 == NULL) {
+                    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;
+            }
+            int32_t 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 == NULL) {
+                    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 == NULL) {
+                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 {
+                int32_t 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(NULL /* 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) != NULL;
+            }
+            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) != NULL;
+            }
+            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(int32_t 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(NULL /* fMaker */, type))
+        return (SkOpType) kObject;
+    if (SkDisplayType::IsEnum(NULL /* 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/src/animator/SkScript.h b/src/animator/SkScript.h
new file mode 100644
index 0000000..bb7d978
--- /dev/null
+++ b/src/animator/SkScript.h
@@ -0,0 +1,274 @@
+/* libs/graphics/animator/SkScript.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(int32_t );
+    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;
+    int32_t fIntAnswer;
+    SkScalar fScalarAnswer;
+    const char* fStringAnswer;
+};
+
+#endif
+
+#endif // SkScript_DEFINED
diff --git a/src/animator/SkScript2.h b/src/animator/SkScript2.h
new file mode 100644
index 0000000..4d8bd8c
--- /dev/null
+++ b/src/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(int32_t );
+	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;
+	int32_t fIntAnswer;
+	SkScalar fScalarAnswer;
+	const char* fStringAnswer;
+};
+
+#endif
+
+
+#endif // SkScript2_DEFINED
+
diff --git a/src/animator/SkScriptCallBack.h b/src/animator/SkScriptCallBack.h
new file mode 100644
index 0000000..725e493
--- /dev/null
+++ b/src/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/src/animator/SkScriptDecompile.cpp b/src/animator/SkScriptDecompile.cpp
new file mode 100644
index 0000000..d582d33
--- /dev/null
+++ b/src/animator/SkScriptDecompile.cpp
@@ -0,0 +1,221 @@
+/* libs/graphics/animator/SkScriptDecompile.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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: {
+            int32_t integer;
+            memcpy(&integer, opCode, sizeof(integer));
+            opCode += sizeof(int32_t);
+            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/src/animator/SkScriptRuntime.cpp b/src/animator/SkScriptRuntime.cpp
new file mode 100644
index 0000000..6d8c208
--- /dev/null
+++ b/src/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(int32_t));
+			opCode += sizeof(int32_t);
+			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] = NULL;
+}
+
+void SkScriptRuntime::untrack(SkString* string) {
+	int index = fTrackString.find(string);
+	SkASSERT(index >= 0);
+	fTrackString.begin()[index] = NULL;
+}
+
diff --git a/src/animator/SkScriptRuntime.h b/src/animator/SkScriptRuntime.h
new file mode 100644
index 0000000..c864fe4
--- /dev/null
+++ b/src/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/src/animator/SkScriptTokenizer.cpp b/src/animator/SkScriptTokenizer.cpp
new file mode 100644
index 0000000..d75e68e
--- /dev/null
+++ b/src/animator/SkScriptTokenizer.cpp
@@ -0,0 +1,1514 @@
+#include "SkScript2.h"
+#include "SkFloatingPoint.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, &params);
+        if (success)
+            success = handleMemberFunction(field, fieldLength, object, &params);
+    }
+    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 = NULL);
+                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, &params);
+    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, NULL);
+                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 == NULL) {
+                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) != NULL;
+            }
+                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) != NULL;
+            }
+                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(int32_t 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/src/animator/SkSnapshot.cpp b/src/animator/SkSnapshot.cpp
new file mode 100644
index 0000000..b65c517
--- /dev/null
+++ b/src/animator/SkSnapshot.cpp
@@ -0,0 +1,74 @@
+/* libs/graphics/animator/SkSnapshot.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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;
+}
+
+#include "SkDevice.h"
+
+bool SkSnapshot::draw(SkAnimateMaker& maker) {
+    SkASSERT(type >= 0);
+    SkASSERT(filename.size() > 0);
+    SkImageEncoder* encoder = SkImageEncoder::Create((SkImageEncoder::Type) type);
+
+    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(),
+                        maker.fCanvas->getDevice()->accessBitmap(false),
+                        SkScalarFloor(quality));
+    return false;
+}
+
+#endif
diff --git a/src/animator/SkSnapshot.h b/src/animator/SkSnapshot.h
new file mode 100644
index 0000000..c459fbb
--- /dev/null
+++ b/src/animator/SkSnapshot.h
@@ -0,0 +1,42 @@
+/* libs/graphics/animator/SkSnapshot.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkTDArray_Experimental.h b/src/animator/SkTDArray_Experimental.h
new file mode 100644
index 0000000..94d7871
--- /dev/null
+++ b/src/animator/SkTDArray_Experimental.h
@@ -0,0 +1,150 @@
+/* libs/graphics/animator/SkTDArray_Experimental.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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, NULL); }
+    int32_t* append(U16CPU count, const int32_t* src = NULL);
+
+    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 = NULL;
+#ifdef SK_DEBUG
+            fData = NULL;
+#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=NULL); 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 = NULL) { return (T*) SkDS32Array::append(count, (const int32_t*) src); }
+    T*  begin() const { SYNC(); return (T*) fArray; }
+    T*  end() const { return (T*) (fArray ? fArray + fCount : NULL); }
+    int find(const T& elem) const { return SkDS32Array::find((const int32_t&) elem); }
+    T* insert(U16CPU index) { return this->insert(index, 1, NULL); }
+    T* insert(U16CPU index, U16CPU count, const T* src = NULL) {
+        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/src/animator/SkTextOnPath.cpp b/src/animator/SkTextOnPath.cpp
new file mode 100644
index 0000000..1a06746
--- /dev/null
+++ b/src/animator/SkTextOnPath.cpp
@@ -0,0 +1,47 @@
+/* libs/graphics/animator/SkTextOnPath.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL), text(NULL) {
+}
+
+bool SkTextOnPath::draw(SkAnimateMaker& maker) {
+    SkASSERT(text);
+    SkASSERT(path);
+    SkBoundableAuto boundable(this, maker);
+    maker.fCanvas->drawTextOnPathHV(text->getText(), text->getSize(), 
+                                    path->getPath(), offset, 0, *maker.fPaint);
+    return false;
+}
diff --git a/src/animator/SkTextOnPath.h b/src/animator/SkTextOnPath.h
new file mode 100644
index 0000000..3c78b5b
--- /dev/null
+++ b/src/animator/SkTextOnPath.h
@@ -0,0 +1,38 @@
+/* libs/graphics/animator/SkTextOnPath.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkTextToPath.cpp b/src/animator/SkTextToPath.cpp
new file mode 100644
index 0000000..44036a3
--- /dev/null
+++ b/src/animator/SkTextToPath.cpp
@@ -0,0 +1,56 @@
+/* libs/graphics/animator/SkTextToPath.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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(NULL), path(NULL), text(NULL) {
+}
+
+bool SkTextToPath::draw(SkAnimateMaker& maker) {
+    path->draw(maker);
+    return false;
+}
+
+void SkTextToPath::onEndElement(SkAnimateMaker& maker) {
+    if (paint == NULL || path == NULL || text == NULL) {
+        // !!! 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/src/animator/SkTextToPath.h b/src/animator/SkTextToPath.h
new file mode 100644
index 0000000..6d93239
--- /dev/null
+++ b/src/animator/SkTextToPath.h
@@ -0,0 +1,40 @@
+/* libs/graphics/animator/SkTextToPath.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkTime.cpp b/src/animator/SkTime.cpp
new file mode 100644
index 0000000..a36a95a
--- /dev/null
+++ b/src/animator/SkTime.cpp
@@ -0,0 +1,89 @@
+/* libs/graphics/animator/SkTime.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkTypedArray.cpp b/src/animator/SkTypedArray.cpp
new file mode 100644
index 0000000..075c607
--- /dev/null
+++ b/src/animator/SkTypedArray.cpp
@@ -0,0 +1,187 @@
+/* libs/graphics/animator/SkTypedArray.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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 = NULL;
+#ifdef SK_DEBUG
+    fData = NULL;
+#endif
+}
+
+SkDS32Array::SkDS32Array(const SkDS32Array& src)
+{
+    fReserve = fCount = 0;
+    fArray = NULL;
+#ifdef SK_DEBUG
+    fData = NULL;
+#endif
+    SkDS32Array tmp(src.fArray, src.fCount);
+    this->swap(tmp);
+}
+
+SkDS32Array::SkDS32Array(const int32_t src[], U16CPU count)
+{
+    SkASSERT(src || count == 0);
+
+    fReserve = fCount = 0;
+    fArray = NULL;
+#ifdef SK_DEBUG
+    fData = NULL;
+#endif
+    if (count)
+    {
+        fArray = (int32_t*)sk_malloc_throw(count * sizeof(int32_t));
+#ifdef SK_DEBUG
+        fData = (int32_t (*)[kDebugArraySize]) fArray;
+#endif
+        memcpy(fArray, src, sizeof(int32_t) * 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(int32_t) * 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(int32_t)));
+}
+
+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);
+}
+
+int32_t* SkDS32Array::append(U16CPU count, const int32_t* src)
+{
+    unsigned oldCount = fCount;
+    if (count)
+    {
+        SkASSERT(src == NULL || fArray == NULL ||
+                src + count <= fArray || fArray + count <= src);
+
+        this->growBy(count);
+        if (src)
+            memcpy(fArray + oldCount, src, sizeof(int32_t) * count);
+    }
+    return fArray + oldCount;
+}
+
+int SkDS32Array::find(const int32_t& elem) const
+{
+    const int32_t* iter = fArray;
+    const int32_t* 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;
+        int32_t* array = (int32_t*)sk_malloc_throw(size * sizeof(int32_t));
+        memcpy(array, fArray, fCount * sizeof(int32_t));
+
+        sk_free(fArray);
+        fArray = array;
+#ifdef SK_DEBUG
+        fData = (int32_t (*)[kDebugArraySize]) fArray;
+#endif
+        fReserve = SkToU16((U16CPU)size);
+    }
+    fCount = SkToU16(fCount + extra);
+}
+
+int32_t* SkDS32Array::insert(U16CPU index, U16CPU count, const int32_t* src)
+{
+    SkASSERT(count);
+    int oldCount = fCount;
+    this->growBy(count);
+    int32_t* dst = fArray + index;
+    memmove(dst + count, dst, sizeof(int32_t) * (oldCount - index));
+    if (src)
+        memcpy(dst, src, sizeof(int32_t) * count);
+    return dst;
+}
+
+
+    int SkDS32Array::rfind(const int32_t& elem) const
+    {
+        const int32_t* iter = fArray + fCount;
+        const int32_t* stop = fArray;
+
+        while (iter > stop)
+        {
+            if (*--iter == elem)
+                return (int) (iter - stop);
+        }
+        return -1;
+    }
+
+#endif
diff --git a/src/animator/SkTypedArray.h b/src/animator/SkTypedArray.h
new file mode 100644
index 0000000..a658f29
--- /dev/null
+++ b/src/animator/SkTypedArray.h
@@ -0,0 +1,39 @@
+/* libs/graphics/animator/SkTypedArray.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/SkXMLAnimatorWriter.cpp b/src/animator/SkXMLAnimatorWriter.cpp
new file mode 100644
index 0000000..b26bc73
--- /dev/null
+++ b/src/animator/SkXMLAnimatorWriter.cpp
@@ -0,0 +1,91 @@
+/* libs/graphics/animator/SkXMLAnimatorWriter.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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->drawColor(SK_ColorWHITE);
+    s.draw(canvas, &paint, 0);
+}
+
+#endif
+
diff --git a/src/animator/SkXMLAnimatorWriter.h b/src/animator/SkXMLAnimatorWriter.h
new file mode 100644
index 0000000..c5830cd
--- /dev/null
+++ b/src/animator/SkXMLAnimatorWriter.h
@@ -0,0 +1,42 @@
+/* libs/graphics/animator/SkXMLAnimatorWriter.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#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/src/animator/thingstodo.txt b/src/animator/thingstodo.txt
new file mode 100644
index 0000000..8d0d47a
--- /dev/null
+++ b/src/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