/* * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. * */ package org.apache.flex.swf.types; import org.apache.flex.swf.tags.ICharacterReferrer; import org.apache.flex.swf.tags.ICharacterTag; import org.apache.flex.swf.tags.CharacterIterableFactory; /** * The style change record is also a non-edge record. It can be used to do the * following: * <ol> * <li>Select a fill or line style for drawing.</li> * <li>Move the current drawing position (without drawing).</li> * <li>Replace the current fill and line style arrays with a new set of styles.</li> * </ol> * <p> * Because fill and line styles often change at the start of a new path, it is * useful to perform more than one action in a single record. For example, say a * {@code DefineShape} tag defines a red circle and a blue square. After the * circle is closed, it is necessary to move the drawing position, and replace * the red fill with the blue fill. The style change record can achieve this * with a single shape record. * </p> */ public class StyleChangeRecord extends ShapeRecord implements ICharacterReferrer { public StyleChangeRecord() { super(ShapeRecordType.STYLE_CHANGE); this.stateNewStyles = false; this.stateLineStyle = false; this.stateFillStyle0 = false; this.stateFillStyle1 = false; this.stateMoveTo = false; } private boolean stateNewStyles; private boolean stateLineStyle; private boolean stateFillStyle1; private boolean stateFillStyle0; private boolean stateMoveTo; private int moveDeltaX; private int moveDeltaY; private IFillStyle fillStyle0; private IFillStyle fillStyle1; private ILineStyle lineStyle; private int numFillBits; private int numLineBits; private Styles styles; /** * Move the current drawing position (without drawing). * * @param x delta x * @param y delta y */ public void setMove(int x, int y) { stateMoveTo = true; moveDeltaX = x; moveDeltaY = y; } /** * Select styles from parent {@code ShapeWithStyle} record. The * {@code FillStyle} and {@code LineStyle} objects provided must be defined * in the parent {@code ShapeWithStyle} record. Otherwise, exception will be * thrown. * * @param fillStyle0 fill0 style * @param fillStyle1 fill1 style * @param lineStyle line style * @throws IllegalArgumentException using styles not defined in the parent * shape */ public void setDefinedStyles( final IFillStyle fillStyle0, final IFillStyle fillStyle1, final ILineStyle lineStyle, final Styles styleContext) { if (fillStyle0 != null && !styleContext.getFillStyles().contains(fillStyle0)) { throw new IllegalArgumentException("FillStyle0 is not defined in parent shape."); } if (fillStyle1 != null && !styleContext.getFillStyles().contains(fillStyle1)) { throw new IllegalArgumentException("FillStyle1 is not defined in parent shape."); } if (lineStyle != null && !styleContext.getLineStyles().contains(lineStyle)) { throw new IllegalArgumentException("LineStyle is not defined in parent shape."); } this.fillStyle0 = fillStyle0; this.fillStyle1 = fillStyle1; this.lineStyle = lineStyle; this.stateFillStyle0 = fillStyle0 != null; this.stateFillStyle1 = fillStyle1 != null; this.stateLineStyle = lineStyle != null; } /** * Select styles from parent {@code ShapeWithStyle} record. The * {@code FillStyle} and {@code LineStyle} objects provided must be defined * in the parent {@code ShapeWithStyle} record. Otherwise, exception will be * thrown. * * @param fillStyle0 fill0 style * @param fillStyle1 fill1 style * @param lineStyle line style * @throws IllegalArgumentException using styles not defined in the parent * shape */ public void setDefinedStyles( final IFillStyle fillStyle0, final IFillStyle fillStyle1, final ILineStyle lineStyle, final boolean stateFillStyle0, final boolean stateFillStyle1, final boolean stateLineStyle, final Styles styleContext) { this.fillStyle0 = fillStyle0; this.fillStyle1 = fillStyle1; this.lineStyle = lineStyle; this.stateFillStyle0 = stateFillStyle0; this.stateFillStyle1 = stateFillStyle1; this.stateLineStyle = stateLineStyle; } /** * Select styles from parent {@code ShapeWithStyle} record. The * {@code FillStyle} and {@code LineStyle} objects provided must be defined * in the parent {@code ShapeWithStyle} record. Otherwise, exception will be * thrown. * * @param fillStyle0Index fill0 style * @param fillStyle1Index fill1 style * @param lineStyleIndex line style * @throws IllegalArgumentException using styles not defined in the parent * shape */ public void setDefinedStyles( final int fillStyle0Index, final int fillStyle1Index, final int lineStyleIndex, final Styles styleContext) { if (fillStyle0Index >= 0) { if (fillStyle0Index > 0) { this.fillStyle0 = styleContext.getFillStyles().get(fillStyle0Index - 1); } else { this.fillStyle0 = null; } stateFillStyle0 = true; } if (fillStyle1Index >= 0) { if (fillStyle1Index > 0) { this.fillStyle1 = styleContext.getFillStyles().get(fillStyle1Index - 1); } else { this.fillStyle1 = null; } stateFillStyle1 = true; } if (lineStyleIndex >= 0) { if (lineStyleIndex > 0) { this.lineStyle = styleContext.getLineStyles().get(lineStyleIndex - 1); } else { this.lineStyle = null; } stateLineStyle = true; } } /** * Select styles from parent {@code Shape} record for a font. The * {@code FillStyle} and {@code LineStyle} objects provided must be defined * in the parent {@code ShapeWithStyle} record. Otherwise, exception will be * thrown. * * @param fillStyle0Index fill0 style * @param fillStyle1Index fill1 style * @param lineStyleIndex line style * @throws IllegalArgumentException using styles not defined in the parent * shape */ public void setDefinedFontStyles( final int fillStyle0Index, final int fillStyle1Index, final int lineStyleIndex, final Styles styleContext) { // there shouldn't be any styles on a shape for fonts, as the // tag is a Shape, not ShapeWithStyle, but the fillStyle0 can be 1 because // of the following from the SWF spec: // "The first STYLECHANGERECORD of each SHAPE in the GlyphShapeTable does not use // the LineStyle and LineStyles fields. In addition, the first STYLECHANGERECORD of each // shape must have both fields StateFillStyle0 and FillStyle0 set to 1." if (fillStyle0Index >= 0) { fillStyle0 = null; stateFillStyle0 = true; } if (fillStyle1Index >= 0) { fillStyle1 = null; stateFillStyle1 = true; } if (lineStyleIndex >= 0) { lineStyle = null; stateLineStyle = true; } } /** * clears the styles of this style change record if the respective boolean is set * * @param fill0 <code>true</code> to clear fill style 0 * @param fill1 <code>true</code> to clear file style 1 * @param line <code>true</code> to clear line style */ public void defaultStyles(boolean fill0, boolean fill1, boolean line) { if (fill0) { this.fillStyle0 = null; stateFillStyle0 = true; } if (fill1) { this.fillStyle1 = null; stateFillStyle1 = true; } if (line) { this.lineStyle = null; stateLineStyle = true; } } /** * Define new styles and use the new styles. */ public void setNewStyles(final Styles value) { this.stateNewStyles = true; this.styles = value; } /** * If true, this {@code StyleChangeRecord} defines new styles, and its * FillStyle0, FillStyle1, LineStyle points to the new styles. * * @return true if the StyleChangeRecord defines new styles. */ public boolean isStateNewStyles() { return stateNewStyles; } /** * If true, this {@code StyleChangeReocrd} selects a line style. * * @return true if the StyleChangeRecord selects a line style. */ public boolean isStateLineStyle() { return stateLineStyle; } /** * If true, this {@code StyleChangeReocrd} selects a fill style for * {@code FillStyle1}. * * @return true if the StyleChangeRecord selects a fill style for * {@code FillStyle1}. */ public boolean isStateFillStyle1() { return stateFillStyle1; } /** * If true, this {@code StyleChangeReocrd} selects a fill style for * {@code FillStyle0}. * * @return true if the StyleChangeRecord selects a fill style for * {@code FillStyle0}. */ public boolean isStateFillStyle0() { return stateFillStyle0; } /** * If true, this {@code StyleChangeReocrd} moves the draw position. * * @return true if the StyleChangeRecord moves the draw position. */ public boolean isStateMoveTo() { return stateMoveTo; } /** * Get move delta on X-axis. * * @return move delta X. */ public int getMoveDeltaX() { return moveDeltaX; } /** * Get move delta on Y-axis. * * @return move delta Y. */ public int getMoveDeltaY() { return moveDeltaY; } /** * Get FillStyle0. * * @return fill0 style */ public IFillStyle getFillstyle0() { return fillStyle0; } /** * Get FillStyle1 * * @return fill1 style */ public IFillStyle getFillstyle1() { return fillStyle1; } /** * Get LineStyle * * @return line style */ public ILineStyle getLinestyle() { return lineStyle; } public Styles getStyles() { return styles; } /** * StyleChangeRecord refers to fill styles either from its parent * ShapeWithStyle's fill styles or from its own private fill styles (when * stateNewStyle is true). */ @Override public Iterable<ICharacterTag> getReferences() { return CharacterIterableFactory.collect( (stateFillStyle0 && fillStyle0 != null) ? fillStyle0.getReferences() : CharacterIterableFactory.empty(), (stateFillStyle1 && fillStyle1 != null) ? fillStyle1.getReferences() : CharacterIterableFactory.empty()); } /** * Get the numFillBits field read from SWF. * * @return the numFillBits */ public int getNumFillBits() { return numFillBits; } /** * Only SWFReader can set this field. * * @param value the numFillBits to set */ public void setNumFillBits(int value) { this.numFillBits = value; } /** * Get the numLineBits field read from SWF. * * @return the numLineBits */ public int getNumLineBits() { return numLineBits; } /** * Only SWFReader can set this field. * * @param value the numLineBits to set */ public void setNumLineBits(int value) { this.numLineBits = value; } }