/* * 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 "SkDrawGradient.h" #include "SkAnimateMaker.h" #include "SkAnimatorScript.h" #include "SkGradientShader.h" #include "SkUnitMapper.h" static SkScalar SkUnitToScalar(U16CPU x) { #ifdef SK_SCALAR_IS_FLOAT return x / 65535.0f; #else return x + (x >> 8); #endif } static 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 SkDrawGradientUnitMapper : public SkUnitMapper { public: SkDrawGradientUnitMapper(SkAnimateMaker* maker, const char* script) : fMaker(maker), fScript(script) { } SK_DECLARE_UNFLATTENABLE_OBJECT() 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 SkDrawGradient::fInfo[] = { SK_MEMBER_INHERITED, SK_MEMBER_ARRAY(offsets, Float), SK_MEMBER(unitMapper, String) }; #endif DEFINE_GET_MEMBER(SkDrawGradient); SkDrawGradient::SkDrawGradient() : fUnitMapper(NULL) { } SkDrawGradient::~SkDrawGradient() { for (int index = 0; index < fDrawColors.count(); index++) delete fDrawColors[index]; delete fUnitMapper; } bool SkDrawGradient::addChild(SkAnimateMaker& , SkDisplayable* child) { SkASSERT(child); if (child->isColor()) { SkDrawColor* color = (SkDrawColor*) child; *fDrawColors.append() = color; return true; } return false; } int SkDrawGradient::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 SkDrawGradient::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 SkDrawGradient::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 SkDrawGradientUnitMapper(&maker, unitMapper.c_str()); INHERITED::onEndElement(maker); } #if SK_USE_CONDENSED_INFO == 0 const SkMemberInfo SkDrawLinearGradient::fInfo[] = { SK_MEMBER_INHERITED, SK_MEMBER_ARRAY(points, Float), }; #endif DEFINE_GET_MEMBER(SkDrawLinearGradient); SkDrawLinearGradient::SkDrawLinearGradient() { } void SkDrawLinearGradient::onEndElement(SkAnimateMaker& maker) { if (points.count() != 4) maker.setErrorCode(SkDisplayXMLParserError::kGradientPointsLengthMustBeFour); INHERITED::onEndElement(maker); } #ifdef SK_DUMP_ENABLED void SkDrawLinearGradient::dump(SkAnimateMaker* maker) { dumpBase(maker); dumpRest(maker); } #endif SkShader* SkDrawLinearGradient::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 SkDrawRadialGradient::fInfo[] = { SK_MEMBER_INHERITED, SK_MEMBER(center, Point), SK_MEMBER(radius, Float) }; #endif DEFINE_GET_MEMBER(SkDrawRadialGradient); SkDrawRadialGradient::SkDrawRadialGradient() : radius(0) { center.set(0, 0); } #ifdef SK_DUMP_ENABLED void SkDrawRadialGradient::dump(SkAnimateMaker* maker) { dumpBase(maker); dumpRest(maker); } #endif SkShader* SkDrawRadialGradient::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; }