/*
* TextSettings.java
* Transform
*
* Copyright (c) 2001-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.text;
import java.io.IOException;
import com.flagstone.transform.MovieTag;
import com.flagstone.transform.MovieTypes;
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.exception.IllegalArgumentRangeException;
/**
* TextSettings allows you to control how individual text fields are rendered.
*
* <p>
* There are four parameters that control how the text is rendered:
* </p>
* <ol>
* <li>Advanced Rendering - whether the text is rendered using the advanced
* anti-aliasing engine added in Flash 8.</li>
* <li>Grid Alignment - how letters are aligned with respect to the pixel grid
* used in LCD monitors.</li>
* <li>Thickness - a parameter used to control the thickness of the line when
* anti-aliasing is used.</li>
* <li>Sharpness - a parameter used to control the sharpness of the line when
* anti-aliasing is used.</li>
* </ol>
* <p>
* The thickness and sharpness control the how the text is rendered:
*
* <pre>
* outsideCutoff = (0.5 * sharpness - thickness) * fontSize
* insideCutoff = (-0.5 * sharpness - thickness) * fontSize
* </pre>
*
* Note that Adobe reports the results can be poor when the text is scaled by a
* significant amount and so the default values of 0.0 should be used for the
* thickness and sharpness values.
* </p>
*/
public final class TextSettings implements MovieTag {
/**
* Grid specifies how letters are aligned with respect to the pixel grid on
* a screen.
*/
public enum Grid {
/** Do not use grid fitting. */
NONE,
/** Align letters on pixel boundaries. */
PIXEL,
/** Align letters on 1/3 pixel boundaries. */
SUBPIXEL
}
/** Format string used in toString() method. */
private static final String FORMAT = "TextSettings: { identifier=%d;"
+ " useAdvanced=%s; grid=%s; thickness=%f; sharpness=%f}";
/** The unique identifier of the text field. */
private transient int identifier;
/** Compound code for the rendering settings. */
private transient int rendering;
/** Control for the thickness of the line. */
private transient int thickness;
/** Control for the sharpness of the line. */
private transient int sharpness;
/**
* Creates and initialises an TextSettings using values encoded in the Flash
* binary format.
*
* @param coder
* an SWFDecoder object that contains the encoded Flash data.
*
* @throws IOException
* if an error occurs while decoding the data.
*/
public TextSettings(final SWFDecoder coder) throws IOException {
if ((coder.readUnsignedShort() & Coder.LENGTH_FIELD)
== Coder.IS_EXTENDED) {
coder.readInt();
}
identifier = coder.readUnsignedShort();
rendering = coder.readByte();
thickness = coder.readInt();
sharpness = coder.readInt();
coder.readByte();
}
/**
* Creates a TextSettings object with the specified values.
*
* @param uid
* the unique identifier of an existing text field.
* @param advanced
* whether the advanced rendering engine will be used to display
* the text.
* @param grid
* how letters are aligned with respect to the pixel grid.
* @param thick
* the thickness used when anti-aliasing the text.
* @param sharp
* the sharpness used when anti-aliasing the text.
*/
public TextSettings(final int uid, final boolean advanced, final Grid grid,
final float thick, final float sharp) {
setIdentifier(uid);
useAdvanced(advanced);
setGrid(grid);
setThickness(thick);
setSharpness(sharp);
}
/**
* Creates an TextSettings object and initialised it by copying the values
* from an existing one.
*
* @param object
* a TextSettings object.
*/
public TextSettings(final TextSettings object) {
identifier = object.identifier;
rendering = object.rendering;
thickness = object.thickness;
sharpness = object.sharpness;
}
/**
* Get the unique identifier of the text definition that this object
* applies to.
*
* @return the unique identifier of the text object.
*/
public int getIdentifier() {
return identifier;
}
/**
* Sets the identifier of the text definition that this object applies to.
*
* @param uid
* the unique identifier of an DefineText, DefineText2 or
* DefineTextField object. Must be in the range 1..65535.
*/
public void setIdentifier(final int uid) {
if ((uid < 1) || (uid > Coder.USHORT_MAX)) {
throw new IllegalArgumentRangeException(
1, Coder.USHORT_MAX, uid);
}
identifier = uid;
}
/**
* Will the advanced text rendering engine, introduced in Flash 8
* be used.
*
* @return true if advanced text rendering is used, false if the standard
* rendering engine is used.
*/
public boolean useAdvanced() {
return (rendering & Coder.BIT6) != 0;
}
/**
* Sets whether the advanced text rendering engine (true) or standard engine
* (false) will be used to render the text.
*
* @param flag set true to select the advanced text rendering engine, false
* for the standard rendering engine.
*/
public void useAdvanced(final boolean flag) {
rendering |= Coder.BIT6;
}
/**
* Returns the alignment of letters with respect to the pixel grid.
*
* @return the alignment, either NONE, PIXEL or SUBPIXEL.
*/
public Grid getGrid() {
Grid alignment;
if ((rendering & Coder.BIT4) > 0) {
alignment = Grid.SUBPIXEL;
} else if ((rendering & Coder.BIT3) > 0) {
alignment = Grid.PIXEL;
} else {
alignment = Grid.NONE;
}
return alignment;
}
/**
* Selects how the text letters will be aligned with respect to the pixel
* grid used in LCD screens.
*
* @param alignment
* the alignment with respect to the pixel grid, either NONE,
* PIXEL or SUBPIXEL.
*/
public void setGrid(final Grid alignment) {
rendering &= ~(Coder.BIT3 | Coder.BIT4 | Coder.BIT5 | Coder.BIT6);
switch (alignment) {
case PIXEL:
rendering |= Coder.BIT3;
break;
case SUBPIXEL:
rendering |= Coder.BIT4;
break;
default:
break;
}
}
/**
* Get the value used to control the thickness of a line when rendered.
* May be set to 0.0 if the default anti-aliasing value will be used.
*
* @return the adjustment applied to the line thickness.
*/
public float getThickness() {
return Float.intBitsToFloat(thickness);
}
/**
* Sets the value used to control the thickness of a line when rendered. May
* be set to 0.0 if the default anti-aliasing value will be used.
*
* @param level
* the value of the thickness parameter used by the rendering
* engine.
*/
public void setThickness(final float level) {
thickness = Float.floatToIntBits(level);
}
/**
* Get the value used to control the sharpness of a line when rendered.
* May be set to 0.0 if the default anti-aliasing value will be used.
*
* @return the adjustment applied to the line sharpness.
*/
public float getSharpness() {
return Float.intBitsToFloat(sharpness);
}
/**
* Sets the value used to control the sharpness of a line when rendered. May
* be set to 0.0 if the default anti-aliasing value will be used.
*
* @param level
* the value of the sharpness parameter used by the rendering
* engine.
*/
public void setSharpness(final float level) {
this.sharpness = Float.floatToIntBits(level);
}
/** {@inheritDoc} */
public TextSettings copy() {
return new TextSettings(this);
}
@Override
public String toString() {
return String.format(FORMAT, identifier, String.valueOf(useAdvanced()),
getGrid(), thickness / Coder.SCALE_16,
sharpness / Coder.SCALE_16);
}
/** {@inheritDoc} */
public int prepareToEncode(final Context context) {
// CHECKSTYLE IGNORE MagicNumberCheck FOR NEXT 1 LINES
return 14;
}
/** {@inheritDoc} */
public void encode(final SWFEncoder coder, final Context context)
throws IOException {
// CHECKSTYLE IGNORE MagicNumberCheck FOR NEXT 2 LINES
coder.writeShort((MovieTypes.TEXT_SETTINGS << Coder.LENGTH_FIELD_SIZE)
| 12);
coder.writeShort(identifier);
coder.writeByte(rendering);
coder.writeInt(thickness);
coder.writeInt(sharpness);
coder.writeByte(0);
}
}