package org.andengine.extension.svg.adt;
import java.util.ArrayList;
import java.util.HashMap;
import org.andengine.extension.svg.exception.SVGParseException;
import org.andengine.extension.svg.util.SVGParserUtils;
import org.andengine.extension.svg.util.SVGTransformParser;
import org.andengine.extension.svg.util.constants.ISVGConstants;
import org.xml.sax.Attributes;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
/**
* @author Larva Labs, LLC
* (c) 2010 Nicolas Gramlich
* (c) 2011 Zynga Inc.
*
* @author Nicolas Gramlich
* @since 16:50:09 - 21.05.2011
*/
public class SVGGradient implements ISVGConstants {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private final String mID;
private final String mHref;
private SVGGradient mParent;
private Shader mShader;
private final SVGAttributes mSVGAttributes;
private final boolean mLinear;
private Matrix mMatrix;
private ArrayList<SVGGradientStop> mSVGGradientStops;
private float[] mSVGGradientStopsPositions;
private int[] mSVGGradientStopsColors;
private boolean mSVGGradientStopsBuilt;
// ===========================================================
// Constructors
// ===========================================================
public SVGGradient(final String pID, final boolean pLinear, final Attributes pAttributes) {
this.mID = pID;
this.mHref = SVGParserUtils.parseHref(pAttributes);
this.mLinear = pLinear;
this.mSVGAttributes = new SVGAttributes(pAttributes, true);
}
// ===========================================================
// Getter & Setter
// ===========================================================
public boolean hasHref() {
return this.mHref != null;
}
public String getHref() {
return this.mHref;
}
public String getID() {
return this.mID;
}
public boolean hasHrefResolved() {
return this.mHref == null || this.mParent != null;
}
public Shader getShader() {
return this.mShader;
}
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
public Shader createShader() {
if(this.mShader != null) {
return this.mShader;
}
if(!this.mSVGGradientStopsBuilt) {
this.buildSVGGradientStopsArrays();
}
final TileMode tileMode = this.getTileMode();
if(this.mLinear) {
final float x1 =this.mSVGAttributes.getFloatAttribute(ATTRIBUTE_X1, true, 0f);
final float x2 = this.mSVGAttributes.getFloatAttribute(ATTRIBUTE_X2, true, 0f);
final float y1 = this.mSVGAttributes.getFloatAttribute(ATTRIBUTE_Y1, true, 0f);
final float y2 = this.mSVGAttributes.getFloatAttribute(ATTRIBUTE_Y2, true, 0f);
this.mShader = new LinearGradient(x1, y1, x2, y2, this.mSVGGradientStopsColors, this.mSVGGradientStopsPositions, tileMode);
} else {
final float centerX = this.mSVGAttributes.getFloatAttribute(ATTRIBUTE_CENTER_X, true, 0f);
final float centerY = this.mSVGAttributes.getFloatAttribute(ATTRIBUTE_CENTER_Y, true, 0f);
final float radius = this.mSVGAttributes.getFloatAttribute(ATTRIBUTE_RADIUS, true, 0f);
this.mShader = new RadialGradient(centerX, centerY, radius, this.mSVGGradientStopsColors, this.mSVGGradientStopsPositions, tileMode);
}
this.mMatrix = this.getTransform();
if (this.mMatrix != null) {
this.mShader.setLocalMatrix(this.mMatrix);
}
return this.mShader;
}
private TileMode getTileMode() {
final String spreadMethod = this.mSVGAttributes.getStringAttribute(ATTRIBUTE_SPREADMETHOD, true);
if(spreadMethod == null || ATTRIBUTE_SPREADMETHOD_VALUE_PAD.equals(spreadMethod)) {
return TileMode.CLAMP;
} else if(ATTRIBUTE_SPREADMETHOD_VALUE_REFLECT.equals(spreadMethod)) {
return TileMode.MIRROR;
} else if(ATTRIBUTE_SPREADMETHOD_VALUE_REPEAT.equals(spreadMethod)) {
return TileMode.REPEAT;
} else {
throw new SVGParseException("Unexpected spreadmethod: '" + spreadMethod + "'.");
}
}
private Matrix getTransform() {
if(this.mMatrix != null) {
return this.mMatrix;
} else {
final String transfromString = this.mSVGAttributes.getStringAttribute(ATTRIBUTE_GRADIENT_TRANSFORM, false);
if(transfromString != null) {
this.mMatrix = SVGTransformParser.parseTransform(transfromString);
return this.mMatrix;
} else {
if(this.mParent != null) {
return this.mParent.getTransform();
} else {
return null;
}
}
}
}
public void ensureHrefResolved(final HashMap<String, SVGGradient> pSVGGradientMap) {
if(!this.hasHrefResolved()) {
this.resolveHref(pSVGGradientMap);
}
}
private void resolveHref(final HashMap<String, SVGGradient> pSVGGradientMap) {
final SVGGradient parent = pSVGGradientMap.get(this.mHref);
if(parent == null) {
throw new SVGParseException("Could not resolve href: '" + this.mHref + "' of SVGGradient: '" + this.mID + "'.");
} else {
parent.ensureHrefResolved(pSVGGradientMap);
this.mParent = parent;
this.mSVGAttributes.setParentSVGAttributes(this.mParent.mSVGAttributes);
if(this.mSVGGradientStops == null) {
this.mSVGGradientStops = this.mParent.mSVGGradientStops;
this.mSVGGradientStopsColors = this.mParent.mSVGGradientStopsColors;
this.mSVGGradientStopsPositions = this.mParent.mSVGGradientStopsPositions;
}
}
}
private void buildSVGGradientStopsArrays() {
this.mSVGGradientStopsBuilt = true;
final ArrayList<SVGGradientStop> svgGradientStops = this.mSVGGradientStops;
final int svgGradientStopCount = svgGradientStops.size();
this.mSVGGradientStopsColors = new int[svgGradientStopCount];
this.mSVGGradientStopsPositions = new float[svgGradientStopCount];
for (int i = 0; i < svgGradientStopCount; i++) {
final SVGGradientStop svgGradientStop = svgGradientStops.get(i);
this.mSVGGradientStopsColors[i] = svgGradientStop.mColor;
this.mSVGGradientStopsPositions[i] = svgGradientStop.mOffset;
}
}
public void addSVGGradientStop(final SVGGradientStop pSVGGradientStop) {
if(this.mSVGGradientStops == null) {
this.mSVGGradientStops = new ArrayList<SVGGradient.SVGGradientStop>();
}
this.mSVGGradientStops.add(pSVGGradientStop);
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
public static class SVGGradientStop {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private final float mOffset;
private final int mColor;
// ===========================================================
// Constructors
// ===========================================================
public SVGGradientStop(final float pOffset, final int pColor) {
this.mOffset = pOffset;
this.mColor = pColor;
}
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}
}