/* * FocalGradientFill.java * Transform * * Copyright (c) 2009-2010 Flagstone Software Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Flagstone Software Ltd. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package com.flagstone.transform.fillstyle; import java.io.IOException; import java.util.ArrayList; import java.util.List; import com.flagstone.transform.coder.Coder; import com.flagstone.transform.coder.Context; import com.flagstone.transform.coder.SWFDecoder; import com.flagstone.transform.coder.SWFEncoder; import com.flagstone.transform.datatype.CoordTransform; /** * MorphFocalGradientFill extends the functionality of MorphGradientFill by * allowing the focal point for the gradient at the start and end of the * morphing process to be specified rather than defaulting to the centre of the * shape. * * The value for the focal point ranges from -1.0 to 1.0, where negative values * up to -1.0 sets the focal point closer to the left border gradient circle and * positive values up to 1.0 sets the focal point closer the right border. A * value of zero means the focal point is in the centre. */ public final class MorphFocalGradientFill implements FillStyle { /** Bit mask for extracting the spread field in gradient fills. */ private static final int SPREAD_MASK = 0x00C0; /** Bit mask for extracting the interpolation field in gradient fills. */ private static final int INTER_MASK = 0x0030; /** Bit mask for extracting the interpolation field in gradient fills. */ private static final int GRADIENT_MASK = 0x000F; /** Format string used in toString() method. */ private static final String FORMAT = "MorphFocalGradientFill: { spread=%s;" + " interpolation=%s; startFocalPoint=%f; endFocalPoint=%f;" + " startTransform=%s; endTransform=%s; gradients=%s}"; /** Maps the Gradient Square to real coordinates at the start. */ private CoordTransform startTransform; /** Maps the Gradient Square to real coordinates at the end. */ private CoordTransform endTransform; /** Code for the Spread type. */ private int spread; /** Interpolation for colour changes. */ private int interpolation; /** The position of the focal point at the start of the morphing process. */ private int startFocalPoint; /** The position of the focal point at the end of the morphing process. */ private int endFocalPoint; /** List of gradients defining the colour changes. */ private List<MorphGradient> gradients; /** Number of gradients in list. */ private transient int count; /** * Creates and initialises a FocalGradientFill fill style using values * encoded in the Flash binary format. * * @param coder * an SWFDecoder object that contains the encoded Flash data. * * @param context * a Context object used to manage the decoders for different * type of object and to pass information on how objects are * decoded. * * @throws IOException * if an error occurs while decoding the data. */ public MorphFocalGradientFill(final SWFDecoder coder, final Context context) throws IOException { startTransform = new CoordTransform(coder); endTransform = new CoordTransform(coder); count = coder.readByte() & Gradient.MAX_GRADIENTS; spread = count & SPREAD_MASK; interpolation = count & INTER_MASK; count = count & GRADIENT_MASK; gradients = new ArrayList<MorphGradient>(count); for (int i = 0; i < count; i++) { gradients.add(new MorphGradient(coder, context)); } startFocalPoint = coder.readSignedShort(); endFocalPoint = coder.readSignedShort(); } /** * Creates a MorphFocalGradientFill. * * @param startMatrix * the coordinate transform mapping the gradient square onto * physical coordinates at the start of the morphing process. * Must not be null. * @param endMatrix * the coordinate transform mapping the gradient square onto * physical coordinates at the end of the morphing process. * Must not be null. * @param spreadType * To be documented. * @param interpolationType * how the changes in colours across the gradient are calculated. * @param startPoint * the position of the focal point relative to the centre of the * radial circle at the start of the morphing process. Values * range from -1.0 (close to the left edge), to 1.0 (close to * the right edge). * @param endPoint * the position of the focal point relative to the centre of the * radial circle at the start of the morphing process. Values * range from -1.0 (close to the left edge), to 1.0 (close to * the right edge). * @param list * a list of Gradient objects defining the control points for * the gradient. For Flash 7 and earlier versions there can be up * to 8 Gradients. For Flash 8 onwards this number was increased * to 15. Must not be null. */ public MorphFocalGradientFill(final CoordTransform startMatrix, final CoordTransform endMatrix, final Spread spreadType, final Interpolation interpolationType, final float startPoint, final float endPoint, final List<MorphGradient> list) { setStartTransform(startMatrix); setEndTransform(endMatrix); setSpread(spreadType); setInterpolation(interpolationType); setStartFocalPoint(startPoint); setEndFocalPoint(endPoint); setGradients(list); } /** * Creates and initialises a FocalGradientFill fill style using the values * copied from another FocalGradientFill object. * * @param object * a FocalGradientFill fill style from which the values will be * copied. */ public MorphFocalGradientFill(final MorphFocalGradientFill object) { spread = object.spread; interpolation = object.interpolation; startTransform = object.startTransform; endTransform = object.endTransform; startFocalPoint = object.startFocalPoint; endFocalPoint = object.endFocalPoint; gradients = new ArrayList<MorphGradient>(object.gradients); } /** * Get the Spread describing how the gradient fills the area: PAD - the * last colour fills the remaining area; REPEAT - the gradient is repeated; * REFLECT - the gradient is repeated but reflected (reversed) each time. * * @return the Spread, either PAD, REFLECT or REPEAT. */ public Spread getSpread() { return Spread.fromInt(spread); } /** * Set the Spread describing how the gradient fills the area: either by * using the last gradient colour to fill the area (PAD); repeating the * gradient (REPEAT) or repeating but reversing it each time (REFLECT). * * @param spreadType the Spread, either PAD, REFLECT or REPEAT. */ public void setSpread(final Spread spreadType) { spread = spreadType.getValue(); } /** * Get the method used to calculate the colour changes across the gradient. * * @return the Interpolation that describes how colours change. */ public Interpolation getInterpolation() { return Interpolation.fromInt(interpolation); } /** * Set the method used to calculate the colour changes across the gradient. * * @param interp the Interpolation that describes how colours change. */ public void setInterpolation(final Interpolation interp) { interpolation = interp.getValue(); } /** * Get the focal point at the start of the morphing process. * @return the focal point in the range -1.0 to 1.0. */ public float getStartFocalPoint() { return startFocalPoint / Coder.SCALE_8; } /** * Set the focal point at the start of the morphing process. * @param point the focal point in the range -1.0 to 1.0. */ public void setStartFocalPoint(final float point) { startFocalPoint = (int) (point * Coder.SCALE_8); } /** * Get the focal point at the end of the morphing process. * @return the focal point in the range -1.0 to 1.0. */ public float getEndFocalPoint() { return endFocalPoint / Coder.SCALE_8; } /** * Set the focal point at the end of the morphing process. * @param point the focal point in the range -1.0 to 1.0. */ public void setEndFocalPoint(final float point) { endFocalPoint = (int) (point * Coder.SCALE_8); } /** * Add a Gradient object to the list of gradient objects. For Flash 7 and * earlier versions there can be up to 8 Gradients. For Flash 8 onwards this * number was increased to 15. * * @param aGradient * an Gradient object. Must not be null. * @return this object. */ public MorphFocalGradientFill add(final MorphGradient aGradient) { if (aGradient == null) { throw new IllegalArgumentException(); } if (gradients.size() == Gradient.MAX_GRADIENTS) { throw new IllegalStateException( "Maximum number of gradients exceeded."); } gradients.add(aGradient); return this; } /** * Get the list of Gradient objects defining the points for the * gradient fill. * * @return the set of points that define the gradient. */ public List<MorphGradient> getGradients() { return gradients; } /** * Sets the list of control points that define the gradient. For Flash 7 * and earlier this list can contain up to 8 Gradient objects. For Flash 8 * onwards this limit was increased to 15. * * @param list * a list of Gradient objects. Must not be null. */ public void setGradients(final List<MorphGradient> list) { if (list == null) { throw new IllegalArgumentException(); } if (gradients.size() > Gradient.MAX_GRADIENTS) { throw new IllegalStateException( "Maximum number of gradients exceeded."); } gradients = list; } /** * Get the coordinate transform mapping the gradient square onto * physical coordinates at the start of the morphing process. * * @return the starting transform for the gradient. */ public CoordTransform getStartTransform() { return startTransform; } /** * Get the coordinate transform mapping the gradient square onto * physical coordinates at the end of the morphing process. * * @return the final transform for the gradient. */ public CoordTransform getEndTransform() { return endTransform; } /** * Sets the coordinate transform mapping the gradient square onto physical * coordinates at the start of the morphing process. * * @param matrix * the starting coordinate transform. Must not be null. */ public void setStartTransform(final CoordTransform matrix) { if (matrix == null) { throw new IllegalArgumentException(); } startTransform = matrix; } /** * Sets the coordinate transform mapping the gradient square onto physical * coordinates at the end of the morphing process. * * @param matrix * the ending coordinate transform. Must not be null. */ public void setEndTransform(final CoordTransform matrix) { if (matrix == null) { throw new IllegalArgumentException(); } endTransform = matrix; } /** {@inheritDoc} */ public MorphFocalGradientFill copy() { return new MorphFocalGradientFill(this); } /** {@inheritDoc} */ @Override public String toString() { return String.format(FORMAT, getSpread(), getInterpolation(), getStartFocalPoint(), getEndFocalPoint(), startTransform.toString(), endTransform.toString(), gradients.toString()); } /** {@inheritDoc} */ public int prepareToEncode(final Context context) { // CHECKSTYLE:OFF // Calculate size of gradient list directly. int length = 6 + startTransform.prepareToEncode(context) + endTransform.prepareToEncode(context); count = gradients.size(); for (final MorphGradient gradient : gradients) { length += gradient.prepareToEncode(context); } //CHECKSTYLE:ON return length; } /** {@inheritDoc} */ public void encode(final SWFEncoder coder, final Context context) throws IOException { coder.writeByte(FillStyleTypes.FOCAL_GRADIENT); startTransform.encode(coder, context); endTransform.encode(coder, context); coder.writeByte(count | spread | interpolation); for (final MorphGradient gradient : gradients) { gradient.encode(coder, context); } coder.writeShort(startFocalPoint); coder.writeShort(endFocalPoint); } }