/*
* JSwiff is an open source Java API for Macromedia Flash file generation
* and manipulation
*
* Copyright (C) 2004-2005 Ralf Terdic (contact@jswiff.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.jswiff.swfrecords;
import com.jswiff.io.InputBitStream;
import com.jswiff.io.OutputBitStream;
import java.io.IOException;
/**
* Unlike <code>StraightEdgeRecord</code> and <code>CurvedEdgeRecord</code>,
* this shape record is used for changing the actual style rather than
* defining new shapes. There are three ways to do this:
*
* <ul>
* <li>
* select a previously defined fill or line style
* </li>
* <li>
* move current drawing position to specified coordinates
* </li>
* <li>
* replace current fill and line style arrays with new ones
* </li>
* </ul>
*/
public final class StyleChangeRecord extends ShapeRecord {
private int moveToX;
private int moveToY;
private int fillStyle0;
private int fillStyle1;
private int lineStyle;
private FillStyleArray fillStyles;
private LineStyleArray lineStyles;
private byte numFillBits; // Set only when hasNewStyles! Initial value in Shape/ShapeWithStyle
private byte numLineBits; // Set only when hasNewStyles! Initial value in Shape/ShapeWithStyle
private boolean hasNewStyles;
private boolean hasLineStyle;
private boolean hasFillStyle1;
private boolean hasFillStyle0;
private boolean hasMoveTo;
/**
* Creates a new StyleChangeRecord instance.
*/
public StyleChangeRecord() {
// empty
}
StyleChangeRecord(
InputBitStream stream, byte flags, byte numFillBits, byte numLineBits,
boolean useNewLineStyle, boolean hasAlpha) throws IOException {
hasNewStyles = ((flags & 16) != 0);
hasLineStyle = ((flags & 8) != 0);
hasFillStyle1 = ((flags & 4) != 0);
hasFillStyle0 = ((flags & 2) != 0);
hasMoveTo = ((flags & 1) != 0);
if (hasMoveTo) {
int moveBits = (int) stream.readUnsignedBits(5);
moveToX = (int) stream.readSignedBits(moveBits);
moveToY = (int) stream.readSignedBits(moveBits);
}
if (hasFillStyle0) {
fillStyle0 = (int) stream.readUnsignedBits(numFillBits);
}
if (hasFillStyle1) {
fillStyle1 = (int) stream.readUnsignedBits(numFillBits);
}
if (hasLineStyle) {
lineStyle = (int) stream.readUnsignedBits(numLineBits);
}
if (hasNewStyles) {
fillStyles = new FillStyleArray(stream, hasAlpha);
if (useNewLineStyle) {
lineStyles = new LineStyleArray(stream);
} else {
lineStyles = new LineStyleArray(stream, hasAlpha);
}
this.numFillBits = (byte) stream.readUnsignedBits(4); // set new values
this.numLineBits = (byte) stream.readUnsignedBits(4);
} else {
this.numFillBits = numFillBits; // set passed values, no new values available
this.numLineBits = numLineBits;
}
}
/**
* Sets the value for fillStyle0 (i.e. the fill style for non-overlapping
* shape portions). This value is used as index in the current fill style
* array. Warning: style array indexes start with 1. A fill style value of 0
* means the path is not filled.
*
* @param fillStyle0 fill style array index
*/
public void setFillStyle0(int fillStyle0) {
this.fillStyle0 = fillStyle0;
hasFillStyle0 = true;
}
/**
* Returns the value for fillStyle0 (i.e. the fill style for non-overlapping
* shape portions). This value is used as index in the current fill style
* array. A fill style value of 0 means the path is not filled. Check with
* <code>hasFillStyle0()</code> first if the style has been specified.
*
* @return the value for fillStyle0
*/
public int getFillStyle0() {
return fillStyle0;
}
/**
* Sets the value for fillStyle1 (i.e. the fill style for overlapping shape
* portions). This value is used as index in the current fill style array.
* Warning: style array indexes start with 1. A fill style value of 0 means
* the path is not filled.
*
* @param fillStyle1 fill style array index
*/
public void setFillStyle1(int fillStyle1) {
this.fillStyle1 = fillStyle1;
hasFillStyle1 = true;
}
/**
* Returns the value for fillStyle1 (i.e. the fill style for overlapping
* shape portions). This value is used as index in the current fill style
* array. A fill style value of 0 means the path is not filled. Check with
* <code>hasFillStyle1()</code> first if the style has been specified.
*
* @return the value for fillStyle1
*/
public int getFillStyle1() {
return fillStyle1;
}
/**
* Sets the value for the line style (i.e. the fill style for overlapping
* shapes). This value is used as index in the current line style array.
* Warning: style array indexes start with 1. A line style value of 0 means
* the path has no stroke.
*
* @param lineStyle line style array index
*/
public void setLineStyle(int lineStyle) {
this.lineStyle = lineStyle;
hasLineStyle = true;
}
/**
* Returns the value for the line style (i.e. the fill style for overlapping
* shapes). This value is used as index in the current line style array. A
* line style value of 0 means the path has no stroke. Check with
* <code>hasLineStyle()</code> first if the style has been specified.
*
* @return line style array index
*/
public int getLineStyle() {
return lineStyle;
}
/**
* Sets the current drawing position to new coordinates.
*
* @param x x coordinate in twips
* @param y y coordinate in twips
*/
public void setMoveTo(int x, int y) {
moveToX = x;
moveToY = y;
hasMoveTo = true;
}
/**
* Returns the x coordinate of the current drawing position in twips (i.e.
* 1/20 px). Check with <code>hasMoveTo()</code> first if the value is set.
*
* @return x coordinate in twips
*/
public int getMoveToX() {
return moveToX;
}
/**
* Returns the y coordinate of the current drawing position in twips (i.e.
* 1/20 px). Check with <code>hasMoveTo()</code> first if the value is set.
*
* @return y coordinate in twips
*/
public int getMoveToY() {
return moveToY;
}
/**
* Returns the new set of fill styles which is supposed to replace the old
* one. Check with <code>hasNewStyles()</code> if new styles have been
* specified.
*
* @return new fill style array
*/
public FillStyleArray getNewFillStyles() {
return fillStyles;
}
/**
* Returns the new set of line styles which is supposed to replace the old
* one. Check with <code>hasNewStyles()</code> if new styles have been
* specified.
*
* @return new line style array
*/
public LineStyleArray getNewLineStyles() {
return lineStyles;
}
/**
* Specifies a new set of line and fill styles, thus replacing the old ones.
* This is not supported within the <code>DefineShape</code> tag.
*
* @param lineStyles a line style array
* @param fillStyles a fill style array
*/
public void setNewStyles(
LineStyleArray lineStyles, FillStyleArray fillStyles) {
this.lineStyles = lineStyles;
this.fillStyles = fillStyles;
hasNewStyles = true;
}
/**
* Checks if a value for fillStyle0 is selected. This value is used as index
* in the current fill style array.
*
* @return <code>true</code> if fillStyle0 specified, else <code>false</code>
*/
public boolean hasFillStyle0() {
return hasFillStyle0;
}
/**
* Checks if a value for fillStyle1 is selected. This value is used as index
* in the current fill style array.
*
* @return <code>true</code> if fillStyle1 specified, else <code>false</code>
*/
public boolean hasFillStyle1() {
return hasFillStyle1;
}
/**
* Checks if a value for the line style is selected. This value is used as
* index in the current line style array.
*
* @return <code>true</code> if line style specified, else <code>false</code>
*/
public boolean hasLineStyle() {
return hasLineStyle;
}
/**
* Checks if the style change record moves the current drawing position.
*
* @return <code>true</code> if new coordinates for the current drawing
* position were specified, else <code>false</code>
*/
public boolean hasMoveTo() {
return hasMoveTo;
}
/**
* Checks if the style change record specifies a new set of line and fill
* styles, thus replacing the old ones.
*
* @return <code>true</code> if line and fill style array specified
*/
public boolean hasNewStyles() {
return hasNewStyles;
}
void setNumFillBits(byte numFillBits) {
this.numFillBits = numFillBits;
}
byte getNumFillBits() {
return numFillBits;
}
void setNumLineBits(byte numLineBits) {
this.numLineBits = numLineBits;
}
byte getNumLineBits() {
return numLineBits;
}
void write(OutputBitStream stream, byte fillBits, byte lineBits)
throws IOException {
stream.writeUnsignedBits(0, 1); // non-edge
stream.writeBooleanBit(hasNewStyles);
stream.writeBooleanBit(hasLineStyle);
stream.writeBooleanBit(hasFillStyle1);
stream.writeBooleanBit(hasFillStyle0);
stream.writeBooleanBit(hasMoveTo);
if (hasMoveTo) {
int moveBits = OutputBitStream.getSignedBitsLength(moveToX);
moveBits = Math.max(
moveBits, OutputBitStream.getSignedBitsLength(moveToY));
stream.writeUnsignedBits(moveBits, 5);
stream.writeSignedBits(moveToX, moveBits);
stream.writeSignedBits(moveToY, moveBits);
}
if (hasFillStyle0) {
stream.writeUnsignedBits(fillStyle0, fillBits);
}
if (hasFillStyle1) {
stream.writeUnsignedBits(fillStyle1, fillBits);
}
if (hasLineStyle) {
stream.writeUnsignedBits(lineStyle, lineBits);
}
if (hasNewStyles) {
fillStyles.write(stream);
lineStyles.write(stream);
stream.writeUnsignedBits(this.numFillBits, 4);
stream.writeUnsignedBits(this.numLineBits, 4);
}
}
}