|  |  | 
|  | /* | 
|  | * Copyright 2006 The Android Open Source Project | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #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::addChild(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::addChild(SkAnimateMaker& , SkDisplayable*) { | 
|  | 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(); | 
|  | } |