/* 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; }