mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-18 18:14:38 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
import java.text.CharacterIterator;
|
||||
|
||||
class CharArrayIterator implements CharacterIterator {
|
||||
|
||||
private char[] chars;
|
||||
private int pos;
|
||||
private int begin;
|
||||
|
||||
CharArrayIterator(char[] chars) {
|
||||
|
||||
reset(chars, 0);
|
||||
}
|
||||
|
||||
CharArrayIterator(char[] chars, int begin) {
|
||||
|
||||
reset(chars, begin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position to getBeginIndex() and returns the character at that
|
||||
* position.
|
||||
* @return the first character in the text, or DONE if the text is empty
|
||||
* @see #getBeginIndex
|
||||
*/
|
||||
public char first() {
|
||||
|
||||
pos = 0;
|
||||
return current();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)
|
||||
* and returns the character at that position.
|
||||
* @return the last character in the text, or DONE if the text is empty
|
||||
* @see #getEndIndex
|
||||
*/
|
||||
public char last() {
|
||||
|
||||
if (chars.length > 0) {
|
||||
pos = chars.length-1;
|
||||
}
|
||||
else {
|
||||
pos = 0;
|
||||
}
|
||||
return current();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character at the current position (as returned by getIndex()).
|
||||
* @return the character at the current position or DONE if the current
|
||||
* position is off the end of the text.
|
||||
* @see #getIndex
|
||||
*/
|
||||
public char current() {
|
||||
|
||||
if (pos >= 0 && pos < chars.length) {
|
||||
return chars[pos];
|
||||
}
|
||||
else {
|
||||
return DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the iterator's index by one and returns the character
|
||||
* at the new index. If the resulting index is greater or equal
|
||||
* to getEndIndex(), the current index is reset to getEndIndex() and
|
||||
* a value of DONE is returned.
|
||||
* @return the character at the new position or DONE if the new
|
||||
* position is off the end of the text range.
|
||||
*/
|
||||
public char next() {
|
||||
|
||||
if (pos < chars.length-1) {
|
||||
pos++;
|
||||
return chars[pos];
|
||||
}
|
||||
else {
|
||||
pos = chars.length;
|
||||
return DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the iterator's index by one and returns the character
|
||||
* at the new index. If the current index is getBeginIndex(), the index
|
||||
* remains at getBeginIndex() and a value of DONE is returned.
|
||||
* @return the character at the new position or DONE if the current
|
||||
* position is equal to getBeginIndex().
|
||||
*/
|
||||
public char previous() {
|
||||
|
||||
if (pos > 0) {
|
||||
pos--;
|
||||
return chars[pos];
|
||||
}
|
||||
else {
|
||||
pos = 0;
|
||||
return DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position to the specified position in the text and returns that
|
||||
* character.
|
||||
* @param position the position within the text. Valid values range from
|
||||
* getBeginIndex() to getEndIndex(). An IllegalArgumentException is thrown
|
||||
* if an invalid value is supplied.
|
||||
* @return the character at the specified position or DONE if the specified position is equal to getEndIndex()
|
||||
*/
|
||||
public char setIndex(int position) {
|
||||
|
||||
position -= begin;
|
||||
if (position < 0 || position > chars.length) {
|
||||
throw new IllegalArgumentException("Invalid index");
|
||||
}
|
||||
pos = position;
|
||||
return current();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start index of the text.
|
||||
* @return the index at which the text begins.
|
||||
*/
|
||||
public int getBeginIndex() {
|
||||
return begin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end index of the text. This index is the index of the first
|
||||
* character following the end of the text.
|
||||
* @return the index after the last character in the text
|
||||
*/
|
||||
public int getEndIndex() {
|
||||
return begin+chars.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current index.
|
||||
* @return the current index.
|
||||
*/
|
||||
public int getIndex() {
|
||||
return begin+pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this iterator
|
||||
* @return A copy of this
|
||||
*/
|
||||
public Object clone() {
|
||||
CharArrayIterator c = new CharArrayIterator(chars, begin);
|
||||
c.pos = this.pos;
|
||||
return c;
|
||||
}
|
||||
|
||||
void reset(char[] chars) {
|
||||
reset(chars, 0);
|
||||
}
|
||||
|
||||
void reset(char[] chars, int begin) {
|
||||
|
||||
this.chars = chars;
|
||||
this.begin = begin;
|
||||
pos = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author Charlton Innovations, Inc.
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
import java.awt.RenderingHints;
|
||||
import static java.awt.RenderingHints.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
|
||||
/**
|
||||
* The {@code FontRenderContext} class is a container for the
|
||||
* information needed to correctly measure text. The measurement of text
|
||||
* can vary because of rules that map outlines to pixels, and rendering
|
||||
* hints provided by an application.
|
||||
* <p>
|
||||
* One such piece of information is a transform that scales
|
||||
* typographical points to pixels. (A point is defined to be exactly 1/72
|
||||
* of an inch, which is slightly different than
|
||||
* the traditional mechanical measurement of a point.) A character that
|
||||
* is rendered at 12pt on a 600dpi device might have a different size
|
||||
* than the same character rendered at 12pt on a 72dpi device because of
|
||||
* such factors as rounding to pixel boundaries and hints that the font
|
||||
* designer may have specified.
|
||||
* <p>
|
||||
* Anti-aliasing and Fractional-metrics specified by an application can also
|
||||
* affect the size of a character because of rounding to pixel
|
||||
* boundaries.
|
||||
* <p>
|
||||
* Typically, instances of {@code FontRenderContext} are
|
||||
* obtained from a {@link java.awt.Graphics2D Graphics2D} object. A
|
||||
* {@code FontRenderContext} which is directly constructed will
|
||||
* most likely not represent any actual graphics device, and may lead
|
||||
* to unexpected or incorrect results.
|
||||
* @see java.awt.RenderingHints#KEY_TEXT_ANTIALIASING
|
||||
* @see java.awt.RenderingHints#KEY_FRACTIONALMETRICS
|
||||
* @see java.awt.Graphics2D#getFontRenderContext()
|
||||
* @see java.awt.font.LineMetrics
|
||||
*/
|
||||
|
||||
public class FontRenderContext {
|
||||
private transient AffineTransform tx;
|
||||
private transient Object aaHintValue;
|
||||
private transient Object fmHintValue;
|
||||
private transient boolean defaulting;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code FontRenderContext}
|
||||
* object.
|
||||
*
|
||||
*/
|
||||
protected FontRenderContext() {
|
||||
aaHintValue = VALUE_TEXT_ANTIALIAS_DEFAULT;
|
||||
fmHintValue = VALUE_FRACTIONALMETRICS_DEFAULT;
|
||||
defaulting = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code FontRenderContext} object from an
|
||||
* optional {@link AffineTransform} and two {@code boolean}
|
||||
* values that determine if the newly constructed object has
|
||||
* anti-aliasing or fractional metrics.
|
||||
* In each case the boolean values {@code true} and {@code false}
|
||||
* correspond to the rendering hint values {@code ON} and
|
||||
* {@code OFF} respectively.
|
||||
* <p>
|
||||
* To specify other hint values, use the constructor which
|
||||
* specifies the rendering hint values as parameters :
|
||||
* {@link #FontRenderContext(AffineTransform, Object, Object)}.
|
||||
* @param tx the transform which is used to scale typographical points
|
||||
* to pixels in this {@code FontRenderContext}. If null, an
|
||||
* identity transform is used.
|
||||
* @param isAntiAliased determines if the newly constructed object
|
||||
* has anti-aliasing.
|
||||
* @param usesFractionalMetrics determines if the newly constructed
|
||||
* object has fractional metrics.
|
||||
*/
|
||||
public FontRenderContext(AffineTransform tx,
|
||||
boolean isAntiAliased,
|
||||
boolean usesFractionalMetrics) {
|
||||
if (tx != null && !tx.isIdentity()) {
|
||||
this.tx = new AffineTransform(tx);
|
||||
}
|
||||
if (isAntiAliased) {
|
||||
aaHintValue = VALUE_TEXT_ANTIALIAS_ON;
|
||||
} else {
|
||||
aaHintValue = VALUE_TEXT_ANTIALIAS_OFF;
|
||||
}
|
||||
if (usesFractionalMetrics) {
|
||||
fmHintValue = VALUE_FRACTIONALMETRICS_ON;
|
||||
} else {
|
||||
fmHintValue = VALUE_FRACTIONALMETRICS_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code FontRenderContext} object from an
|
||||
* optional {@link AffineTransform} and two {@code Object}
|
||||
* values that determine if the newly constructed object has
|
||||
* anti-aliasing or fractional metrics.
|
||||
* @param tx the transform which is used to scale typographical points
|
||||
* to pixels in this {@code FontRenderContext}. If null, an
|
||||
* identity transform is used.
|
||||
* @param aaHint - one of the text antialiasing rendering hint values
|
||||
* defined in {@link java.awt.RenderingHints java.awt.RenderingHints}.
|
||||
* Any other value will throw {@code IllegalArgumentException}.
|
||||
* {@link java.awt.RenderingHints#VALUE_TEXT_ANTIALIAS_DEFAULT VALUE_TEXT_ANTIALIAS_DEFAULT}
|
||||
* may be specified, in which case the mode used is implementation
|
||||
* dependent.
|
||||
* @param fmHint - one of the text fractional rendering hint values defined
|
||||
* in {@link java.awt.RenderingHints java.awt.RenderingHints}.
|
||||
* {@link java.awt.RenderingHints#VALUE_FRACTIONALMETRICS_DEFAULT VALUE_FRACTIONALMETRICS_DEFAULT}
|
||||
* may be specified, in which case the mode used is implementation
|
||||
* dependent.
|
||||
* Any other value will throw {@code IllegalArgumentException}
|
||||
* @throws IllegalArgumentException if the hints are not one of the
|
||||
* legal values.
|
||||
* @since 1.6
|
||||
*/
|
||||
public FontRenderContext(AffineTransform tx, Object aaHint, Object fmHint){
|
||||
if (tx != null && !tx.isIdentity()) {
|
||||
this.tx = new AffineTransform(tx);
|
||||
}
|
||||
try {
|
||||
if (KEY_TEXT_ANTIALIASING.isCompatibleValue(aaHint)) {
|
||||
aaHintValue = aaHint;
|
||||
} else {
|
||||
throw new IllegalArgumentException("AA hint:" + aaHint);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("AA hint:" +aaHint);
|
||||
}
|
||||
try {
|
||||
if (KEY_FRACTIONALMETRICS.isCompatibleValue(fmHint)) {
|
||||
fmHintValue = fmHint;
|
||||
} else {
|
||||
throw new IllegalArgumentException("FM hint:" + fmHint);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("FM hint:" +fmHint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not this {@code FontRenderContext} object
|
||||
* measures text in a transformed render context.
|
||||
* @return {@code true} if this {@code FontRenderContext}
|
||||
* object has a non-identity AffineTransform attribute.
|
||||
* {@code false} otherwise.
|
||||
* @see java.awt.font.FontRenderContext#getTransform
|
||||
* @since 1.6
|
||||
*/
|
||||
public boolean isTransformed() {
|
||||
if (!defaulting) {
|
||||
return tx != null;
|
||||
} else {
|
||||
return !getTransform().isIdentity();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer type of the affine transform for this
|
||||
* {@code FontRenderContext} as specified by
|
||||
* {@link java.awt.geom.AffineTransform#getType()}
|
||||
* @return the type of the transform.
|
||||
* @see AffineTransform
|
||||
* @since 1.6
|
||||
*/
|
||||
public int getTransformType() {
|
||||
if (!defaulting) {
|
||||
if (tx == null) {
|
||||
return AffineTransform.TYPE_IDENTITY;
|
||||
} else {
|
||||
return tx.getType();
|
||||
}
|
||||
} else {
|
||||
return getTransform().getType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the transform that is used to scale typographical points
|
||||
* to pixels in this {@code FontRenderContext}.
|
||||
* @return the {@code AffineTransform} of this
|
||||
* {@code FontRenderContext}.
|
||||
* @see AffineTransform
|
||||
*/
|
||||
public AffineTransform getTransform() {
|
||||
return (tx == null) ? new AffineTransform() : new AffineTransform(tx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean which indicates whether or not some form of
|
||||
* antialiasing is specified by this {@code FontRenderContext}.
|
||||
* Call {@link #getAntiAliasingHint() getAntiAliasingHint()}
|
||||
* for the specific rendering hint value.
|
||||
* @return {@code true}, if text is anti-aliased in this
|
||||
* {@code FontRenderContext}; {@code false} otherwise.
|
||||
* @see java.awt.RenderingHints#KEY_TEXT_ANTIALIASING
|
||||
* @see #FontRenderContext(AffineTransform,boolean,boolean)
|
||||
* @see #FontRenderContext(AffineTransform,Object,Object)
|
||||
*/
|
||||
public boolean isAntiAliased() {
|
||||
return !(aaHintValue == VALUE_TEXT_ANTIALIAS_OFF ||
|
||||
aaHintValue == VALUE_TEXT_ANTIALIAS_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean which whether text fractional metrics mode
|
||||
* is used in this {@code FontRenderContext}.
|
||||
* Call {@link #getFractionalMetricsHint() getFractionalMetricsHint()}
|
||||
* to obtain the corresponding rendering hint value.
|
||||
* @return {@code true}, if layout should be performed with
|
||||
* fractional metrics; {@code false} otherwise.
|
||||
* in this {@code FontRenderContext}.
|
||||
* @see java.awt.RenderingHints#KEY_FRACTIONALMETRICS
|
||||
* @see #FontRenderContext(AffineTransform,boolean,boolean)
|
||||
* @see #FontRenderContext(AffineTransform,Object,Object)
|
||||
*/
|
||||
public boolean usesFractionalMetrics() {
|
||||
return !(fmHintValue == VALUE_FRACTIONALMETRICS_OFF ||
|
||||
fmHintValue == VALUE_FRACTIONALMETRICS_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the text anti-aliasing rendering mode hint used in this
|
||||
* {@code FontRenderContext}.
|
||||
* This will be one of the text antialiasing rendering hint values
|
||||
* defined in {@link java.awt.RenderingHints java.awt.RenderingHints}.
|
||||
* @return text anti-aliasing rendering mode hint used in this
|
||||
* {@code FontRenderContext}.
|
||||
* @since 1.6
|
||||
*/
|
||||
public Object getAntiAliasingHint() {
|
||||
if (defaulting) {
|
||||
if (isAntiAliased()) {
|
||||
return VALUE_TEXT_ANTIALIAS_ON;
|
||||
} else {
|
||||
return VALUE_TEXT_ANTIALIAS_OFF;
|
||||
}
|
||||
}
|
||||
return aaHintValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the text fractional metrics rendering mode hint used in this
|
||||
* {@code FontRenderContext}.
|
||||
* This will be one of the text fractional metrics rendering hint values
|
||||
* defined in {@link java.awt.RenderingHints java.awt.RenderingHints}.
|
||||
* @return the text fractional metrics rendering mode hint used in this
|
||||
* {@code FontRenderContext}.
|
||||
* @since 1.6
|
||||
*/
|
||||
public Object getFractionalMetricsHint() {
|
||||
if (defaulting) {
|
||||
if (usesFractionalMetrics()) {
|
||||
return VALUE_FRACTIONALMETRICS_ON;
|
||||
} else {
|
||||
return VALUE_FRACTIONALMETRICS_OFF;
|
||||
}
|
||||
}
|
||||
return fmHintValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if obj is an instance of FontRenderContext and has the same
|
||||
* transform, antialiasing, and fractional metrics values as this.
|
||||
* @param obj the object to test for equality
|
||||
* @return {@code true} if the specified object is equal to
|
||||
* this {@code FontRenderContext}; {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
try {
|
||||
return equals((FontRenderContext)obj);
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if rhs has the same transform, antialiasing,
|
||||
* and fractional metrics values as this.
|
||||
* @param rhs the {@code FontRenderContext} to test for equality
|
||||
* @return {@code true} if {@code rhs} is equal to
|
||||
* this {@code FontRenderContext}; {@code false}
|
||||
* otherwise.
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean equals(FontRenderContext rhs) {
|
||||
if (this == rhs) {
|
||||
return true;
|
||||
}
|
||||
if (rhs == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* if neither instance is a subclass, reference values directly. */
|
||||
if (!rhs.defaulting && !defaulting) {
|
||||
if (rhs.aaHintValue == aaHintValue &&
|
||||
rhs.fmHintValue == fmHintValue) {
|
||||
|
||||
return tx == null ? rhs.tx == null : tx.equals(rhs.tx);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return
|
||||
rhs.getAntiAliasingHint() == getAntiAliasingHint() &&
|
||||
rhs.getFractionalMetricsHint() == getFractionalMetricsHint() &&
|
||||
rhs.getTransform().equals(getTransform());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hashcode for this FontRenderContext.
|
||||
*/
|
||||
public int hashCode() {
|
||||
int hash = tx == null ? 0 : tx.hashCode();
|
||||
/* SunHints value objects have identity hashcode, so we can rely on
|
||||
* this to ensure that two equal FRC's have the same hashcode.
|
||||
*/
|
||||
if (defaulting) {
|
||||
hash += getAntiAliasingHint().hashCode();
|
||||
hash += getFractionalMetricsHint().hashCode();
|
||||
} else {
|
||||
hash += aaHintValue.hashCode();
|
||||
hash += fmHintValue.hashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is
|
||||
* copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
|
||||
* of IBM. These materials are provided under terms of a License
|
||||
* Agreement between Taligent and Sun. This technology is protected
|
||||
* by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
/**
|
||||
* The {@code GlyphJustificationInfo} class represents information
|
||||
* about the justification properties of a glyph. A glyph is the visual
|
||||
* representation of one or more characters. Many different glyphs can
|
||||
* be used to represent a single character or combination of characters.
|
||||
* The four justification properties represented by
|
||||
* {@code GlyphJustificationInfo} are weight, priority, absorb and
|
||||
* limit.
|
||||
* <p>
|
||||
* Weight is the overall 'weight' of the glyph in the line. Generally it is
|
||||
* proportional to the size of the font. Glyphs with larger weight are
|
||||
* allocated a correspondingly larger amount of the change in space.
|
||||
* <p>
|
||||
* Priority determines the justification phase in which this glyph is used.
|
||||
* All glyphs of the same priority are examined before glyphs of the next
|
||||
* priority. If all the change in space can be allocated to these glyphs
|
||||
* without exceeding their limits, then glyphs of the next priority are not
|
||||
* examined. There are four priorities, kashida, whitespace, interchar,
|
||||
* and none. KASHIDA is the first priority examined. NONE is the last
|
||||
* priority examined.
|
||||
* <p>
|
||||
* Absorb determines whether a glyph absorbs all change in space. Within a
|
||||
* given priority, some glyphs may absorb all the change in space. If any of
|
||||
* these glyphs are present, no glyphs of later priority are examined.
|
||||
* <p>
|
||||
* Limit determines the maximum or minimum amount by which the glyph can
|
||||
* change. Left and right sides of the glyph can have different limits.
|
||||
* <p>
|
||||
* Each {@code GlyphJustificationInfo} represents two sets of
|
||||
* metrics, which are <i>growing</i> and <i>shrinking</i>. Growing
|
||||
* metrics are used when the glyphs on a line are to be
|
||||
* spread apart to fit a larger width. Shrinking metrics are used when
|
||||
* the glyphs are to be moved together to fit a smaller width.
|
||||
*/
|
||||
|
||||
public final class GlyphJustificationInfo {
|
||||
|
||||
/**
|
||||
* Constructs information about the justification properties of a
|
||||
* glyph.
|
||||
* @param weight the weight of this glyph when allocating space. Must be non-negative.
|
||||
* @param growAbsorb if {@code true} this glyph absorbs
|
||||
* all extra space at this priority and lower priority levels when it
|
||||
* grows
|
||||
* @param growPriority the priority level of this glyph when it
|
||||
* grows
|
||||
* @param growLeftLimit the maximum amount by which the left side of this
|
||||
* glyph can grow. Must be non-negative.
|
||||
* @param growRightLimit the maximum amount by which the right side of this
|
||||
* glyph can grow. Must be non-negative.
|
||||
* @param shrinkAbsorb if {@code true}, this glyph absorbs all
|
||||
* remaining shrinkage at this and lower priority levels when it
|
||||
* shrinks
|
||||
* @param shrinkPriority the priority level of this glyph when
|
||||
* it shrinks
|
||||
* @param shrinkLeftLimit the maximum amount by which the left side of this
|
||||
* glyph can shrink. Must be non-negative.
|
||||
* @param shrinkRightLimit the maximum amount by which the right side
|
||||
* of this glyph can shrink. Must be non-negative.
|
||||
*/
|
||||
public GlyphJustificationInfo(float weight,
|
||||
boolean growAbsorb,
|
||||
int growPriority,
|
||||
float growLeftLimit,
|
||||
float growRightLimit,
|
||||
boolean shrinkAbsorb,
|
||||
int shrinkPriority,
|
||||
float shrinkLeftLimit,
|
||||
float shrinkRightLimit)
|
||||
{
|
||||
if (weight < 0) {
|
||||
throw new IllegalArgumentException("weight is negative");
|
||||
}
|
||||
|
||||
if (!priorityIsValid(growPriority)) {
|
||||
throw new IllegalArgumentException("Invalid grow priority");
|
||||
}
|
||||
if (growLeftLimit < 0) {
|
||||
throw new IllegalArgumentException("growLeftLimit is negative");
|
||||
}
|
||||
if (growRightLimit < 0) {
|
||||
throw new IllegalArgumentException("growRightLimit is negative");
|
||||
}
|
||||
|
||||
if (!priorityIsValid(shrinkPriority)) {
|
||||
throw new IllegalArgumentException("Invalid shrink priority");
|
||||
}
|
||||
if (shrinkLeftLimit < 0) {
|
||||
throw new IllegalArgumentException("shrinkLeftLimit is negative");
|
||||
}
|
||||
if (shrinkRightLimit < 0) {
|
||||
throw new IllegalArgumentException("shrinkRightLimit is negative");
|
||||
}
|
||||
|
||||
this.weight = weight;
|
||||
this.growAbsorb = growAbsorb;
|
||||
this.growPriority = growPriority;
|
||||
this.growLeftLimit = growLeftLimit;
|
||||
this.growRightLimit = growRightLimit;
|
||||
this.shrinkAbsorb = shrinkAbsorb;
|
||||
this.shrinkPriority = shrinkPriority;
|
||||
this.shrinkLeftLimit = shrinkLeftLimit;
|
||||
this.shrinkRightLimit = shrinkRightLimit;
|
||||
}
|
||||
|
||||
private static boolean priorityIsValid(int priority) {
|
||||
|
||||
return priority >= PRIORITY_KASHIDA && priority <= PRIORITY_NONE;
|
||||
}
|
||||
|
||||
/** The highest justification priority. */
|
||||
public static final int PRIORITY_KASHIDA = 0;
|
||||
|
||||
/** The second highest justification priority. */
|
||||
public static final int PRIORITY_WHITESPACE = 1;
|
||||
|
||||
/** The second lowest justification priority. */
|
||||
public static final int PRIORITY_INTERCHAR = 2;
|
||||
|
||||
/** The lowest justification priority. */
|
||||
public static final int PRIORITY_NONE = 3;
|
||||
|
||||
/**
|
||||
* The weight of this glyph.
|
||||
*/
|
||||
public final float weight;
|
||||
|
||||
/**
|
||||
* The priority level of this glyph as it is growing.
|
||||
*/
|
||||
public final int growPriority;
|
||||
|
||||
/**
|
||||
* If {@code true}, this glyph absorbs all extra
|
||||
* space at this and lower priority levels when it grows.
|
||||
*/
|
||||
public final boolean growAbsorb;
|
||||
|
||||
/**
|
||||
* The maximum amount by which the left side of this glyph can grow.
|
||||
*/
|
||||
public final float growLeftLimit;
|
||||
|
||||
/**
|
||||
* The maximum amount by which the right side of this glyph can grow.
|
||||
*/
|
||||
public final float growRightLimit;
|
||||
|
||||
/**
|
||||
* The priority level of this glyph as it is shrinking.
|
||||
*/
|
||||
public final int shrinkPriority;
|
||||
|
||||
/**
|
||||
* If {@code true},this glyph absorbs all remaining shrinkage at
|
||||
* this and lower priority levels as it shrinks.
|
||||
*/
|
||||
public final boolean shrinkAbsorb;
|
||||
|
||||
/**
|
||||
* The maximum amount by which the left side of this glyph can shrink
|
||||
* (a positive number).
|
||||
*/
|
||||
public final float shrinkLeftLimit;
|
||||
|
||||
/**
|
||||
* The maximum amount by which the right side of this glyph can shrink
|
||||
* (a positive number).
|
||||
*/
|
||||
public final float shrinkRightLimit;
|
||||
}
|
324
src/java.desktop/share/classes/java/awt/font/GlyphMetrics.java
Normal file
324
src/java.desktop/share/classes/java/awt/font/GlyphMetrics.java
Normal file
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is
|
||||
* copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
|
||||
* of IBM. These materials are provided under terms of a License
|
||||
* Agreement between Taligent and Sun. This technology is protected
|
||||
* by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* The {@code GlyphMetrics} class represents information for a
|
||||
* single glyph. A glyph is the visual representation of one or more
|
||||
* characters. Many different glyphs can be used to represent a single
|
||||
* character or combination of characters. {@code GlyphMetrics}
|
||||
* instances are produced by {@link java.awt.Font Font} and are applicable
|
||||
* to a specific glyph in a particular {@code Font}.
|
||||
* <p>
|
||||
* Glyphs are either STANDARD, LIGATURE, COMBINING, or COMPONENT.
|
||||
* <ul>
|
||||
* <li>STANDARD glyphs are commonly used to represent single characters.
|
||||
* <li>LIGATURE glyphs are used to represent sequences of characters.
|
||||
* <li>COMPONENT glyphs in a {@link GlyphVector} do not correspond to a
|
||||
* particular character in a text model. Instead, COMPONENT glyphs are
|
||||
* added for typographical reasons, such as Arabic justification.
|
||||
* <li>COMBINING glyphs embellish STANDARD or LIGATURE glyphs, such
|
||||
* as accent marks. Carets do not appear before COMBINING glyphs.
|
||||
* </ul>
|
||||
* <p>
|
||||
* Other metrics available through {@code GlyphMetrics} are the
|
||||
* components of the advance, the visual bounds, and the left and right
|
||||
* side bearings.
|
||||
* <p>
|
||||
* Glyphs for a rotated font, or obtained from a {@code GlyphVector}
|
||||
* which has applied a rotation to the glyph, can have advances that
|
||||
* contain both X and Y components. Usually the advance only has one
|
||||
* component.
|
||||
* <p>
|
||||
* The advance of a glyph is the distance from the glyph's origin to the
|
||||
* origin of the next glyph along the baseline, which is either vertical
|
||||
* or horizontal. Note that, in a {@code GlyphVector},
|
||||
* the distance from a glyph to its following glyph might not be the
|
||||
* glyph's advance, because of kerning or other positioning adjustments.
|
||||
* <p>
|
||||
* The bounds is the smallest rectangle that completely contains the
|
||||
* outline of the glyph. The bounds rectangle is relative to the
|
||||
* glyph's origin. The left-side bearing is the distance from the glyph
|
||||
* origin to the left of its bounds rectangle. If the left-side bearing is
|
||||
* negative, part of the glyph is drawn to the left of its origin. The
|
||||
* right-side bearing is the distance from the right side of the bounds
|
||||
* rectangle to the next glyph origin (the origin plus the advance). If
|
||||
* negative, part of the glyph is drawn to the right of the next glyph's
|
||||
* origin. Note that the bounds does not necessarily enclose all the pixels
|
||||
* affected when rendering the glyph, because of rasterization and pixel
|
||||
* adjustment effects.
|
||||
* <p>
|
||||
* Although instances of {@code GlyphMetrics} can be directly
|
||||
* constructed, they are almost always obtained from a
|
||||
* {@code GlyphVector}. Once constructed, {@code GlyphMetrics}
|
||||
* objects are immutable.
|
||||
* <p>
|
||||
* <strong>Example</strong>:<p>
|
||||
* Querying a {@code Font} for glyph information
|
||||
* <blockquote><pre>
|
||||
* Font font = ...;
|
||||
* int glyphIndex = ...;
|
||||
* GlyphMetrics metrics = GlyphVector.getGlyphMetrics(glyphIndex);
|
||||
* int isStandard = metrics.isStandard();
|
||||
* float glyphAdvance = metrics.getAdvance();
|
||||
* </pre></blockquote>
|
||||
* @see java.awt.Font
|
||||
* @see GlyphVector
|
||||
*/
|
||||
|
||||
public final class GlyphMetrics {
|
||||
/**
|
||||
* Indicates whether the metrics are for a horizontal or vertical baseline.
|
||||
*/
|
||||
private boolean horizontal;
|
||||
|
||||
/**
|
||||
* The x-component of the advance.
|
||||
*/
|
||||
private float advanceX;
|
||||
|
||||
/**
|
||||
* The y-component of the advance.
|
||||
*/
|
||||
private float advanceY;
|
||||
|
||||
/**
|
||||
* The bounds of the associated glyph.
|
||||
*/
|
||||
private Rectangle2D.Float bounds;
|
||||
|
||||
/**
|
||||
* Additional information about the glyph encoded as a byte.
|
||||
*/
|
||||
private byte glyphType;
|
||||
|
||||
/**
|
||||
* Indicates a glyph that represents a single standard
|
||||
* character.
|
||||
*/
|
||||
public static final byte STANDARD = 0;
|
||||
|
||||
/**
|
||||
* Indicates a glyph that represents multiple characters
|
||||
* as a ligature, for example 'fi' or 'ffi'. It is followed by
|
||||
* filler glyphs for the remaining characters. Filler and combining
|
||||
* glyphs can be intermixed to control positioning of accent marks
|
||||
* on the logically preceding ligature.
|
||||
*/
|
||||
public static final byte LIGATURE = 1;
|
||||
|
||||
/**
|
||||
* Indicates a glyph that represents a combining character,
|
||||
* such as an umlaut. There is no caret position between this glyph
|
||||
* and the preceding glyph.
|
||||
*/
|
||||
public static final byte COMBINING = 2;
|
||||
|
||||
/**
|
||||
* Indicates a glyph with no corresponding character in the
|
||||
* backing store. The glyph is associated with the character
|
||||
* represented by the logically preceding non-component glyph. This
|
||||
* is used for kashida justification or other visual modifications to
|
||||
* existing glyphs. There is no caret position between this glyph
|
||||
* and the preceding glyph.
|
||||
*/
|
||||
public static final byte COMPONENT = 3;
|
||||
|
||||
/**
|
||||
* Indicates a glyph with no visual representation. It can
|
||||
* be added to the other code values to indicate an invisible glyph.
|
||||
*/
|
||||
public static final byte WHITESPACE = 4;
|
||||
|
||||
/**
|
||||
* Constructs a {@code GlyphMetrics} object.
|
||||
* @param advance the advance width of the glyph
|
||||
* @param bounds the black box bounds of the glyph
|
||||
* @param glyphType the type of the glyph
|
||||
*/
|
||||
public GlyphMetrics(float advance, Rectangle2D bounds, byte glyphType) {
|
||||
this.horizontal = true;
|
||||
this.advanceX = advance;
|
||||
this.advanceY = 0;
|
||||
this.bounds = new Rectangle2D.Float();
|
||||
this.bounds.setRect(bounds);
|
||||
this.glyphType = glyphType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code GlyphMetrics} object.
|
||||
* @param horizontal if true, metrics are for a horizontal baseline,
|
||||
* otherwise they are for a vertical baseline
|
||||
* @param advanceX the X-component of the glyph's advance
|
||||
* @param advanceY the Y-component of the glyph's advance
|
||||
* @param bounds the visual bounds of the glyph
|
||||
* @param glyphType the type of the glyph
|
||||
* @since 1.4
|
||||
*/
|
||||
public GlyphMetrics(boolean horizontal, float advanceX, float advanceY,
|
||||
Rectangle2D bounds, byte glyphType) {
|
||||
|
||||
this.horizontal = horizontal;
|
||||
this.advanceX = advanceX;
|
||||
this.advanceY = advanceY;
|
||||
this.bounds = new Rectangle2D.Float();
|
||||
this.bounds.setRect(bounds);
|
||||
this.glyphType = glyphType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the advance of the glyph along the baseline (either
|
||||
* horizontal or vertical).
|
||||
* @return the advance of the glyph
|
||||
*/
|
||||
public float getAdvance() {
|
||||
return horizontal ? advanceX : advanceY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the x-component of the advance of the glyph.
|
||||
* @return the x-component of the advance of the glyph
|
||||
* @since 1.4
|
||||
*/
|
||||
public float getAdvanceX() {
|
||||
return advanceX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the y-component of the advance of the glyph.
|
||||
* @return the y-component of the advance of the glyph
|
||||
* @since 1.4
|
||||
*/
|
||||
public float getAdvanceY() {
|
||||
return advanceY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bounds of the glyph. This is the bounding box of the glyph outline.
|
||||
* Because of rasterization and pixel alignment effects, it does not necessarily
|
||||
* enclose the pixels that are affected when rendering the glyph.
|
||||
* @return a {@link Rectangle2D} that is the bounds of the glyph.
|
||||
*/
|
||||
public Rectangle2D getBounds2D() {
|
||||
return new Rectangle2D.Float(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the left (top) side bearing of the glyph.
|
||||
* <p>
|
||||
* This is the distance from 0, 0 to the left (top) of the glyph
|
||||
* bounds. If the bounds of the glyph is to the left of (above) the
|
||||
* origin, the LSB is negative.
|
||||
* @return the left side bearing of the glyph.
|
||||
*/
|
||||
public float getLSB() {
|
||||
return horizontal ? bounds.x : bounds.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the right (bottom) side bearing of the glyph.
|
||||
* <p>
|
||||
* This is the distance from the right (bottom) of the glyph bounds to
|
||||
* the advance. If the bounds of the glyph is to the right of (below)
|
||||
* the advance, the RSB is negative.
|
||||
* @return the right side bearing of the glyph.
|
||||
*/
|
||||
public float getRSB() {
|
||||
return horizontal ?
|
||||
advanceX - bounds.x - bounds.width :
|
||||
advanceY - bounds.y - bounds.height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw glyph type code.
|
||||
* @return the raw glyph type code.
|
||||
*/
|
||||
public int getType() {
|
||||
return glyphType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a standard glyph.
|
||||
* @return {@code true} if this is a standard glyph;
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public boolean isStandard() {
|
||||
return (glyphType & 0x3) == STANDARD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a ligature glyph.
|
||||
* @return {@code true} if this is a ligature glyph;
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public boolean isLigature() {
|
||||
return (glyphType & 0x3) == LIGATURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a combining glyph.
|
||||
* @return {@code true} if this is a combining glyph;
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public boolean isCombining() {
|
||||
return (glyphType & 0x3) == COMBINING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a component glyph.
|
||||
* @return {@code true} if this is a component glyph;
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public boolean isComponent() {
|
||||
return (glyphType & 0x3) == COMPONENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a whitespace glyph.
|
||||
* @return {@code true} if this is a whitespace glyph;
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public boolean isWhitespace() {
|
||||
return (glyphType & 0x4) == WHITESPACE;
|
||||
}
|
||||
}
|
611
src/java.desktop/share/classes/java/awt/font/GlyphVector.java
Normal file
611
src/java.desktop/share/classes/java/awt/font/GlyphVector.java
Normal file
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author Charlton Innovations, Inc.
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Font;
|
||||
import java.awt.Polygon; // remind - need a floating point version
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.Shape;
|
||||
import java.awt.font.GlyphMetrics;
|
||||
import java.awt.font.GlyphJustificationInfo;
|
||||
|
||||
/**
|
||||
* A {@code GlyphVector} object is a collection of glyphs
|
||||
* containing geometric information for the placement of each glyph
|
||||
* in a transformed coordinate space which corresponds to the
|
||||
* device on which the {@code GlyphVector} is ultimately
|
||||
* displayed.
|
||||
* <p>
|
||||
* The {@code GlyphVector} does not attempt any interpretation of
|
||||
* the sequence of glyphs it contains. Relationships between adjacent
|
||||
* glyphs in sequence are solely used to determine the placement of
|
||||
* the glyphs in the visual coordinate space.
|
||||
* <p>
|
||||
* Instances of {@code GlyphVector} are created by a {@link Font}.
|
||||
* <p>
|
||||
* In a text processing application that can cache intermediate
|
||||
* representations of text, creation and subsequent caching of a
|
||||
* {@code GlyphVector} for use during rendering is the fastest
|
||||
* method to present the visual representation of characters to a user.
|
||||
* <p>
|
||||
* A {@code GlyphVector} is associated with exactly one
|
||||
* {@code Font}, and can provide data useful only in relation to
|
||||
* this {@code Font}. In addition, metrics obtained from a
|
||||
* {@code GlyphVector} are not generally geometrically scalable
|
||||
* since the pixelization and spacing are dependent on grid-fitting
|
||||
* algorithms within a {@code Font}. To facilitate accurate
|
||||
* measurement of a {@code GlyphVector} and its component
|
||||
* glyphs, you must specify a scaling transform, anti-alias mode, and
|
||||
* fractional metrics mode when creating the {@code GlyphVector}.
|
||||
* These characteristics can be derived from the destination device.
|
||||
* <p>
|
||||
* For each glyph in the {@code GlyphVector}, you can obtain:
|
||||
* <ul>
|
||||
* <li>the position of the glyph
|
||||
* <li>the transform associated with the glyph
|
||||
* <li>the metrics of the glyph in the context of the
|
||||
* {@code GlyphVector}. The metrics of the glyph may be
|
||||
* different under different transforms, application specified
|
||||
* rendering hints, and the specific instance of the glyph within
|
||||
* the {@code GlyphVector}.
|
||||
* </ul>
|
||||
* <p>
|
||||
* Altering the data used to create the {@code GlyphVector} does not
|
||||
* alter the state of the {@code GlyphVector}.
|
||||
* <p>
|
||||
* Methods are provided to adjust the positions of the glyphs
|
||||
* within the {@code GlyphVector}. These methods are most
|
||||
* appropriate for applications that are performing justification
|
||||
* operations for the presentation of the glyphs.
|
||||
* <p>
|
||||
* Methods are provided to transform individual glyphs within the
|
||||
* {@code GlyphVector}. These methods are primarily useful for
|
||||
* special effects.
|
||||
* <p>
|
||||
* Methods are provided to return both the visual, logical, and pixel bounds
|
||||
* of the entire {@code GlyphVector} or of individual glyphs within
|
||||
* the {@code GlyphVector}.
|
||||
* <p>
|
||||
* Methods are provided to return a {@link Shape} for the
|
||||
* {@code GlyphVector}, and for individual glyphs within the
|
||||
* {@code GlyphVector}.
|
||||
* @see Font
|
||||
* @see GlyphMetrics
|
||||
* @see TextLayout
|
||||
* @author Charlton Innovations, Inc.
|
||||
*/
|
||||
|
||||
public abstract class GlyphVector implements Cloneable {
|
||||
|
||||
//
|
||||
// methods associated with creation-time state
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns the {@code Font} associated with this
|
||||
* {@code GlyphVector}.
|
||||
* @return {@code Font} used to create this
|
||||
* {@code GlyphVector}.
|
||||
* @see Font
|
||||
*/
|
||||
public abstract Font getFont();
|
||||
|
||||
/**
|
||||
* Returns the {@link FontRenderContext} associated with this
|
||||
* {@code GlyphVector}.
|
||||
* @return {@code FontRenderContext} used to create this
|
||||
* {@code GlyphVector}.
|
||||
* @see FontRenderContext
|
||||
* @see Font
|
||||
*/
|
||||
public abstract FontRenderContext getFontRenderContext();
|
||||
|
||||
//
|
||||
// methods associated with the GlyphVector as a whole
|
||||
//
|
||||
|
||||
/**
|
||||
* Assigns default positions to each glyph in this
|
||||
* {@code GlyphVector}. This can destroy information
|
||||
* generated during initial layout of this {@code GlyphVector}.
|
||||
*/
|
||||
public abstract void performDefaultLayout();
|
||||
|
||||
/**
|
||||
* Returns the number of glyphs in this {@code GlyphVector}.
|
||||
* @return number of glyphs in this {@code GlyphVector}.
|
||||
*/
|
||||
public abstract int getNumGlyphs();
|
||||
|
||||
/**
|
||||
* Returns the glyphcode of the specified glyph.
|
||||
* This return value is meaningless to anything other
|
||||
* than the {@code Font} object that created this
|
||||
* {@code GlyphVector}.
|
||||
* @param glyphIndex the index into this {@code GlyphVector}
|
||||
* that corresponds to the glyph from which to retrieve the
|
||||
* glyphcode.
|
||||
* @return the glyphcode of the glyph at the specified
|
||||
* {@code glyphIndex}.
|
||||
* @throws IndexOutOfBoundsException if {@code glyphIndex}
|
||||
* is less than 0 or greater than or equal to the
|
||||
* number of glyphs in this {@code GlyphVector}
|
||||
*/
|
||||
public abstract int getGlyphCode(int glyphIndex);
|
||||
|
||||
/**
|
||||
* Returns an array of glyphcodes for the specified glyphs.
|
||||
* The contents of this return value are meaningless to anything other
|
||||
* than the {@code Font} used to create this
|
||||
* {@code GlyphVector}. This method is used
|
||||
* for convenience and performance when processing glyphcodes.
|
||||
* If no array is passed in, a new array is created.
|
||||
* @param beginGlyphIndex the index into this
|
||||
* {@code GlyphVector} at which to start retrieving glyphcodes
|
||||
* @param numEntries the number of glyphcodes to retrieve
|
||||
* @param codeReturn the array that receives the glyphcodes and is
|
||||
* then returned
|
||||
* @return an array of glyphcodes for the specified glyphs.
|
||||
* @throws IllegalArgumentException if {@code numEntries} is
|
||||
* less than 0
|
||||
* @throws IndexOutOfBoundsException if {@code beginGlyphIndex}
|
||||
* is less than 0
|
||||
* @throws IndexOutOfBoundsException if the sum of
|
||||
* {@code beginGlyphIndex} and {@code numEntries} is
|
||||
* greater than the number of glyphs in this
|
||||
* {@code GlyphVector}
|
||||
*/
|
||||
public abstract int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
|
||||
int[] codeReturn);
|
||||
|
||||
/**
|
||||
* Returns the character index of the specified glyph.
|
||||
* The character index is the index of the first logical
|
||||
* character represented by the glyph. The default
|
||||
* implementation assumes a one-to-one, left-to-right mapping
|
||||
* of glyphs to characters.
|
||||
* @param glyphIndex the index of the glyph
|
||||
* @return the index of the first character represented by the glyph
|
||||
* @since 1.4
|
||||
*/
|
||||
public int getGlyphCharIndex(int glyphIndex) {
|
||||
return glyphIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character indices of the specified glyphs.
|
||||
* The character index is the index of the first logical
|
||||
* character represented by the glyph. Indices are returned
|
||||
* in glyph order. The default implementation invokes
|
||||
* getGlyphCharIndex for each glyph, and subclassers will probably
|
||||
* want to override this implementation for performance reasons.
|
||||
* Use this method for convenience and performance
|
||||
* in processing of glyphcodes. If no array is passed in,
|
||||
* a new array is created.
|
||||
* @param beginGlyphIndex the index of the first glyph
|
||||
* @param numEntries the number of glyph indices
|
||||
* @param codeReturn the array into which to return the character indices
|
||||
* @return an array of character indices, one per glyph.
|
||||
* @since 1.4
|
||||
*/
|
||||
public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries,
|
||||
int[] codeReturn) {
|
||||
if (codeReturn == null) {
|
||||
codeReturn = new int[numEntries];
|
||||
}
|
||||
for (int i = 0, j = beginGlyphIndex; i < numEntries; ++i, ++j) {
|
||||
codeReturn[i] = getGlyphCharIndex(j);
|
||||
}
|
||||
return codeReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logical bounds of this {@code GlyphVector}.
|
||||
* This method is used when positioning this {@code GlyphVector}
|
||||
* in relation to visually adjacent {@code GlyphVector} objects.
|
||||
* @return a {@link Rectangle2D} that is the logical bounds of this
|
||||
* {@code GlyphVector}.
|
||||
*/
|
||||
public abstract Rectangle2D getLogicalBounds();
|
||||
|
||||
/**
|
||||
* Returns the visual bounds of this {@code GlyphVector}
|
||||
* The visual bounds is the bounding box of the outline of this
|
||||
* {@code GlyphVector}. Because of rasterization and
|
||||
* alignment of pixels, it is possible that this box does not
|
||||
* enclose all pixels affected by rendering this {@code GlyphVector}.
|
||||
* @return a {@code Rectangle2D} that is the bounding box
|
||||
* of this {@code GlyphVector}.
|
||||
*/
|
||||
public abstract Rectangle2D getVisualBounds();
|
||||
|
||||
/**
|
||||
* Returns the pixel bounds of this {@code GlyphVector} when
|
||||
* rendered in a graphics with the given
|
||||
* {@code FontRenderContext} at the given location. The
|
||||
* renderFRC need not be the same as the
|
||||
* {@code FontRenderContext} of this
|
||||
* {@code GlyphVector}, and can be null. If it is null, the
|
||||
* {@code FontRenderContext} of this {@code GlyphVector}
|
||||
* is used. The default implementation returns the visual bounds,
|
||||
* offset to x, y and rounded out to the next integer value (i.e. returns an
|
||||
* integer rectangle which encloses the visual bounds) and
|
||||
* ignores the FRC. Subclassers should override this method.
|
||||
* @param renderFRC the {@code FontRenderContext} of the {@code Graphics}.
|
||||
* @param x the x-coordinate at which to render this {@code GlyphVector}.
|
||||
* @param y the y-coordinate at which to render this {@code GlyphVector}.
|
||||
* @return a {@code Rectangle} bounding the pixels that would be affected.
|
||||
* @since 1.4
|
||||
*/
|
||||
public Rectangle getPixelBounds(FontRenderContext renderFRC, float x, float y) {
|
||||
Rectangle2D rect = getVisualBounds();
|
||||
int l = (int)Math.floor(rect.getX() + x);
|
||||
int t = (int)Math.floor(rect.getY() + y);
|
||||
int r = (int)Math.ceil(rect.getMaxX() + x);
|
||||
int b = (int)Math.ceil(rect.getMaxY() + y);
|
||||
return new Rectangle(l, t, r - l, b - t);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a {@code Shape} whose interior corresponds to the
|
||||
* visual representation of this {@code GlyphVector}.
|
||||
* @return a {@code Shape} that is the outline of this
|
||||
* {@code GlyphVector}.
|
||||
*/
|
||||
public abstract Shape getOutline();
|
||||
|
||||
/**
|
||||
* Returns a {@code Shape} whose interior corresponds to the
|
||||
* visual representation of this {@code GlyphVector} when
|
||||
* rendered at x, y.
|
||||
* @param x the X coordinate of this {@code GlyphVector}.
|
||||
* @param y the Y coordinate of this {@code GlyphVector}.
|
||||
* @return a {@code Shape} that is the outline of this
|
||||
* {@code GlyphVector} when rendered at the specified
|
||||
* coordinates.
|
||||
*/
|
||||
public abstract Shape getOutline(float x, float y);
|
||||
|
||||
/**
|
||||
* Returns a {@code Shape} whose interior corresponds to the
|
||||
* visual representation of the specified glyph
|
||||
* within this {@code GlyphVector}.
|
||||
* The outline returned by this method is positioned around the
|
||||
* origin of each individual glyph.
|
||||
* @param glyphIndex the index into this {@code GlyphVector}
|
||||
* @return a {@code Shape} that is the outline of the glyph
|
||||
* at the specified {@code glyphIndex} of this
|
||||
* {@code GlyphVector}.
|
||||
* @throws IndexOutOfBoundsException if {@code glyphIndex}
|
||||
* is less than 0 or greater than or equal to the number
|
||||
* of glyphs in this {@code GlyphVector}
|
||||
*/
|
||||
public abstract Shape getGlyphOutline(int glyphIndex);
|
||||
|
||||
/**
|
||||
* Returns a {@code Shape} whose interior corresponds to the
|
||||
* visual representation of the specified glyph
|
||||
* within this {@code GlyphVector}, offset to x, y.
|
||||
* The outline returned by this method is positioned around the
|
||||
* origin of each individual glyph.
|
||||
* @param glyphIndex the index into this {@code GlyphVector}
|
||||
* @param x the X coordinate of the location of this {@code GlyphVector}
|
||||
* @param y the Y coordinate of the location of this {@code GlyphVector}
|
||||
* @return a {@code Shape} that is the outline of the glyph
|
||||
* at the specified {@code glyphIndex} of this
|
||||
* {@code GlyphVector} when rendered at the specified
|
||||
* coordinates.
|
||||
* @throws IndexOutOfBoundsException if {@code glyphIndex}
|
||||
* is less than 0 or greater than or equal to the number
|
||||
* of glyphs in this {@code GlyphVector}
|
||||
* @since 1.4
|
||||
*/
|
||||
public Shape getGlyphOutline(int glyphIndex, float x, float y) {
|
||||
Shape s = getGlyphOutline(glyphIndex);
|
||||
AffineTransform at = AffineTransform.getTranslateInstance(x,y);
|
||||
return at.createTransformedShape(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of the specified glyph relative to the
|
||||
* origin of this {@code GlyphVector}.
|
||||
* If {@code glyphIndex} equals the number of glyphs in
|
||||
* this {@code GlyphVector}, this method returns the position after
|
||||
* the last glyph. This position is used to define the advance of
|
||||
* the entire {@code GlyphVector}.
|
||||
* @param glyphIndex the index into this {@code GlyphVector}
|
||||
* @return a {@link Point2D} object that is the position of the glyph
|
||||
* at the specified {@code glyphIndex}.
|
||||
* @throws IndexOutOfBoundsException if {@code glyphIndex}
|
||||
* is less than 0 or greater than the number of glyphs
|
||||
* in this {@code GlyphVector}
|
||||
* @see #setGlyphPosition
|
||||
*/
|
||||
public abstract Point2D getGlyphPosition(int glyphIndex);
|
||||
|
||||
/**
|
||||
* Sets the position of the specified glyph within this
|
||||
* {@code GlyphVector}.
|
||||
* If {@code glyphIndex} equals the number of glyphs in
|
||||
* this {@code GlyphVector}, this method sets the position after
|
||||
* the last glyph. This position is used to define the advance of
|
||||
* the entire {@code GlyphVector}.
|
||||
* @param glyphIndex the index into this {@code GlyphVector}
|
||||
* @param newPos the {@code Point2D} at which to position the
|
||||
* glyph at the specified {@code glyphIndex}
|
||||
* @throws IndexOutOfBoundsException if {@code glyphIndex}
|
||||
* is less than 0 or greater than the number of glyphs
|
||||
* in this {@code GlyphVector}
|
||||
* @see #getGlyphPosition
|
||||
*/
|
||||
public abstract void setGlyphPosition(int glyphIndex, Point2D newPos);
|
||||
|
||||
/**
|
||||
* Returns the transform of the specified glyph within this
|
||||
* {@code GlyphVector}. The transform is relative to the
|
||||
* glyph position. If no special transform has been applied,
|
||||
* {@code null} can be returned. A null return indicates
|
||||
* an identity transform.
|
||||
* @param glyphIndex the index into this {@code GlyphVector}
|
||||
* @return an {@link AffineTransform} that is the transform of
|
||||
* the glyph at the specified {@code glyphIndex}.
|
||||
* @throws IndexOutOfBoundsException if {@code glyphIndex}
|
||||
* is less than 0 or greater than or equal to the number
|
||||
* of glyphs in this {@code GlyphVector}
|
||||
* @see #setGlyphTransform
|
||||
*/
|
||||
public abstract AffineTransform getGlyphTransform(int glyphIndex);
|
||||
|
||||
/**
|
||||
* Sets the transform of the specified glyph within this
|
||||
* {@code GlyphVector}. The transform is relative to the glyph
|
||||
* position. A {@code null} argument for {@code newTX}
|
||||
* indicates that no special transform is applied for the specified
|
||||
* glyph.
|
||||
* This method can be used to rotate, mirror, translate and scale the
|
||||
* glyph. Adding a transform can result in significant performance changes.
|
||||
* @param glyphIndex the index into this {@code GlyphVector}
|
||||
* @param newTX the new transform of the glyph at {@code glyphIndex}
|
||||
* @throws IndexOutOfBoundsException if {@code glyphIndex}
|
||||
* is less than 0 or greater than or equal to the number
|
||||
* of glyphs in this {@code GlyphVector}
|
||||
* @see #getGlyphTransform
|
||||
*/
|
||||
public abstract void setGlyphTransform(int glyphIndex, AffineTransform newTX);
|
||||
|
||||
/**
|
||||
* Returns flags describing the global state of the GlyphVector.
|
||||
* Flags not described below are reserved. The default
|
||||
* implementation returns 0 (meaning false) for the position adjustments,
|
||||
* transforms, rtl, and complex flags.
|
||||
* Subclassers should override this method, and make sure
|
||||
* it correctly describes the GlyphVector and corresponds
|
||||
* to the results of related calls.
|
||||
* @return an int containing the flags describing the state
|
||||
* @see #FLAG_HAS_POSITION_ADJUSTMENTS
|
||||
* @see #FLAG_HAS_TRANSFORMS
|
||||
* @see #FLAG_RUN_RTL
|
||||
* @see #FLAG_COMPLEX_GLYPHS
|
||||
* @see #FLAG_MASK
|
||||
* @since 1.4
|
||||
*/
|
||||
public int getLayoutFlags() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A flag used with getLayoutFlags that indicates that this {@code GlyphVector} has
|
||||
* per-glyph transforms.
|
||||
* @since 1.4
|
||||
*/
|
||||
public static final int FLAG_HAS_TRANSFORMS = 1;
|
||||
|
||||
/**
|
||||
* A flag used with getLayoutFlags that indicates that this {@code GlyphVector} has
|
||||
* position adjustments. When this is true, the glyph positions don't match the
|
||||
* accumulated default advances of the glyphs (for example, if kerning has been done).
|
||||
* @since 1.4
|
||||
*/
|
||||
public static final int FLAG_HAS_POSITION_ADJUSTMENTS = 2;
|
||||
|
||||
/**
|
||||
* A flag used with getLayoutFlags that indicates that this {@code GlyphVector} has
|
||||
* a right-to-left run direction. This refers to the glyph-to-char mapping and does
|
||||
* not imply that the visual locations of the glyphs are necessarily in this order,
|
||||
* although generally they will be.
|
||||
* @since 1.4
|
||||
*/
|
||||
public static final int FLAG_RUN_RTL = 4;
|
||||
|
||||
/**
|
||||
* A flag used with getLayoutFlags that indicates that this {@code GlyphVector} has
|
||||
* a complex glyph-to-char mapping (one that does not map glyphs to chars one-to-one in
|
||||
* strictly ascending or descending order matching the run direction).
|
||||
* @since 1.4
|
||||
*/
|
||||
public static final int FLAG_COMPLEX_GLYPHS = 8;
|
||||
|
||||
/**
|
||||
* A mask for supported flags from getLayoutFlags. Only bits covered by the mask
|
||||
* should be tested.
|
||||
* @since 1.4
|
||||
*/
|
||||
public static final int FLAG_MASK =
|
||||
FLAG_HAS_TRANSFORMS |
|
||||
FLAG_HAS_POSITION_ADJUSTMENTS |
|
||||
FLAG_RUN_RTL |
|
||||
FLAG_COMPLEX_GLYPHS;
|
||||
|
||||
/**
|
||||
* Returns an array of glyph positions for the specified glyphs.
|
||||
* This method is used for convenience and performance when
|
||||
* processing glyph positions.
|
||||
* If no array is passed in, a new array is created.
|
||||
* Even numbered array entries beginning with position zero are the X
|
||||
* coordinates of the glyph numbered {@code beginGlyphIndex + position/2}.
|
||||
* Odd numbered array entries beginning with position one are the Y
|
||||
* coordinates of the glyph numbered {@code beginGlyphIndex + (position-1)/2}.
|
||||
* If {@code beginGlyphIndex} equals the number of glyphs in
|
||||
* this {@code GlyphVector}, this method gets the position after
|
||||
* the last glyph and this position is used to define the advance of
|
||||
* the entire {@code GlyphVector}.
|
||||
* @param beginGlyphIndex the index at which to begin retrieving
|
||||
* glyph positions
|
||||
* @param numEntries the number of glyphs to retrieve
|
||||
* @param positionReturn the array that receives the glyph positions
|
||||
* and is then returned.
|
||||
* @return an array of glyph positions specified by
|
||||
* {@code beginGlyphIndex} and {@code numEntries}.
|
||||
* @throws IllegalArgumentException if {@code numEntries} is
|
||||
* less than 0
|
||||
* @throws IndexOutOfBoundsException if {@code beginGlyphIndex}
|
||||
* is less than 0
|
||||
* @throws IndexOutOfBoundsException if the sum of
|
||||
* {@code beginGlyphIndex} and {@code numEntries}
|
||||
* is greater than the number of glyphs in this
|
||||
* {@code GlyphVector} plus one
|
||||
*/
|
||||
public abstract float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
|
||||
float[] positionReturn);
|
||||
|
||||
/**
|
||||
* Returns the logical bounds of the specified glyph within this
|
||||
* {@code GlyphVector}.
|
||||
* These logical bounds have a total of four edges, with two edges
|
||||
* parallel to the baseline under the glyph's transform and the other two
|
||||
* edges are shared with adjacent glyphs if they are present. This
|
||||
* method is useful for hit-testing of the specified glyph,
|
||||
* positioning of a caret at the leading or trailing edge of a glyph,
|
||||
* and for drawing a highlight region around the specified glyph.
|
||||
* @param glyphIndex the index into this {@code GlyphVector}
|
||||
* that corresponds to the glyph from which to retrieve its logical
|
||||
* bounds
|
||||
* @return a {@code Shape} that is the logical bounds of the
|
||||
* glyph at the specified {@code glyphIndex}.
|
||||
* @throws IndexOutOfBoundsException if {@code glyphIndex}
|
||||
* is less than 0 or greater than or equal to the number
|
||||
* of glyphs in this {@code GlyphVector}
|
||||
* @see #getGlyphVisualBounds
|
||||
*/
|
||||
public abstract Shape getGlyphLogicalBounds(int glyphIndex);
|
||||
|
||||
/**
|
||||
* Returns the visual bounds of the specified glyph within the
|
||||
* {@code GlyphVector}.
|
||||
* The bounds returned by this method is positioned around the
|
||||
* origin of each individual glyph.
|
||||
* @param glyphIndex the index into this {@code GlyphVector}
|
||||
* that corresponds to the glyph from which to retrieve its visual
|
||||
* bounds
|
||||
* @return a {@code Shape} that is the visual bounds of the
|
||||
* glyph at the specified {@code glyphIndex}.
|
||||
* @throws IndexOutOfBoundsException if {@code glyphIndex}
|
||||
* is less than 0 or greater than or equal to the number
|
||||
* of glyphs in this {@code GlyphVector}
|
||||
* @see #getGlyphLogicalBounds
|
||||
*/
|
||||
public abstract Shape getGlyphVisualBounds(int glyphIndex);
|
||||
|
||||
/**
|
||||
* Returns the pixel bounds of the glyph at index when this
|
||||
* {@code GlyphVector} is rendered in a {@code Graphics} with the
|
||||
* given {@code FontRenderContext} at the given location. The
|
||||
* renderFRC need not be the same as the
|
||||
* {@code FontRenderContext} of this
|
||||
* {@code GlyphVector}, and can be null. If it is null, the
|
||||
* {@code FontRenderContext} of this {@code GlyphVector}
|
||||
* is used. The default implementation returns the visual bounds of the glyph,
|
||||
* offset to x, y and rounded out to the next integer value, and
|
||||
* ignores the FRC. Subclassers should override this method.
|
||||
* @param index the index of the glyph.
|
||||
* @param renderFRC the {@code FontRenderContext} of the {@code Graphics}.
|
||||
* @param x the X position at which to render this {@code GlyphVector}.
|
||||
* @param y the Y position at which to render this {@code GlyphVector}.
|
||||
* @return a {@code Rectangle} bounding the pixels that would be affected.
|
||||
* @since 1.4
|
||||
*/
|
||||
public Rectangle getGlyphPixelBounds(int index, FontRenderContext renderFRC, float x, float y) {
|
||||
Rectangle2D rect = getGlyphVisualBounds(index).getBounds2D();
|
||||
int l = (int)Math.floor(rect.getX() + x);
|
||||
int t = (int)Math.floor(rect.getY() + y);
|
||||
int r = (int)Math.ceil(rect.getMaxX() + x);
|
||||
int b = (int)Math.ceil(rect.getMaxY() + y);
|
||||
return new Rectangle(l, t, r - l, b - t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the metrics of the glyph at the specified index into
|
||||
* this {@code GlyphVector}.
|
||||
* @param glyphIndex the index into this {@code GlyphVector}
|
||||
* that corresponds to the glyph from which to retrieve its metrics
|
||||
* @return a {@link GlyphMetrics} object that represents the
|
||||
* metrics of the glyph at the specified {@code glyphIndex}
|
||||
* into this {@code GlyphVector}.
|
||||
* @throws IndexOutOfBoundsException if {@code glyphIndex}
|
||||
* is less than 0 or greater than or equal to the number
|
||||
* of glyphs in this {@code GlyphVector}
|
||||
*/
|
||||
public abstract GlyphMetrics getGlyphMetrics(int glyphIndex);
|
||||
|
||||
/**
|
||||
* Returns the justification information for the glyph at
|
||||
* the specified index into this {@code GlyphVector}.
|
||||
* @param glyphIndex the index into this {@code GlyphVector}
|
||||
* that corresponds to the glyph from which to retrieve its
|
||||
* justification properties
|
||||
* @return a {@link GlyphJustificationInfo} object that
|
||||
* represents the justification properties of the glyph at the
|
||||
* specified {@code glyphIndex} into this
|
||||
* {@code GlyphVector}.
|
||||
* @throws IndexOutOfBoundsException if {@code glyphIndex}
|
||||
* is less than 0 or greater than or equal to the number
|
||||
* of glyphs in this {@code GlyphVector}
|
||||
*/
|
||||
public abstract GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex);
|
||||
|
||||
//
|
||||
// general utility methods
|
||||
//
|
||||
|
||||
/**
|
||||
* Tests if the specified {@code GlyphVector} exactly
|
||||
* equals this {@code GlyphVector}.
|
||||
* @param set the specified {@code GlyphVector} to test
|
||||
* @return {@code true} if the specified
|
||||
* {@code GlyphVector} equals this {@code GlyphVector};
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public abstract boolean equals(GlyphVector set);
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is
|
||||
* copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
|
||||
* of IBM. These materials are provided under terms of a License
|
||||
* Agreement between Taligent and Sun. This technology is protected
|
||||
* by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Font;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* This class is used with the CHAR_REPLACEMENT attribute.
|
||||
* <p>
|
||||
* The {@code GraphicAttribute} class represents a graphic embedded
|
||||
* in text. Clients subclass this class to implement their own char
|
||||
* replacement graphics. Clients wishing to embed shapes and images in
|
||||
* text need not subclass this class. Instead, clients can use the
|
||||
* {@link ShapeGraphicAttribute} and {@link ImageGraphicAttribute}
|
||||
* classes.
|
||||
* <p>
|
||||
* Subclasses must ensure that their objects are immutable once they
|
||||
* are constructed. Mutating a {@code GraphicAttribute} that
|
||||
* is used in a {@link TextLayout} results in undefined behavior from the
|
||||
* {@code TextLayout}.
|
||||
*/
|
||||
public abstract class GraphicAttribute {
|
||||
|
||||
private int fAlignment;
|
||||
|
||||
/**
|
||||
* Aligns top of graphic to top of line.
|
||||
*/
|
||||
public static final int TOP_ALIGNMENT = -1;
|
||||
|
||||
/**
|
||||
* Aligns bottom of graphic to bottom of line.
|
||||
*/
|
||||
public static final int BOTTOM_ALIGNMENT = -2;
|
||||
|
||||
/**
|
||||
* Aligns origin of graphic to roman baseline of line.
|
||||
*/
|
||||
public static final int ROMAN_BASELINE = Font.ROMAN_BASELINE;
|
||||
|
||||
/**
|
||||
* Aligns origin of graphic to center baseline of line.
|
||||
*/
|
||||
public static final int CENTER_BASELINE = Font.CENTER_BASELINE;
|
||||
|
||||
/**
|
||||
* Aligns origin of graphic to hanging baseline of line.
|
||||
*/
|
||||
public static final int HANGING_BASELINE = Font.HANGING_BASELINE;
|
||||
|
||||
/**
|
||||
* Constructs a {@code GraphicAttribute}.
|
||||
* Subclasses use this to define the alignment of the graphic.
|
||||
* @param alignment an int representing one of the
|
||||
* {@code GraphicAttribute} alignment fields
|
||||
* @throws IllegalArgumentException if alignment is not one of the
|
||||
* five defined values.
|
||||
*/
|
||||
protected GraphicAttribute(int alignment) {
|
||||
if (alignment < BOTTOM_ALIGNMENT || alignment > HANGING_BASELINE) {
|
||||
throw new IllegalArgumentException("bad alignment");
|
||||
}
|
||||
fAlignment = alignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ascent of this {@code GraphicAttribute}. A
|
||||
* graphic can be rendered above its ascent.
|
||||
* @return the ascent of this {@code GraphicAttribute}.
|
||||
* @see #getBounds()
|
||||
*/
|
||||
public abstract float getAscent();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the descent of this {@code GraphicAttribute}. A
|
||||
* graphic can be rendered below its descent.
|
||||
* @return the descent of this {@code GraphicAttribute}.
|
||||
* @see #getBounds()
|
||||
*/
|
||||
public abstract float getDescent();
|
||||
|
||||
/**
|
||||
* Returns the advance of this {@code GraphicAttribute}. The
|
||||
* {@code GraphicAttribute} object's advance is the distance
|
||||
* from the point at which the graphic is rendered and the point where
|
||||
* the next character or graphic is rendered. A graphic can be
|
||||
* rendered beyond its advance
|
||||
* @return the advance of this {@code GraphicAttribute}.
|
||||
* @see #getBounds()
|
||||
*/
|
||||
public abstract float getAdvance();
|
||||
|
||||
/**
|
||||
* Returns a {@link Rectangle2D} that encloses all of the
|
||||
* bits drawn by this {@code GraphicAttribute} relative to the
|
||||
* rendering position.
|
||||
* A graphic may be rendered beyond its origin, ascent, descent,
|
||||
* or advance; but if it is, this method's implementation must
|
||||
* indicate where the graphic is rendered.
|
||||
* Default bounds is the rectangle (0, -ascent, advance, ascent+descent).
|
||||
* @return a {@code Rectangle2D} that encloses all of the bits
|
||||
* rendered by this {@code GraphicAttribute}.
|
||||
*/
|
||||
public Rectangle2D getBounds() {
|
||||
float ascent = getAscent();
|
||||
return new Rectangle2D.Float(0, -ascent,
|
||||
getAdvance(), ascent+getDescent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link java.awt.Shape} that represents the region that
|
||||
* this {@code GraphicAttribute} renders. This is used when a
|
||||
* {@link TextLayout} is requested to return the outline of the text.
|
||||
* The (untransformed) shape must not extend outside the rectangular
|
||||
* bounds returned by {@code getBounds}.
|
||||
* The default implementation returns the rectangle returned by
|
||||
* {@link #getBounds}, transformed by the provided {@link AffineTransform}
|
||||
* if present.
|
||||
* @param tx an optional {@link AffineTransform} to apply to the
|
||||
* outline of this {@code GraphicAttribute}. This can be null.
|
||||
* @return a {@code Shape} representing this graphic attribute,
|
||||
* suitable for stroking or filling.
|
||||
* @since 1.6
|
||||
*/
|
||||
public Shape getOutline(AffineTransform tx) {
|
||||
Shape b = getBounds();
|
||||
if (tx != null) {
|
||||
b = tx.createTransformedShape(b);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders this {@code GraphicAttribute} at the specified
|
||||
* location.
|
||||
* @param graphics the {@link Graphics2D} into which to render the
|
||||
* graphic
|
||||
* @param x the user-space X coordinate where the graphic is rendered
|
||||
* @param y the user-space Y coordinate where the graphic is rendered
|
||||
*/
|
||||
public abstract void draw(Graphics2D graphics, float x, float y);
|
||||
|
||||
/**
|
||||
* Returns the alignment of this {@code GraphicAttribute}.
|
||||
* Alignment can be to a particular baseline, or to the absolute top
|
||||
* or bottom of a line.
|
||||
* @return the alignment of this {@code GraphicAttribute}.
|
||||
*/
|
||||
public final int getAlignment() {
|
||||
|
||||
return fAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the justification information for this
|
||||
* {@code GraphicAttribute}. Subclasses
|
||||
* can override this method to provide different justification
|
||||
* information.
|
||||
* @return a {@link GlyphJustificationInfo} object that contains the
|
||||
* justification information for this {@code GraphicAttribute}.
|
||||
*/
|
||||
public GlyphJustificationInfo getJustificationInfo() {
|
||||
|
||||
// should we cache this?
|
||||
float advance = getAdvance();
|
||||
|
||||
return new GlyphJustificationInfo(
|
||||
advance, // weight
|
||||
false, // growAbsorb
|
||||
2, // growPriority
|
||||
advance/3, // growLeftLimit
|
||||
advance/3, // growRightLimit
|
||||
false, // shrinkAbsorb
|
||||
1, // shrinkPriority
|
||||
0, // shrinkLeftLimit
|
||||
0); // shrinkRightLimit
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is
|
||||
* copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
|
||||
* of IBM. These materials are provided under terms of a License
|
||||
* Agreement between Taligent and Sun. This technology is protected
|
||||
* by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* The {@code ImageGraphicAttribute} class is an implementation of
|
||||
* {@link GraphicAttribute} which draws images in
|
||||
* a {@link TextLayout}.
|
||||
* @see GraphicAttribute
|
||||
*/
|
||||
|
||||
public final class ImageGraphicAttribute extends GraphicAttribute {
|
||||
|
||||
private Image fImage;
|
||||
private float fImageWidth, fImageHeight;
|
||||
private float fOriginX, fOriginY;
|
||||
|
||||
/**
|
||||
* Constructs an {@code ImageGraphicAttribute} from the specified
|
||||
* {@link Image}. The origin is at (0, 0).
|
||||
* @param image the {@code Image} rendered by this
|
||||
* {@code ImageGraphicAttribute}.
|
||||
* This object keeps a reference to {@code image}.
|
||||
* @param alignment one of the alignments from this
|
||||
* {@code ImageGraphicAttribute}
|
||||
*/
|
||||
public ImageGraphicAttribute(Image image, int alignment) {
|
||||
|
||||
this(image, alignment, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an {@code ImageGraphicAttribute} from the specified
|
||||
* {@code Image}. The point
|
||||
* ({@code originX}, {@code originY}) in the
|
||||
* {@code Image} appears at the origin of the
|
||||
* {@code ImageGraphicAttribute} within the text.
|
||||
* @param image the {@code Image} rendered by this
|
||||
* {@code ImageGraphicAttribute}.
|
||||
* This object keeps a reference to {@code image}.
|
||||
* @param alignment one of the alignments from this
|
||||
* {@code ImageGraphicAttribute}
|
||||
* @param originX the X coordinate of the point within
|
||||
* the {@code Image} that appears at the origin of the
|
||||
* {@code ImageGraphicAttribute} in the text line.
|
||||
* @param originY the Y coordinate of the point within
|
||||
* the {@code Image} that appears at the origin of the
|
||||
* {@code ImageGraphicAttribute} in the text line.
|
||||
*/
|
||||
public ImageGraphicAttribute(Image image,
|
||||
int alignment,
|
||||
float originX,
|
||||
float originY) {
|
||||
|
||||
super(alignment);
|
||||
|
||||
// Can't clone image
|
||||
// fImage = (Image) image.clone();
|
||||
fImage = image;
|
||||
|
||||
fImageWidth = image.getWidth(null);
|
||||
fImageHeight = image.getHeight(null);
|
||||
|
||||
// ensure origin is in Image?
|
||||
fOriginX = originX;
|
||||
fOriginY = originY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ascent of this {@code ImageGraphicAttribute}. The
|
||||
* ascent of an {@code ImageGraphicAttribute} is the distance
|
||||
* from the top of the image to the origin.
|
||||
* @return the ascent of this {@code ImageGraphicAttribute}.
|
||||
*/
|
||||
public float getAscent() {
|
||||
|
||||
return Math.max(0, fOriginY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the descent of this {@code ImageGraphicAttribute}.
|
||||
* The descent of an {@code ImageGraphicAttribute} is the
|
||||
* distance from the origin to the bottom of the image.
|
||||
* @return the descent of this {@code ImageGraphicAttribute}.
|
||||
*/
|
||||
public float getDescent() {
|
||||
|
||||
return Math.max(0, fImageHeight-fOriginY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the advance of this {@code ImageGraphicAttribute}.
|
||||
* The advance of an {@code ImageGraphicAttribute} is the
|
||||
* distance from the origin to the right edge of the image.
|
||||
* @return the advance of this {@code ImageGraphicAttribute}.
|
||||
*/
|
||||
public float getAdvance() {
|
||||
|
||||
return Math.max(0, fImageWidth-fOriginX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Rectangle2D} that encloses all of the
|
||||
* bits rendered by this {@code ImageGraphicAttribute}, relative
|
||||
* to the rendering position. A graphic can be rendered beyond its
|
||||
* origin, ascent, descent, or advance; but if it is, this
|
||||
* method's implementation must indicate where the graphic is rendered.
|
||||
* @return a {@code Rectangle2D} that encloses all of the bits
|
||||
* rendered by this {@code ImageGraphicAttribute}.
|
||||
*/
|
||||
public Rectangle2D getBounds() {
|
||||
|
||||
return new Rectangle2D.Float(
|
||||
-fOriginX, -fOriginY, fImageWidth, fImageHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void draw(Graphics2D graphics, float x, float y) {
|
||||
|
||||
graphics.drawImage(fImage, (int) (x-fOriginX), (int) (y-fOriginY), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode for this {@code ImageGraphicAttribute}.
|
||||
* @return a hash code value for this object.
|
||||
*/
|
||||
public int hashCode() {
|
||||
|
||||
return fImage.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@code ImageGraphicAttribute} to the specified
|
||||
* {@link Object}.
|
||||
* @param rhs the {@code Object} to compare for equality
|
||||
* @return {@code true} if this
|
||||
* {@code ImageGraphicAttribute} equals {@code rhs};
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public boolean equals(Object rhs) {
|
||||
|
||||
try {
|
||||
return equals((ImageGraphicAttribute) rhs);
|
||||
}
|
||||
catch(ClassCastException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@code ImageGraphicAttribute} to the specified
|
||||
* {@code ImageGraphicAttribute}.
|
||||
* @param rhs the {@code ImageGraphicAttribute} to compare for
|
||||
* equality
|
||||
* @return {@code true} if this
|
||||
* {@code ImageGraphicAttribute} equals {@code rhs};
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public boolean equals(ImageGraphicAttribute rhs) {
|
||||
|
||||
if (rhs == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == rhs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fOriginX != rhs.fOriginX || fOriginY != rhs.fOriginY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getAlignment() != rhs.getAlignment()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fImage.equals(rhs.fImage)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
import jdk.internal.misc.JavaAWTFontAccess;
|
||||
|
||||
class JavaAWTFontAccessImpl implements JavaAWTFontAccess {
|
||||
|
||||
// java.awt.font.TextAttribute constants
|
||||
public Object getTextAttributeConstant(String name) {
|
||||
switch (name) {
|
||||
case "RUN_DIRECTION":
|
||||
return TextAttribute.RUN_DIRECTION;
|
||||
case "NUMERIC_SHAPING":
|
||||
return TextAttribute.NUMERIC_SHAPING;
|
||||
case "BIDI_EMBEDDING":
|
||||
return TextAttribute.BIDI_EMBEDDING;
|
||||
case "RUN_DIRECTION_LTR":
|
||||
return TextAttribute.RUN_DIRECTION_LTR;
|
||||
default:
|
||||
throw new AssertionError("Constant name is not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
// java.awt.font.NumericShaper
|
||||
public void shape(Object shaper, char[] text, int start, int count) {
|
||||
assert shaper instanceof NumericShaper;
|
||||
((NumericShaper)shaper).shape(text, start,count);
|
||||
}
|
||||
|
||||
}
|
84
src/java.desktop/share/classes/java/awt/font/LayoutPath.java
Normal file
84
src/java.desktop/share/classes/java/awt/font/LayoutPath.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
/*
|
||||
* (C) Copyright IBM Corp. 2005, All Rights Reserved.
|
||||
*/
|
||||
package java.awt.font;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
/**
|
||||
* LayoutPath provides a mapping between locations relative to the
|
||||
* baseline and points in user space. Locations consist of an advance
|
||||
* along the baseline, and an offset perpendicular to the baseline at
|
||||
* the advance. Positive values along the perpendicular are in the
|
||||
* direction that is 90 degrees clockwise from the baseline vector.
|
||||
* Locations are represented as a {@code Point2D}, where x is the advance and
|
||||
* y is the offset.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class LayoutPath {
|
||||
/**
|
||||
* Convert a point in user space to a location relative to the
|
||||
* path. The location is chosen so as to minimize the distance
|
||||
* from the point to the path (e.g., the magnitude of the offset
|
||||
* will be smallest). If there is more than one such location,
|
||||
* the location with the smallest advance is chosen.
|
||||
* @param point the point to convert. If it is not the same
|
||||
* object as location, point will remain unmodified by this call.
|
||||
* @param location a {@code Point2D} to hold the returned location.
|
||||
* It can be the same object as point.
|
||||
* @return true if the point is associated with the portion of the
|
||||
* path preceding the location, false if it is associated with
|
||||
* the portion following. The default, if the location is not at
|
||||
* a break or sharp bend in the path, is to return true.
|
||||
* @throws NullPointerException if point or location is null
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract boolean pointToPath(Point2D point, Point2D location);
|
||||
|
||||
/**
|
||||
* Convert a location relative to the path to a point in user
|
||||
* coordinates. The path might bend abruptly or be disjoint at
|
||||
* the location's advance. If this is the case, the value of
|
||||
* 'preceding' is used to disambiguate the portion of the path
|
||||
* whose location and slope is to be used to interpret the offset.
|
||||
* @param location a {@code Point2D} representing the advance (in x) and
|
||||
* offset (in y) of a location relative to the path. If location
|
||||
* is not the same object as point, location will remain
|
||||
* unmodified by this call.
|
||||
* @param preceding if true, the portion preceding the advance
|
||||
* should be used, if false the portion after should be used.
|
||||
* This has no effect if the path does not break or bend sharply
|
||||
* at the advance.
|
||||
* @param point a {@code Point2D} to hold the returned point. It can be
|
||||
* the same object as location.
|
||||
* @throws NullPointerException if location or point is null
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract void pathToPoint(Point2D location, boolean preceding,
|
||||
Point2D point);
|
||||
}
|
|
@ -0,0 +1,534 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is
|
||||
* copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
|
||||
* of IBM. These materials are provided under terms of a License
|
||||
* Agreement between Taligent and Sun. This technology is protected
|
||||
* by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
import java.text.BreakIterator;
|
||||
import java.text.CharacterIterator;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.awt.font.FontRenderContext;
|
||||
|
||||
/**
|
||||
* The {@code LineBreakMeasurer} class allows styled text to be
|
||||
* broken into lines (or segments) that fit within a particular visual
|
||||
* advance. This is useful for clients who wish to display a paragraph of
|
||||
* text that fits within a specific width, called the <b>wrapping
|
||||
* width</b>.
|
||||
* <p>
|
||||
* {@code LineBreakMeasurer} is constructed with an iterator over
|
||||
* styled text. The iterator's range should be a single paragraph in the
|
||||
* text.
|
||||
* {@code LineBreakMeasurer} maintains a position in the text for the
|
||||
* start of the next text segment. Initially, this position is the
|
||||
* start of text. Paragraphs are assigned an overall direction (either
|
||||
* left-to-right or right-to-left) according to the bidirectional
|
||||
* formatting rules. All segments obtained from a paragraph have the
|
||||
* same direction as the paragraph.
|
||||
* <p>
|
||||
* Segments of text are obtained by calling the method
|
||||
* {@code nextLayout}, which returns a {@link TextLayout}
|
||||
* representing the text that fits within the wrapping width.
|
||||
* The {@code nextLayout} method moves the current position
|
||||
* to the end of the layout returned from {@code nextLayout}.
|
||||
* <p>
|
||||
* {@code LineBreakMeasurer} implements the most commonly used
|
||||
* line-breaking policy: Every word that fits within the wrapping
|
||||
* width is placed on the line. If the first word does not fit, then all
|
||||
* of the characters that fit within the wrapping width are placed on the
|
||||
* line. At least one character is placed on each line.
|
||||
* <p>
|
||||
* The {@code TextLayout} instances returned by
|
||||
* {@code LineBreakMeasurer} treat tabs like 0-width spaces. Clients
|
||||
* who wish to obtain tab-delimited segments for positioning should use
|
||||
* the overload of {@code nextLayout} which takes a limiting offset
|
||||
* in the text.
|
||||
* The limiting offset should be the first character after the tab.
|
||||
* The {@code TextLayout} objects returned from this method end
|
||||
* at the limit provided (or before, if the text between the current
|
||||
* position and the limit won't fit entirely within the wrapping
|
||||
* width).
|
||||
* <p>
|
||||
* Clients who are laying out tab-delimited text need a slightly
|
||||
* different line-breaking policy after the first segment has been
|
||||
* placed on a line. Instead of fitting partial words in the
|
||||
* remaining space, they should place words which don't fit in the
|
||||
* remaining space entirely on the next line. This change of policy
|
||||
* can be requested in the overload of {@code nextLayout} which
|
||||
* takes a {@code boolean} parameter. If this parameter is
|
||||
* {@code true}, {@code nextLayout} returns
|
||||
* {@code null} if the first word won't fit in
|
||||
* the given space. See the tab sample below.
|
||||
* <p>
|
||||
* In general, if the text used to construct the
|
||||
* {@code LineBreakMeasurer} changes, a new
|
||||
* {@code LineBreakMeasurer} must be constructed to reflect
|
||||
* the change. (The old {@code LineBreakMeasurer} continues to
|
||||
* function properly, but it won't be aware of the text change.)
|
||||
* Nevertheless, if the text change is the insertion or deletion of a
|
||||
* single character, an existing {@code LineBreakMeasurer} can be
|
||||
* 'updated' by calling {@code insertChar} or
|
||||
* {@code deleteChar}. Updating an existing
|
||||
* {@code LineBreakMeasurer} is much faster than creating a new one.
|
||||
* Clients who modify text based on user typing should take advantage
|
||||
* of these methods.
|
||||
* <p>
|
||||
* <strong>Examples</strong>:<p>
|
||||
* Rendering a paragraph in a component
|
||||
* <blockquote>
|
||||
* <pre>{@code
|
||||
* public void paint(Graphics graphics) {
|
||||
*
|
||||
* float dx = 0f, dy = 5f;
|
||||
* Graphics2D g2d = (Graphics2D)graphics;
|
||||
* FontRenderContext frc = g2d.getFontRenderContext();
|
||||
*
|
||||
* AttributedString text = new AttributedString(".....");
|
||||
* AttributedCharacterIterator paragraph = text.getIterator();
|
||||
*
|
||||
* LineBreakMeasurer measurer = new LineBreakMeasurer(paragraph, frc);
|
||||
* measurer.setPosition(paragraph.getBeginIndex());
|
||||
* float wrappingWidth = (float)getSize().width;
|
||||
*
|
||||
* while (measurer.getPosition() < paragraph.getEndIndex()) {
|
||||
*
|
||||
* TextLayout layout = measurer.nextLayout(wrappingWidth);
|
||||
*
|
||||
* dy += (layout.getAscent());
|
||||
* float dx = layout.isLeftToRight() ?
|
||||
* 0 : (wrappingWidth - layout.getAdvance());
|
||||
*
|
||||
* layout.draw(graphics, dx, dy);
|
||||
* dy += layout.getDescent() + layout.getLeading();
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
* </blockquote>
|
||||
* <p>
|
||||
* Rendering text with tabs. For simplicity, the overall text
|
||||
* direction is assumed to be left-to-right
|
||||
* <blockquote>
|
||||
* <pre>{@code
|
||||
* public void paint(Graphics graphics) {
|
||||
*
|
||||
* float leftMargin = 10, rightMargin = 310;
|
||||
* float[] tabStops = { 100, 250 };
|
||||
*
|
||||
* // assume styledText is an AttributedCharacterIterator, and the number
|
||||
* // of tabs in styledText is tabCount
|
||||
*
|
||||
* int[] tabLocations = new int[tabCount+1];
|
||||
*
|
||||
* int i = 0;
|
||||
* for (char c = styledText.first(); c != styledText.DONE; c = styledText.next()) {
|
||||
* if (c == '\t') {
|
||||
* tabLocations[i++] = styledText.getIndex();
|
||||
* }
|
||||
* }
|
||||
* tabLocations[tabCount] = styledText.getEndIndex() - 1;
|
||||
*
|
||||
* // Now tabLocations has an entry for every tab's offset in
|
||||
* // the text. For convenience, the last entry is tabLocations
|
||||
* // is the offset of the last character in the text.
|
||||
*
|
||||
* LineBreakMeasurer measurer = new LineBreakMeasurer(styledText);
|
||||
* int currentTab = 0;
|
||||
* float verticalPos = 20;
|
||||
*
|
||||
* while (measurer.getPosition() < styledText.getEndIndex()) {
|
||||
*
|
||||
* // Lay out and draw each line. All segments on a line
|
||||
* // must be computed before any drawing can occur, since
|
||||
* // we must know the largest ascent on the line.
|
||||
* // TextLayouts are computed and stored in a Vector;
|
||||
* // their horizontal positions are stored in a parallel
|
||||
* // Vector.
|
||||
*
|
||||
* // lineContainsText is true after first segment is drawn
|
||||
* boolean lineContainsText = false;
|
||||
* boolean lineComplete = false;
|
||||
* float maxAscent = 0, maxDescent = 0;
|
||||
* float horizontalPos = leftMargin;
|
||||
* Vector layouts = new Vector(1);
|
||||
* Vector penPositions = new Vector(1);
|
||||
*
|
||||
* while (!lineComplete) {
|
||||
* float wrappingWidth = rightMargin - horizontalPos;
|
||||
* TextLayout layout =
|
||||
* measurer.nextLayout(wrappingWidth,
|
||||
* tabLocations[currentTab]+1,
|
||||
* lineContainsText);
|
||||
*
|
||||
* // layout can be null if lineContainsText is true
|
||||
* if (layout != null) {
|
||||
* layouts.addElement(layout);
|
||||
* penPositions.addElement(new Float(horizontalPos));
|
||||
* horizontalPos += layout.getAdvance();
|
||||
* maxAscent = Math.max(maxAscent, layout.getAscent());
|
||||
* maxDescent = Math.max(maxDescent,
|
||||
* layout.getDescent() + layout.getLeading());
|
||||
* } else {
|
||||
* lineComplete = true;
|
||||
* }
|
||||
*
|
||||
* lineContainsText = true;
|
||||
*
|
||||
* if (measurer.getPosition() == tabLocations[currentTab]+1) {
|
||||
* currentTab++;
|
||||
* }
|
||||
*
|
||||
* if (measurer.getPosition() == styledText.getEndIndex())
|
||||
* lineComplete = true;
|
||||
* else if (horizontalPos >= tabStops[tabStops.length-1])
|
||||
* lineComplete = true;
|
||||
*
|
||||
* if (!lineComplete) {
|
||||
* // move to next tab stop
|
||||
* int j;
|
||||
* for (j=0; horizontalPos >= tabStops[j]; j++) {}
|
||||
* horizontalPos = tabStops[j];
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* verticalPos += maxAscent;
|
||||
*
|
||||
* Enumeration layoutEnum = layouts.elements();
|
||||
* Enumeration positionEnum = penPositions.elements();
|
||||
*
|
||||
* // now iterate through layouts and draw them
|
||||
* while (layoutEnum.hasMoreElements()) {
|
||||
* TextLayout nextLayout = (TextLayout) layoutEnum.nextElement();
|
||||
* Float nextPosition = (Float) positionEnum.nextElement();
|
||||
* nextLayout.draw(graphics, nextPosition.floatValue(), verticalPos);
|
||||
* }
|
||||
*
|
||||
* verticalPos += maxDescent;
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
* </blockquote>
|
||||
* @see TextLayout
|
||||
*/
|
||||
|
||||
public final class LineBreakMeasurer {
|
||||
|
||||
private BreakIterator breakIter;
|
||||
private int start;
|
||||
private int pos;
|
||||
private int limit;
|
||||
private TextMeasurer measurer;
|
||||
private CharArrayIterator charIter;
|
||||
|
||||
/**
|
||||
* Constructs a {@code LineBreakMeasurer} for the specified text.
|
||||
*
|
||||
* @param text the text for which this {@code LineBreakMeasurer}
|
||||
* produces {@code TextLayout} objects; the text must contain
|
||||
* at least one character; if the text available through
|
||||
* {@code iter} changes, further calls to this
|
||||
* {@code LineBreakMeasurer} instance are undefined (except,
|
||||
* in some cases, when {@code insertChar} or
|
||||
* {@code deleteChar} are invoked afterward - see below)
|
||||
* @param frc contains information about a graphics device which is
|
||||
* needed to measure the text correctly;
|
||||
* text measurements can vary slightly depending on the
|
||||
* device resolution, and attributes such as antialiasing; this
|
||||
* parameter does not specify a translation between the
|
||||
* {@code LineBreakMeasurer} and user space
|
||||
* @see LineBreakMeasurer#insertChar
|
||||
* @see LineBreakMeasurer#deleteChar
|
||||
*/
|
||||
public LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc) {
|
||||
this(text, BreakIterator.getLineInstance(), frc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code LineBreakMeasurer} for the specified text.
|
||||
*
|
||||
* @param text the text for which this {@code LineBreakMeasurer}
|
||||
* produces {@code TextLayout} objects; the text must contain
|
||||
* at least one character; if the text available through
|
||||
* {@code iter} changes, further calls to this
|
||||
* {@code LineBreakMeasurer} instance are undefined (except,
|
||||
* in some cases, when {@code insertChar} or
|
||||
* {@code deleteChar} are invoked afterward - see below)
|
||||
* @param breakIter the {@link BreakIterator} which defines line
|
||||
* breaks
|
||||
* @param frc contains information about a graphics device which is
|
||||
* needed to measure the text correctly;
|
||||
* text measurements can vary slightly depending on the
|
||||
* device resolution, and attributes such as antialiasing; this
|
||||
* parameter does not specify a translation between the
|
||||
* {@code LineBreakMeasurer} and user space
|
||||
* @throws IllegalArgumentException if the text has less than one character
|
||||
* @see LineBreakMeasurer#insertChar
|
||||
* @see LineBreakMeasurer#deleteChar
|
||||
*/
|
||||
public LineBreakMeasurer(AttributedCharacterIterator text,
|
||||
BreakIterator breakIter,
|
||||
FontRenderContext frc) {
|
||||
if (text.getEndIndex() - text.getBeginIndex() < 1) {
|
||||
throw new IllegalArgumentException("Text must contain at least one character.");
|
||||
}
|
||||
|
||||
this.breakIter = breakIter;
|
||||
this.measurer = new TextMeasurer(text, frc);
|
||||
this.limit = text.getEndIndex();
|
||||
this.pos = this.start = text.getBeginIndex();
|
||||
|
||||
charIter = new CharArrayIterator(measurer.getChars(), this.start);
|
||||
this.breakIter.setText(charIter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position at the end of the next layout. Does NOT
|
||||
* update the current position of this {@code LineBreakMeasurer}.
|
||||
*
|
||||
* @param wrappingWidth the maximum visible advance permitted for
|
||||
* the text in the next layout
|
||||
* @return an offset in the text representing the limit of the
|
||||
* next {@code TextLayout}.
|
||||
*/
|
||||
public int nextOffset(float wrappingWidth) {
|
||||
return nextOffset(wrappingWidth, limit, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position at the end of the next layout. Does NOT
|
||||
* update the current position of this {@code LineBreakMeasurer}.
|
||||
*
|
||||
* @param wrappingWidth the maximum visible advance permitted for
|
||||
* the text in the next layout
|
||||
* @param offsetLimit the first character that can not be included
|
||||
* in the next layout, even if the text after the limit would fit
|
||||
* within the wrapping width; {@code offsetLimit} must be
|
||||
* greater than the current position
|
||||
* @param requireNextWord if {@code true}, the current position
|
||||
* that is returned if the entire next word does not fit within
|
||||
* {@code wrappingWidth}; if {@code false}, the offset
|
||||
* returned is at least one greater than the current position
|
||||
* @return an offset in the text representing the limit of the
|
||||
* next {@code TextLayout}
|
||||
*/
|
||||
public int nextOffset(float wrappingWidth, int offsetLimit,
|
||||
boolean requireNextWord) {
|
||||
|
||||
int nextOffset = pos;
|
||||
|
||||
if (pos < limit) {
|
||||
if (offsetLimit <= pos) {
|
||||
throw new IllegalArgumentException("offsetLimit must be after current position");
|
||||
}
|
||||
|
||||
int charAtMaxAdvance =
|
||||
measurer.getLineBreakIndex(pos, wrappingWidth);
|
||||
|
||||
if (charAtMaxAdvance == limit) {
|
||||
nextOffset = limit;
|
||||
}
|
||||
else if (Character.isWhitespace(measurer.getChars()[charAtMaxAdvance-start])) {
|
||||
nextOffset = breakIter.following(charAtMaxAdvance);
|
||||
}
|
||||
else {
|
||||
// Break is in a word; back up to previous break.
|
||||
|
||||
// NOTE: I think that breakIter.preceding(limit) should be
|
||||
// equivalent to breakIter.last(), breakIter.previous() but
|
||||
// the authors of BreakIterator thought otherwise...
|
||||
// If they were equivalent then the first branch would be
|
||||
// unnecessary.
|
||||
int testPos = charAtMaxAdvance + 1;
|
||||
if (testPos == limit) {
|
||||
breakIter.last();
|
||||
nextOffset = breakIter.previous();
|
||||
}
|
||||
else {
|
||||
nextOffset = breakIter.preceding(testPos);
|
||||
}
|
||||
|
||||
if (nextOffset <= pos) {
|
||||
// first word doesn't fit on line
|
||||
if (requireNextWord) {
|
||||
nextOffset = pos;
|
||||
}
|
||||
else {
|
||||
nextOffset = Math.max(pos+1, charAtMaxAdvance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nextOffset > offsetLimit) {
|
||||
nextOffset = offsetLimit;
|
||||
}
|
||||
|
||||
return nextOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next layout, and updates the current position.
|
||||
*
|
||||
* @param wrappingWidth the maximum visible advance permitted for
|
||||
* the text in the next layout
|
||||
* @return a {@code TextLayout}, beginning at the current
|
||||
* position, which represents the next line fitting within
|
||||
* {@code wrappingWidth}
|
||||
*/
|
||||
public TextLayout nextLayout(float wrappingWidth) {
|
||||
return nextLayout(wrappingWidth, limit, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next layout, and updates the current position.
|
||||
*
|
||||
* @param wrappingWidth the maximum visible advance permitted
|
||||
* for the text in the next layout
|
||||
* @param offsetLimit the first character that can not be
|
||||
* included in the next layout, even if the text after the limit
|
||||
* would fit within the wrapping width; {@code offsetLimit}
|
||||
* must be greater than the current position
|
||||
* @param requireNextWord if {@code true}, and if the entire word
|
||||
* at the current position does not fit within the wrapping width,
|
||||
* {@code null} is returned. If {@code false}, a valid
|
||||
* layout is returned that includes at least the character at the
|
||||
* current position
|
||||
* @return a {@code TextLayout}, beginning at the current
|
||||
* position, that represents the next line fitting within
|
||||
* {@code wrappingWidth}. If the current position is at the end
|
||||
* of the text used by this {@code LineBreakMeasurer},
|
||||
* {@code null} is returned
|
||||
*/
|
||||
public TextLayout nextLayout(float wrappingWidth, int offsetLimit,
|
||||
boolean requireNextWord) {
|
||||
|
||||
if (pos < limit) {
|
||||
int layoutLimit = nextOffset(wrappingWidth, offsetLimit, requireNextWord);
|
||||
if (layoutLimit == pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TextLayout result = measurer.getLayout(pos, layoutLimit);
|
||||
pos = layoutLimit;
|
||||
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position of this {@code LineBreakMeasurer}.
|
||||
*
|
||||
* @return the current position of this {@code LineBreakMeasurer}
|
||||
* @see #setPosition
|
||||
*/
|
||||
public int getPosition() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current position of this {@code LineBreakMeasurer}.
|
||||
*
|
||||
* @param newPosition the current position of this
|
||||
* {@code LineBreakMeasurer}; the position should be within the
|
||||
* text used to construct this {@code LineBreakMeasurer} (or in
|
||||
* the text most recently passed to {@code insertChar}
|
||||
* or {@code deleteChar}
|
||||
* @see #getPosition
|
||||
*/
|
||||
public void setPosition(int newPosition) {
|
||||
if (newPosition < start || newPosition > limit) {
|
||||
throw new IllegalArgumentException("position is out of range");
|
||||
}
|
||||
pos = newPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this {@code LineBreakMeasurer} after a single
|
||||
* character is inserted into the text, and sets the current
|
||||
* position to the beginning of the paragraph.
|
||||
*
|
||||
* @param newParagraph the text after the insertion
|
||||
* @param insertPos the position in the text at which the character
|
||||
* is inserted
|
||||
* @throws IndexOutOfBoundsException if {@code insertPos} is less
|
||||
* than the start of {@code newParagraph} or greater than
|
||||
* or equal to the end of {@code newParagraph}
|
||||
* @throws NullPointerException if {@code newParagraph} is
|
||||
* {@code null}
|
||||
* @see #deleteChar
|
||||
*/
|
||||
public void insertChar(AttributedCharacterIterator newParagraph,
|
||||
int insertPos) {
|
||||
|
||||
measurer.insertChar(newParagraph, insertPos);
|
||||
|
||||
limit = newParagraph.getEndIndex();
|
||||
pos = start = newParagraph.getBeginIndex();
|
||||
|
||||
charIter.reset(measurer.getChars(), newParagraph.getBeginIndex());
|
||||
breakIter.setText(charIter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this {@code LineBreakMeasurer} after a single
|
||||
* character is deleted from the text, and sets the current
|
||||
* position to the beginning of the paragraph.
|
||||
* @param newParagraph the text after the deletion
|
||||
* @param deletePos the position in the text at which the character
|
||||
* is deleted
|
||||
* @throws IndexOutOfBoundsException if {@code deletePos} is
|
||||
* less than the start of {@code newParagraph} or greater
|
||||
* than the end of {@code newParagraph}
|
||||
* @throws NullPointerException if {@code newParagraph} is
|
||||
* {@code null}
|
||||
* @see #insertChar
|
||||
*/
|
||||
public void deleteChar(AttributedCharacterIterator newParagraph,
|
||||
int deletePos) {
|
||||
|
||||
measurer.deleteChar(newParagraph, deletePos);
|
||||
|
||||
limit = newParagraph.getEndIndex();
|
||||
pos = start = newParagraph.getBeginIndex();
|
||||
|
||||
charIter.reset(measurer.getChars(), start);
|
||||
breakIter.setText(charIter);
|
||||
}
|
||||
}
|
143
src/java.desktop/share/classes/java/awt/font/LineMetrics.java
Normal file
143
src/java.desktop/share/classes/java/awt/font/LineMetrics.java
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
/**
|
||||
* The {@code LineMetrics} class allows access to the
|
||||
* metrics needed to layout characters along a line
|
||||
* and to layout of a set of lines. A {@code LineMetrics}
|
||||
* object encapsulates the measurement information associated
|
||||
* with a run of text.
|
||||
* <p>
|
||||
* Fonts can have different metrics for different ranges of
|
||||
* characters. The {@code getLineMetrics} methods of
|
||||
* {@link java.awt.Font Font} take some text as an argument
|
||||
* and return a {@code LineMetrics} object describing the
|
||||
* metrics of the initial number of characters in that text, as
|
||||
* returned by {@link #getNumChars}.
|
||||
*/
|
||||
|
||||
|
||||
public abstract class LineMetrics {
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of characters ({@code char} values) in the text whose
|
||||
* metrics are encapsulated by this {@code LineMetrics}
|
||||
* object.
|
||||
* @return the number of characters ({@code char} values) in the text with which
|
||||
* this {@code LineMetrics} was created.
|
||||
*/
|
||||
public abstract int getNumChars();
|
||||
|
||||
/**
|
||||
* Returns the ascent of the text. The ascent
|
||||
* is the distance from the baseline
|
||||
* to the ascender line. The ascent usually represents the
|
||||
* the height of the capital letters of the text. Some characters
|
||||
* can extend above the ascender line.
|
||||
* @return the ascent of the text.
|
||||
*/
|
||||
public abstract float getAscent();
|
||||
|
||||
/**
|
||||
* Returns the descent of the text. The descent
|
||||
* is the distance from the baseline
|
||||
* to the descender line. The descent usually represents
|
||||
* the distance to the bottom of lower case letters like
|
||||
* 'p'. Some characters can extend below the descender
|
||||
* line.
|
||||
* @return the descent of the text.
|
||||
*/
|
||||
public abstract float getDescent();
|
||||
|
||||
/**
|
||||
* Returns the leading of the text. The
|
||||
* leading is the recommended
|
||||
* distance from the bottom of the descender line to the
|
||||
* top of the next line.
|
||||
* @return the leading of the text.
|
||||
*/
|
||||
public abstract float getLeading();
|
||||
|
||||
/**
|
||||
* Returns the height of the text. The
|
||||
* height is equal to the sum of the ascent, the
|
||||
* descent and the leading.
|
||||
* @return the height of the text.
|
||||
*/
|
||||
public abstract float getHeight();
|
||||
|
||||
/**
|
||||
* Returns the baseline index of the text.
|
||||
* The index is one of
|
||||
* {@link java.awt.Font#ROMAN_BASELINE ROMAN_BASELINE},
|
||||
* {@link java.awt.Font#CENTER_BASELINE CENTER_BASELINE},
|
||||
* {@link java.awt.Font#HANGING_BASELINE HANGING_BASELINE}.
|
||||
* @return the baseline of the text.
|
||||
*/
|
||||
public abstract int getBaselineIndex();
|
||||
|
||||
/**
|
||||
* Returns the baseline offsets of the text,
|
||||
* relative to the baseline of the text. The
|
||||
* offsets are indexed by baseline index. For
|
||||
* example, if the baseline index is
|
||||
* {@code CENTER_BASELINE} then
|
||||
* {@code offsets[HANGING_BASELINE]} is usually
|
||||
* negative, {@code offsets[CENTER_BASELINE]}
|
||||
* is zero, and {@code offsets[ROMAN_BASELINE]}
|
||||
* is usually positive.
|
||||
* @return the baseline offsets of the text.
|
||||
*/
|
||||
public abstract float[] getBaselineOffsets();
|
||||
|
||||
/**
|
||||
* Returns the position of the strike-through line
|
||||
* relative to the baseline.
|
||||
* @return the position of the strike-through line.
|
||||
*/
|
||||
public abstract float getStrikethroughOffset();
|
||||
|
||||
/**
|
||||
* Returns the thickness of the strike-through line.
|
||||
* @return the thickness of the strike-through line.
|
||||
*/
|
||||
public abstract float getStrikethroughThickness();
|
||||
|
||||
/**
|
||||
* Returns the position of the underline relative to
|
||||
* the baseline.
|
||||
* @return the position of the underline.
|
||||
*/
|
||||
public abstract float getUnderlineOffset();
|
||||
|
||||
/**
|
||||
* Returns the thickness of the underline.
|
||||
* @return the thickness of the underline.
|
||||
*/
|
||||
public abstract float getUnderlineThickness();
|
||||
}
|
106
src/java.desktop/share/classes/java/awt/font/MultipleMaster.java
Normal file
106
src/java.desktop/share/classes/java/awt/font/MultipleMaster.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.awt.font;
|
||||
|
||||
import java.awt.Font;
|
||||
|
||||
/**
|
||||
* The {@code MultipleMaster} interface represents Type 1
|
||||
* Multiple Master fonts.
|
||||
* A particular {@link Font} object can implement this interface.
|
||||
*/
|
||||
public interface MultipleMaster {
|
||||
|
||||
/**
|
||||
* Returns the number of multiple master design controls.
|
||||
* Design axes include things like width, weight and optical scaling.
|
||||
* @return the number of multiple master design controls
|
||||
*/
|
||||
public int getNumDesignAxes();
|
||||
|
||||
/**
|
||||
* Returns an array of design limits interleaved in the form [from→to]
|
||||
* for each axis. For example,
|
||||
* design limits for weight could be from 0.1 to 1.0. The values are
|
||||
* returned in the same order returned by
|
||||
* {@code getDesignAxisNames}.
|
||||
* @return an array of design limits for each axis.
|
||||
*/
|
||||
public float[] getDesignAxisRanges();
|
||||
|
||||
/**
|
||||
* Returns an array of default design values for each axis. For example,
|
||||
* the default value for weight could be 1.6. The values are returned
|
||||
* in the same order returned by {@code getDesignAxisNames}.
|
||||
* @return an array of default design values for each axis.
|
||||
*/
|
||||
public float[] getDesignAxisDefaults();
|
||||
|
||||
/**
|
||||
* Returns the name for each design axis. This also determines the order in
|
||||
* which the values for each axis are returned.
|
||||
* @return an array containing the names of each design axis.
|
||||
*/
|
||||
public String[] getDesignAxisNames();
|
||||
|
||||
/**
|
||||
* Creates a new instance of a multiple master font based on the design
|
||||
* axis values contained in the specified array. The size of the array
|
||||
* must correspond to the value returned from
|
||||
* {@code getNumDesignAxes} and the values of the array elements
|
||||
* must fall within limits specified by
|
||||
* {@code getDesignAxesLimits}. In case of an error,
|
||||
* {@code null} is returned.
|
||||
* @param axes an array containing axis values
|
||||
* @return a {@link Font} object that is an instance of
|
||||
* {@code MultipleMaster} and is based on the design axis values
|
||||
* provided by {@code axes}.
|
||||
*/
|
||||
public Font deriveMMFont(float[] axes);
|
||||
|
||||
/**
|
||||
* Creates a new instance of a multiple master font based on detailed metric
|
||||
* information. In case of an error, {@code null} is returned.
|
||||
* @param glyphWidths an array of floats representing the desired width
|
||||
* of each glyph in font space
|
||||
* @param avgStemWidth the average stem width for the overall font in
|
||||
* font space
|
||||
* @param typicalCapHeight the height of a typical upper case char
|
||||
* @param typicalXHeight the height of a typical lower case char
|
||||
* @param italicAngle the angle at which the italics lean, in degrees
|
||||
* counterclockwise from vertical
|
||||
* @return a {@code Font} object that is an instance of
|
||||
* {@code MultipleMaster} and is based on the specified metric
|
||||
* information.
|
||||
*/
|
||||
public Font deriveMMFont(
|
||||
float[] glyphWidths,
|
||||
float avgStemWidth,
|
||||
float typicalCapHeight,
|
||||
float typicalXHeight,
|
||||
float italicAngle);
|
||||
|
||||
|
||||
}
|
1924
src/java.desktop/share/classes/java/awt/font/NumericShaper.java
Normal file
1924
src/java.desktop/share/classes/java/awt/font/NumericShaper.java
Normal file
File diff suppressed because it is too large
Load diff
432
src/java.desktop/share/classes/java/awt/font/OpenType.java
Normal file
432
src/java.desktop/share/classes/java/awt/font/OpenType.java
Normal file
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
/**
|
||||
* The {@code OpenType} interface represents OpenType and
|
||||
* TrueType fonts. This interface makes it possible to obtain
|
||||
* <i>sfnt</i> tables from the font. A particular
|
||||
* {@code Font} object can implement this interface.
|
||||
* <p>
|
||||
* For more information on TrueType and OpenType fonts, see the
|
||||
* OpenType specification.
|
||||
* ( <a href="http://www.microsoft.com/typography/otspec/">http://www.microsoft.com/typography/otspec/</a> ).
|
||||
*/
|
||||
public interface OpenType {
|
||||
|
||||
/* 51 tag types so far */
|
||||
|
||||
/**
|
||||
* Character to glyph mapping. Table tag "cmap" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_CMAP = 0x636d6170;
|
||||
|
||||
/**
|
||||
* Font header. Table tag "head" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_HEAD = 0x68656164;
|
||||
|
||||
/**
|
||||
* Naming table. Table tag "name" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_NAME = 0x6e616d65;
|
||||
|
||||
/**
|
||||
* Glyph data. Table tag "glyf" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_GLYF = 0x676c7966;
|
||||
|
||||
/**
|
||||
* Maximum profile. Table tag "maxp" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_MAXP = 0x6d617870;
|
||||
|
||||
/**
|
||||
* CVT preprogram. Table tag "prep" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_PREP = 0x70726570;
|
||||
|
||||
/**
|
||||
* Horizontal metrics. Table tag "hmtx" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_HMTX = 0x686d7478;
|
||||
|
||||
/**
|
||||
* Kerning. Table tag "kern" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_KERN = 0x6b65726e;
|
||||
|
||||
/**
|
||||
* Horizontal device metrics. Table tag "hdmx" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_HDMX = 0x68646d78;
|
||||
|
||||
/**
|
||||
* Index to location. Table tag "loca" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_LOCA = 0x6c6f6361;
|
||||
|
||||
/**
|
||||
* PostScript Information. Table tag "post" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_POST = 0x706f7374;
|
||||
|
||||
/**
|
||||
* OS/2 and Windows specific metrics. Table tag "OS/2"
|
||||
* in the Open Type Specification.
|
||||
*/
|
||||
public static final int TAG_OS2 = 0x4f532f32;
|
||||
|
||||
/**
|
||||
* Control value table. Table tag "cvt "
|
||||
* in the Open Type Specification.
|
||||
*/
|
||||
public static final int TAG_CVT = 0x63767420;
|
||||
|
||||
/**
|
||||
* Grid-fitting and scan conversion procedure. Table tag
|
||||
* "gasp" in the Open Type Specification.
|
||||
*/
|
||||
public static final int TAG_GASP = 0x67617370;
|
||||
|
||||
/**
|
||||
* Vertical device metrics. Table tag "VDMX" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_VDMX = 0x56444d58;
|
||||
|
||||
/**
|
||||
* Vertical metrics. Table tag "vmtx" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_VMTX = 0x766d7478;
|
||||
|
||||
/**
|
||||
* Vertical metrics header. Table tag "vhea" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_VHEA = 0x76686561;
|
||||
|
||||
/**
|
||||
* Horizontal metrics header. Table tag "hhea" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_HHEA = 0x68686561;
|
||||
|
||||
/**
|
||||
* Adobe Type 1 font data. Table tag "typ1" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_TYP1 = 0x74797031;
|
||||
|
||||
/**
|
||||
* Baseline table. Table tag "bsln" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_BSLN = 0x62736c6e;
|
||||
|
||||
/**
|
||||
* Glyph substitution. Table tag "GSUB" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_GSUB = 0x47535542;
|
||||
|
||||
/**
|
||||
* Digital signature. Table tag "DSIG" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_DSIG = 0x44534947;
|
||||
|
||||
/**
|
||||
* Font program. Table tag "fpgm" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_FPGM = 0x6670676d;
|
||||
|
||||
/**
|
||||
* Font variation. Table tag "fvar" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_FVAR = 0x66766172;
|
||||
|
||||
/**
|
||||
* Glyph variation. Table tag "gvar" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_GVAR = 0x67766172;
|
||||
|
||||
/**
|
||||
* Compact font format (Type1 font). Table tag
|
||||
* "CFF " in the Open Type Specification.
|
||||
*/
|
||||
public static final int TAG_CFF = 0x43464620;
|
||||
|
||||
/**
|
||||
* Multiple master supplementary data. Table tag
|
||||
* "MMSD" in the Open Type Specification.
|
||||
*/
|
||||
public static final int TAG_MMSD = 0x4d4d5344;
|
||||
|
||||
/**
|
||||
* Multiple master font metrics. Table tag
|
||||
* "MMFX" in the Open Type Specification.
|
||||
*/
|
||||
public static final int TAG_MMFX = 0x4d4d4658;
|
||||
|
||||
/**
|
||||
* Baseline data. Table tag "BASE" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_BASE = 0x42415345;
|
||||
|
||||
/**
|
||||
* Glyph definition. Table tag "GDEF" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_GDEF = 0x47444546;
|
||||
|
||||
/**
|
||||
* Glyph positioning. Table tag "GPOS" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_GPOS = 0x47504f53;
|
||||
|
||||
/**
|
||||
* Justification. Table tag "JSTF" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_JSTF = 0x4a535446;
|
||||
|
||||
/**
|
||||
* Embedded bitmap data. Table tag "EBDT" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_EBDT = 0x45424454;
|
||||
|
||||
/**
|
||||
* Embedded bitmap location. Table tag "EBLC" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_EBLC = 0x45424c43;
|
||||
|
||||
/**
|
||||
* Embedded bitmap scaling. Table tag "EBSC" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_EBSC = 0x45425343;
|
||||
|
||||
/**
|
||||
* Linear threshold. Table tag "LTSH" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_LTSH = 0x4c545348;
|
||||
|
||||
/**
|
||||
* PCL 5 data. Table tag "PCLT" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_PCLT = 0x50434c54;
|
||||
|
||||
/**
|
||||
* Accent attachment. Table tag "acnt" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_ACNT = 0x61636e74;
|
||||
|
||||
/**
|
||||
* Axis variation. Table tag "avar" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_AVAR = 0x61766172;
|
||||
|
||||
/**
|
||||
* Bitmap data. Table tag "bdat" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_BDAT = 0x62646174;
|
||||
|
||||
/**
|
||||
* Bitmap location. Table tag "bloc" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_BLOC = 0x626c6f63;
|
||||
|
||||
/**
|
||||
* CVT variation. Table tag "cvar" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_CVAR = 0x63766172;
|
||||
|
||||
/**
|
||||
* Feature name. Table tag "feat" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_FEAT = 0x66656174;
|
||||
|
||||
/**
|
||||
* Font descriptors. Table tag "fdsc" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_FDSC = 0x66647363;
|
||||
|
||||
/**
|
||||
* Font metrics. Table tag "fmtx" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_FMTX = 0x666d7478;
|
||||
|
||||
/**
|
||||
* Justification. Table tag "just" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_JUST = 0x6a757374;
|
||||
|
||||
/**
|
||||
* Ligature caret. Table tag "lcar" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_LCAR = 0x6c636172;
|
||||
|
||||
/**
|
||||
* Glyph metamorphosis. Table tag "mort" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_MORT = 0x6d6f7274;
|
||||
|
||||
/**
|
||||
* Optical bounds. Table tag "opbd" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_OPBD = 0x6F706264;
|
||||
|
||||
/**
|
||||
* Glyph properties. Table tag "prop" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_PROP = 0x70726f70;
|
||||
|
||||
/**
|
||||
* Tracking. Table tag "trak" in the Open
|
||||
* Type Specification.
|
||||
*/
|
||||
public static final int TAG_TRAK = 0x7472616b;
|
||||
|
||||
/**
|
||||
* Returns the version of the {@code OpenType} font.
|
||||
* 1.0 is represented as 0x00010000.
|
||||
* @return the version of the {@code OpenType} font.
|
||||
*/
|
||||
public int getVersion();
|
||||
|
||||
/**
|
||||
* Returns the table as an array of bytes for a specified tag.
|
||||
* Tags for sfnt tables include items like <i>cmap</i>,
|
||||
* <i>name</i> and <i>head</i>. The {@code byte} array
|
||||
* returned is a copy of the font data in memory.
|
||||
* @param sfntTag a four-character code as a 32-bit integer
|
||||
* @return a {@code byte} array that is the table that
|
||||
* contains the font data corresponding to the specified
|
||||
* tag.
|
||||
*/
|
||||
public byte[] getFontTable(int sfntTag);
|
||||
|
||||
/**
|
||||
* Returns the table as an array of bytes for a specified tag.
|
||||
* Tags for sfnt tables include items like <i>cmap</i>,
|
||||
* <i>name</i> and <i>head</i>. The byte array returned is a
|
||||
* copy of the font data in memory.
|
||||
* @param strSfntTag a four-character code as a
|
||||
* {@code String}
|
||||
* @return a {@code byte} array that is the table that
|
||||
* contains the font data corresponding to the specified
|
||||
* tag.
|
||||
*/
|
||||
public byte[] getFontTable(String strSfntTag);
|
||||
|
||||
/**
|
||||
* Returns a subset of the table as an array of bytes
|
||||
* for a specified tag. Tags for sfnt tables include
|
||||
* items like <i>cmap</i>, <i>name</i> and <i>head</i>.
|
||||
* The byte array returned is a copy of the font data in
|
||||
* memory.
|
||||
* @param sfntTag a four-character code as a 32-bit integer
|
||||
* @param offset index of first byte to return from table
|
||||
* @param count number of bytes to return from table
|
||||
* @return a subset of the table corresponding to
|
||||
* {@code sfntTag} and containing the bytes
|
||||
* starting at {@code offset} byte and including
|
||||
* {@code count} bytes.
|
||||
*/
|
||||
public byte[] getFontTable(int sfntTag, int offset, int count);
|
||||
|
||||
/**
|
||||
* Returns a subset of the table as an array of bytes
|
||||
* for a specified tag. Tags for sfnt tables include items
|
||||
* like <i>cmap</i>, <i>name</i> and <i>head</i>. The
|
||||
* {@code byte} array returned is a copy of the font
|
||||
* data in memory.
|
||||
* @param strSfntTag a four-character code as a
|
||||
* {@code String}
|
||||
* @param offset index of first byte to return from table
|
||||
* @param count number of bytes to return from table
|
||||
* @return a subset of the table corresponding to
|
||||
* {@code strSfntTag} and containing the bytes
|
||||
* starting at {@code offset} byte and including
|
||||
* {@code count} bytes.
|
||||
*/
|
||||
public byte[] getFontTable(String strSfntTag, int offset, int count);
|
||||
|
||||
/**
|
||||
* Returns the size of the table for a specified tag. Tags for sfnt
|
||||
* tables include items like <i>cmap</i>, <i>name</i> and <i>head</i>.
|
||||
* @param sfntTag a four-character code as a 32-bit integer
|
||||
* @return the size of the table corresponding to the specified
|
||||
* tag.
|
||||
*/
|
||||
public int getFontTableSize(int sfntTag);
|
||||
|
||||
/**
|
||||
* Returns the size of the table for a specified tag. Tags for sfnt
|
||||
* tables include items like <i>cmap</i>, <i>name</i> and <i>head</i>.
|
||||
* @param strSfntTag a four-character code as a
|
||||
* {@code String}
|
||||
* @return the size of the table corresponding to the specified tag.
|
||||
*/
|
||||
public int getFontTableSize(String strSfntTag);
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is
|
||||
* copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
|
||||
* of IBM. These materials are provided under terms of a License
|
||||
* Agreement between Taligent and Sun. This technology is protected
|
||||
* by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
import java.awt.Shape;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* The {@code ShapeGraphicAttribute} class is an implementation of
|
||||
* {@link GraphicAttribute} that draws shapes in a {@link TextLayout}.
|
||||
* @see GraphicAttribute
|
||||
*/
|
||||
public final class ShapeGraphicAttribute extends GraphicAttribute {
|
||||
|
||||
private Shape fShape;
|
||||
private boolean fStroke;
|
||||
|
||||
/**
|
||||
* A key indicating the shape should be stroked with a 1-pixel wide stroke.
|
||||
*/
|
||||
public static final boolean STROKE = true;
|
||||
|
||||
/**
|
||||
* A key indicating the shape should be filled.
|
||||
*/
|
||||
public static final boolean FILL = false;
|
||||
|
||||
// cache shape bounds, since GeneralPath doesn't
|
||||
private Rectangle2D fShapeBounds;
|
||||
|
||||
/**
|
||||
* Constructs a {@code ShapeGraphicAttribute} for the specified
|
||||
* {@link Shape}.
|
||||
* @param shape the {@code Shape} to render. The
|
||||
* {@code Shape} is rendered with its origin at the origin of
|
||||
* this {@code ShapeGraphicAttribute} in the
|
||||
* host {@code TextLayout}. This object maintains a reference to
|
||||
* {@code shape}.
|
||||
* @param alignment one of the alignments from this
|
||||
* {@code ShapeGraphicAttribute}.
|
||||
* @param stroke {@code true} if the {@code Shape} should be
|
||||
* stroked; {@code false} if the {@code Shape} should be
|
||||
* filled.
|
||||
*/
|
||||
public ShapeGraphicAttribute(Shape shape,
|
||||
int alignment,
|
||||
boolean stroke) {
|
||||
|
||||
super(alignment);
|
||||
|
||||
fShape = shape;
|
||||
fStroke = stroke;
|
||||
fShapeBounds = fShape.getBounds2D();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ascent of this {@code ShapeGraphicAttribute}. The
|
||||
* ascent of a {@code ShapeGraphicAttribute} is the positive
|
||||
* distance from the origin of its {@code Shape} to the top of
|
||||
* bounds of its {@code Shape}.
|
||||
* @return the ascent of this {@code ShapeGraphicAttribute}.
|
||||
*/
|
||||
public float getAscent() {
|
||||
|
||||
return (float) Math.max(0, -fShapeBounds.getMinY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the descent of this {@code ShapeGraphicAttribute}.
|
||||
* The descent of a {@code ShapeGraphicAttribute} is the distance
|
||||
* from the origin of its {@code Shape} to the bottom of the
|
||||
* bounds of its {@code Shape}.
|
||||
* @return the descent of this {@code ShapeGraphicAttribute}.
|
||||
*/
|
||||
public float getDescent() {
|
||||
|
||||
return (float) Math.max(0, fShapeBounds.getMaxY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the advance of this {@code ShapeGraphicAttribute}.
|
||||
* The advance of a {@code ShapeGraphicAttribute} is the distance
|
||||
* from the origin of its {@code Shape} to the right side of the
|
||||
* bounds of its {@code Shape}.
|
||||
* @return the advance of this {@code ShapeGraphicAttribute}.
|
||||
*/
|
||||
public float getAdvance() {
|
||||
|
||||
return (float) Math.max(0, fShapeBounds.getMaxX());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void draw(Graphics2D graphics, float x, float y) {
|
||||
|
||||
// translating graphics to draw Shape !!!
|
||||
graphics.translate((int)x, (int)y);
|
||||
|
||||
try {
|
||||
if (fStroke == STROKE) {
|
||||
// REMIND: set stroke to correct size
|
||||
graphics.draw(fShape);
|
||||
}
|
||||
else {
|
||||
graphics.fill(fShape);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
graphics.translate(-(int)x, -(int)y);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Rectangle2D} that encloses all of the
|
||||
* bits drawn by this {@code ShapeGraphicAttribute} relative to
|
||||
* the rendering position. A graphic can be rendered beyond its
|
||||
* origin, ascent, descent, or advance; but if it does, this method's
|
||||
* implementation should indicate where the graphic is rendered.
|
||||
* @return a {@code Rectangle2D} that encloses all of the bits
|
||||
* rendered by this {@code ShapeGraphicAttribute}.
|
||||
*/
|
||||
public Rectangle2D getBounds() {
|
||||
|
||||
Rectangle2D.Float bounds = new Rectangle2D.Float();
|
||||
bounds.setRect(fShapeBounds);
|
||||
|
||||
if (fStroke == STROKE) {
|
||||
++bounds.width;
|
||||
++bounds.height;
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link java.awt.Shape} that represents the region that
|
||||
* this {@code ShapeGraphicAttribute} renders. This is used when a
|
||||
* {@link TextLayout} is requested to return the outline of the text.
|
||||
* The (untransformed) shape must not extend outside the rectangular
|
||||
* bounds returned by {@code getBounds}.
|
||||
* @param tx an optional {@link AffineTransform} to apply to the
|
||||
* this {@code ShapeGraphicAttribute}. This can be null.
|
||||
* @return the {@code Shape} representing this graphic attribute,
|
||||
* suitable for stroking or filling.
|
||||
* @since 1.6
|
||||
*/
|
||||
public Shape getOutline(AffineTransform tx) {
|
||||
return tx == null ? fShape : tx.createTransformedShape(fShape);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode for this {@code ShapeGraphicAttribute}.
|
||||
* @return a hash code value for this
|
||||
* {@code ShapeGraphicAttribute}.
|
||||
*/
|
||||
public int hashCode() {
|
||||
|
||||
return fShape.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@code ShapeGraphicAttribute} to the specified
|
||||
* {@code Object}.
|
||||
* @param rhs the {@code Object} to compare for equality
|
||||
* @return {@code true} if this
|
||||
* {@code ShapeGraphicAttribute} equals {@code rhs};
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public boolean equals(Object rhs) {
|
||||
|
||||
try {
|
||||
return equals((ShapeGraphicAttribute) rhs);
|
||||
}
|
||||
catch(ClassCastException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@code ShapeGraphicAttribute} to the specified
|
||||
* {@code ShapeGraphicAttribute}.
|
||||
* @param rhs the {@code ShapeGraphicAttribute} to compare for
|
||||
* equality
|
||||
* @return {@code true} if this
|
||||
* {@code ShapeGraphicAttribute} equals {@code rhs};
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public boolean equals(ShapeGraphicAttribute rhs) {
|
||||
|
||||
if (rhs == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == rhs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fStroke != rhs.fStroke) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getAlignment() != rhs.getAlignment()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fShape.equals(rhs.fShape)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,499 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright IBM Corp. 1999, All rights reserved.
|
||||
*/
|
||||
package java.awt.font;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.im.InputMethodHighlight;
|
||||
import java.text.Annotation;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.text.AttributedCharacterIterator.Attribute;
|
||||
import java.util.Vector;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import sun.font.CodePointIterator;
|
||||
import sun.font.Decoration;
|
||||
import sun.font.FontResolver;
|
||||
|
||||
/**
|
||||
* This class stores Font, GraphicAttribute, and Decoration intervals
|
||||
* on a paragraph of styled text.
|
||||
* <p>
|
||||
* Currently, this class is optimized for a small number of intervals
|
||||
* (preferably 1).
|
||||
*/
|
||||
final class StyledParagraph {
|
||||
|
||||
// the length of the paragraph
|
||||
private int length;
|
||||
|
||||
// If there is a single Decoration for the whole paragraph, it
|
||||
// is stored here. Otherwise this field is ignored.
|
||||
|
||||
private Decoration decoration;
|
||||
|
||||
// If there is a single Font or GraphicAttribute for the whole
|
||||
// paragraph, it is stored here. Otherwise this field is ignored.
|
||||
private Object font;
|
||||
|
||||
// If there are multiple Decorations in the paragraph, they are
|
||||
// stored in this Vector, in order. Otherwise this vector and
|
||||
// the decorationStarts array are null.
|
||||
private Vector<Decoration> decorations;
|
||||
// If there are multiple Decorations in the paragraph,
|
||||
// decorationStarts[i] contains the index where decoration i
|
||||
// starts. For convenience, there is an extra entry at the
|
||||
// end of this array with the length of the paragraph.
|
||||
int[] decorationStarts;
|
||||
|
||||
// If there are multiple Fonts/GraphicAttributes in the paragraph,
|
||||
// they are
|
||||
// stored in this Vector, in order. Otherwise this vector and
|
||||
// the fontStarts array are null.
|
||||
private Vector<Object> fonts;
|
||||
// If there are multiple Fonts/GraphicAttributes in the paragraph,
|
||||
// fontStarts[i] contains the index where decoration i
|
||||
// starts. For convenience, there is an extra entry at the
|
||||
// end of this array with the length of the paragraph.
|
||||
int[] fontStarts;
|
||||
|
||||
private static int INITIAL_SIZE = 8;
|
||||
|
||||
/**
|
||||
* Create a new StyledParagraph over the given styled text.
|
||||
* @param aci an iterator over the text
|
||||
* @param chars the characters extracted from aci
|
||||
*/
|
||||
public StyledParagraph(AttributedCharacterIterator aci,
|
||||
char[] chars) {
|
||||
|
||||
int start = aci.getBeginIndex();
|
||||
int end = aci.getEndIndex();
|
||||
length = end - start;
|
||||
|
||||
int index = start;
|
||||
aci.first();
|
||||
|
||||
do {
|
||||
final int nextRunStart = aci.getRunLimit();
|
||||
final int localIndex = index-start;
|
||||
|
||||
Map<? extends Attribute, ?> attributes = aci.getAttributes();
|
||||
attributes = addInputMethodAttrs(attributes);
|
||||
Decoration d = Decoration.getDecoration(attributes);
|
||||
addDecoration(d, localIndex);
|
||||
|
||||
Object f = getGraphicOrFont(attributes);
|
||||
if (f == null) {
|
||||
addFonts(chars, attributes, localIndex, nextRunStart-start);
|
||||
}
|
||||
else {
|
||||
addFont(f, localIndex);
|
||||
}
|
||||
|
||||
aci.setIndex(nextRunStart);
|
||||
index = nextRunStart;
|
||||
|
||||
} while (index < end);
|
||||
|
||||
// Add extra entries to starts arrays with the length
|
||||
// of the paragraph. 'this' is used as a dummy value
|
||||
// in the Vector.
|
||||
if (decorations != null) {
|
||||
decorationStarts = addToVector(this, length, decorations, decorationStarts);
|
||||
}
|
||||
if (fonts != null) {
|
||||
fontStarts = addToVector(this, length, fonts, fontStarts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust indices in starts to reflect an insertion after pos.
|
||||
* Any index in starts greater than pos will be increased by 1.
|
||||
*/
|
||||
private static void insertInto(int pos, int[] starts, int numStarts) {
|
||||
|
||||
while (starts[--numStarts] > pos) {
|
||||
starts[numStarts] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a StyledParagraph reflecting the insertion of a single character
|
||||
* into the text. This method will attempt to reuse the given paragraph,
|
||||
* but may create a new paragraph.
|
||||
* @param aci an iterator over the text. The text should be the same as the
|
||||
* text used to create (or most recently update) oldParagraph, with
|
||||
* the exception of inserting a single character at insertPos.
|
||||
* @param chars the characters in aci
|
||||
* @param insertPos the index of the new character in aci
|
||||
* @param oldParagraph a StyledParagraph for the text in aci before the
|
||||
* insertion
|
||||
*/
|
||||
public static StyledParagraph insertChar(AttributedCharacterIterator aci,
|
||||
char[] chars,
|
||||
int insertPos,
|
||||
StyledParagraph oldParagraph) {
|
||||
|
||||
// If the styles at insertPos match those at insertPos-1,
|
||||
// oldParagraph will be reused. Otherwise we create a new
|
||||
// paragraph.
|
||||
|
||||
char ch = aci.setIndex(insertPos);
|
||||
int relativePos = Math.max(insertPos - aci.getBeginIndex() - 1, 0);
|
||||
|
||||
Map<? extends Attribute, ?> attributes =
|
||||
addInputMethodAttrs(aci.getAttributes());
|
||||
Decoration d = Decoration.getDecoration(attributes);
|
||||
if (!oldParagraph.getDecorationAt(relativePos).equals(d)) {
|
||||
return new StyledParagraph(aci, chars);
|
||||
}
|
||||
Object f = getGraphicOrFont(attributes);
|
||||
if (f == null) {
|
||||
FontResolver resolver = FontResolver.getInstance();
|
||||
int fontIndex = resolver.getFontIndex(ch);
|
||||
f = resolver.getFont(fontIndex, attributes);
|
||||
}
|
||||
if (!oldParagraph.getFontOrGraphicAt(relativePos).equals(f)) {
|
||||
return new StyledParagraph(aci, chars);
|
||||
}
|
||||
|
||||
// insert into existing paragraph
|
||||
oldParagraph.length += 1;
|
||||
if (oldParagraph.decorations != null) {
|
||||
insertInto(relativePos,
|
||||
oldParagraph.decorationStarts,
|
||||
oldParagraph.decorations.size());
|
||||
}
|
||||
if (oldParagraph.fonts != null) {
|
||||
insertInto(relativePos,
|
||||
oldParagraph.fontStarts,
|
||||
oldParagraph.fonts.size());
|
||||
}
|
||||
return oldParagraph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust indices in starts to reflect a deletion after deleteAt.
|
||||
* Any index in starts greater than deleteAt will be increased by 1.
|
||||
* It is the caller's responsibility to make sure that no 0-length
|
||||
* runs result.
|
||||
*/
|
||||
private static void deleteFrom(int deleteAt, int[] starts, int numStarts) {
|
||||
|
||||
while (starts[--numStarts] > deleteAt) {
|
||||
starts[numStarts] -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a StyledParagraph reflecting the insertion of a single character
|
||||
* into the text. This method will attempt to reuse the given paragraph,
|
||||
* but may create a new paragraph.
|
||||
* @param aci an iterator over the text. The text should be the same as the
|
||||
* text used to create (or most recently update) oldParagraph, with
|
||||
* the exception of deleting a single character at deletePos.
|
||||
* @param chars the characters in aci
|
||||
* @param deletePos the index where a character was removed
|
||||
* @param oldParagraph a StyledParagraph for the text in aci before the
|
||||
* insertion
|
||||
*/
|
||||
public static StyledParagraph deleteChar(AttributedCharacterIterator aci,
|
||||
char[] chars,
|
||||
int deletePos,
|
||||
StyledParagraph oldParagraph) {
|
||||
|
||||
// We will reuse oldParagraph unless there was a length-1 run
|
||||
// at deletePos. We could do more work and check the individual
|
||||
// Font and Decoration runs, but we don't right now...
|
||||
deletePos -= aci.getBeginIndex();
|
||||
|
||||
if (oldParagraph.decorations == null && oldParagraph.fonts == null) {
|
||||
oldParagraph.length -= 1;
|
||||
return oldParagraph;
|
||||
}
|
||||
|
||||
if (oldParagraph.getRunLimit(deletePos) == deletePos+1) {
|
||||
if (deletePos == 0 || oldParagraph.getRunLimit(deletePos-1) == deletePos) {
|
||||
return new StyledParagraph(aci, chars);
|
||||
}
|
||||
}
|
||||
|
||||
oldParagraph.length -= 1;
|
||||
if (oldParagraph.decorations != null) {
|
||||
deleteFrom(deletePos,
|
||||
oldParagraph.decorationStarts,
|
||||
oldParagraph.decorations.size());
|
||||
}
|
||||
if (oldParagraph.fonts != null) {
|
||||
deleteFrom(deletePos,
|
||||
oldParagraph.fontStarts,
|
||||
oldParagraph.fonts.size());
|
||||
}
|
||||
return oldParagraph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index at which there is a different Font, GraphicAttribute, or
|
||||
* Decoration than at the given index.
|
||||
* @param index a valid index in the paragraph
|
||||
* @return the first index where there is a change in attributes from
|
||||
* those at index
|
||||
*/
|
||||
public int getRunLimit(int index) {
|
||||
|
||||
if (index < 0 || index >= length) {
|
||||
throw new IllegalArgumentException("index out of range");
|
||||
}
|
||||
int limit1 = length;
|
||||
if (decorations != null) {
|
||||
int run = findRunContaining(index, decorationStarts);
|
||||
limit1 = decorationStarts[run+1];
|
||||
}
|
||||
int limit2 = length;
|
||||
if (fonts != null) {
|
||||
int run = findRunContaining(index, fontStarts);
|
||||
limit2 = fontStarts[run+1];
|
||||
}
|
||||
return Math.min(limit1, limit2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Decoration in effect at the given index.
|
||||
* @param index a valid index in the paragraph
|
||||
* @return the Decoration at index.
|
||||
*/
|
||||
public Decoration getDecorationAt(int index) {
|
||||
|
||||
if (index < 0 || index >= length) {
|
||||
throw new IllegalArgumentException("index out of range");
|
||||
}
|
||||
if (decorations == null) {
|
||||
return decoration;
|
||||
}
|
||||
int run = findRunContaining(index, decorationStarts);
|
||||
return decorations.elementAt(run);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Font or GraphicAttribute in effect at the given index.
|
||||
* The client must test the type of the return value to determine what
|
||||
* it is.
|
||||
* @param index a valid index in the paragraph
|
||||
* @return the Font or GraphicAttribute at index.
|
||||
*/
|
||||
public Object getFontOrGraphicAt(int index) {
|
||||
|
||||
if (index < 0 || index >= length) {
|
||||
throw new IllegalArgumentException("index out of range");
|
||||
}
|
||||
if (fonts == null) {
|
||||
return font;
|
||||
}
|
||||
int run = findRunContaining(index, fontStarts);
|
||||
return fonts.elementAt(run);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return i such that starts[i] <= index < starts[i+1]. starts
|
||||
* must be in increasing order, with at least one element greater
|
||||
* than index.
|
||||
*/
|
||||
private static int findRunContaining(int index, int[] starts) {
|
||||
|
||||
for (int i=1; true; i++) {
|
||||
if (starts[i] > index) {
|
||||
return i-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the given Object to the given Vector. Add
|
||||
* the given index to the given starts array. If the
|
||||
* starts array does not have room for the index, a
|
||||
* new array is created and returned.
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static int[] addToVector(Object obj,
|
||||
int index,
|
||||
Vector v,
|
||||
int[] starts) {
|
||||
|
||||
if (!v.lastElement().equals(obj)) {
|
||||
v.addElement(obj);
|
||||
int count = v.size();
|
||||
if (starts.length == count) {
|
||||
int[] temp = new int[starts.length*2];
|
||||
System.arraycopy(starts, 0, temp, 0, starts.length);
|
||||
starts = temp;
|
||||
}
|
||||
starts[count-1] = index;
|
||||
}
|
||||
return starts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new Decoration run with the given Decoration at the
|
||||
* given index.
|
||||
*/
|
||||
private void addDecoration(Decoration d, int index) {
|
||||
|
||||
if (decorations != null) {
|
||||
decorationStarts = addToVector(d,
|
||||
index,
|
||||
decorations,
|
||||
decorationStarts);
|
||||
}
|
||||
else if (decoration == null) {
|
||||
decoration = d;
|
||||
}
|
||||
else {
|
||||
if (!decoration.equals(d)) {
|
||||
decorations = new Vector<Decoration>(INITIAL_SIZE);
|
||||
decorations.addElement(decoration);
|
||||
decorations.addElement(d);
|
||||
decorationStarts = new int[INITIAL_SIZE];
|
||||
decorationStarts[0] = 0;
|
||||
decorationStarts[1] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new Font/GraphicAttribute run with the given object at the
|
||||
* given index.
|
||||
*/
|
||||
private void addFont(Object f, int index) {
|
||||
|
||||
if (fonts != null) {
|
||||
fontStarts = addToVector(f, index, fonts, fontStarts);
|
||||
}
|
||||
else if (font == null) {
|
||||
font = f;
|
||||
}
|
||||
else {
|
||||
if (!font.equals(f)) {
|
||||
fonts = new Vector<Object>(INITIAL_SIZE);
|
||||
fonts.addElement(font);
|
||||
fonts.addElement(f);
|
||||
fontStarts = new int[INITIAL_SIZE];
|
||||
fontStarts[0] = 0;
|
||||
fontStarts[1] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given chars into Fonts using FontResolver, then add
|
||||
* font runs for each.
|
||||
*/
|
||||
private void addFonts(char[] chars, Map<? extends Attribute, ?> attributes,
|
||||
int start, int limit) {
|
||||
|
||||
FontResolver resolver = FontResolver.getInstance();
|
||||
CodePointIterator iter = CodePointIterator.create(chars, start, limit);
|
||||
for (int runStart = iter.charIndex(); runStart < limit; runStart = iter.charIndex()) {
|
||||
int fontIndex = resolver.nextFontRunIndex(iter);
|
||||
addFont(resolver.getFont(fontIndex, attributes), runStart);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Map with entries from oldStyles, as well as input
|
||||
* method entries, if any.
|
||||
*/
|
||||
static Map<? extends Attribute, ?>
|
||||
addInputMethodAttrs(Map<? extends Attribute, ?> oldStyles) {
|
||||
|
||||
Object value = oldStyles.get(TextAttribute.INPUT_METHOD_HIGHLIGHT);
|
||||
|
||||
try {
|
||||
if (value != null) {
|
||||
if (value instanceof Annotation) {
|
||||
value = ((Annotation)value).getValue();
|
||||
}
|
||||
|
||||
InputMethodHighlight hl;
|
||||
hl = (InputMethodHighlight) value;
|
||||
|
||||
Map<? extends Attribute, ?> imStyles = null;
|
||||
try {
|
||||
imStyles = hl.getStyle();
|
||||
} catch (NoSuchMethodError e) {
|
||||
}
|
||||
|
||||
if (imStyles == null) {
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
imStyles = tk.mapInputMethodHighlight(hl);
|
||||
}
|
||||
|
||||
if (imStyles != null) {
|
||||
HashMap<Attribute, Object>
|
||||
newStyles = new HashMap<>(5, (float)0.9);
|
||||
newStyles.putAll(oldStyles);
|
||||
|
||||
newStyles.putAll(imStyles);
|
||||
|
||||
return newStyles;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(ClassCastException e) {
|
||||
}
|
||||
|
||||
return oldStyles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a GraphicAttribute or Font from the given attributes.
|
||||
* If attributes does not contain a GraphicAttribute, Font, or
|
||||
* Font family entry this method returns null.
|
||||
*/
|
||||
private static Object getGraphicOrFont(
|
||||
Map<? extends Attribute, ?> attributes) {
|
||||
|
||||
Object value = attributes.get(TextAttribute.CHAR_REPLACEMENT);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
value = attributes.get(TextAttribute.FONT);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (attributes.get(TextAttribute.FAMILY) != null) {
|
||||
return Font.getFont(attributes);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
1127
src/java.desktop/share/classes/java/awt/font/TextAttribute.java
Normal file
1127
src/java.desktop/share/classes/java/awt/font/TextAttribute.java
Normal file
File diff suppressed because it is too large
Load diff
247
src/java.desktop/share/classes/java/awt/font/TextHitInfo.java
Normal file
247
src/java.desktop/share/classes/java/awt/font/TextHitInfo.java
Normal file
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is
|
||||
* copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
|
||||
* of IBM. These materials are provided under terms of a License
|
||||
* Agreement between Taligent and Sun. This technology is protected
|
||||
* by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
import java.lang.String;
|
||||
|
||||
/**
|
||||
* The {@code TextHitInfo} class represents a character position in a
|
||||
* text model, and a <b>bias</b>, or "side," of the character. Biases are
|
||||
* either <EM>leading</EM> (the left edge, for a left-to-right character)
|
||||
* or <EM>trailing</EM> (the right edge, for a left-to-right character).
|
||||
* Instances of {@code TextHitInfo} are used to specify caret and
|
||||
* insertion positions within text.
|
||||
* <p>
|
||||
* For example, consider the text "abc". TextHitInfo.trailing(1)
|
||||
* corresponds to the right side of the 'b' in the text.
|
||||
* <p>
|
||||
* {@code TextHitInfo} is used primarily by {@link TextLayout} and
|
||||
* clients of {@code TextLayout}. Clients of {@code TextLayout}
|
||||
* query {@code TextHitInfo} instances for an insertion offset, where
|
||||
* new text is inserted into the text model. The insertion offset is equal
|
||||
* to the character position in the {@code TextHitInfo} if the bias
|
||||
* is leading, and one character after if the bias is trailing. The
|
||||
* insertion offset for TextHitInfo.trailing(1) is 2.
|
||||
* <p>
|
||||
* Sometimes it is convenient to construct a {@code TextHitInfo} with
|
||||
* the same insertion offset as an existing one, but on the opposite
|
||||
* character. The {@code getOtherHit} method constructs a new
|
||||
* {@code TextHitInfo} with the same insertion offset as an existing
|
||||
* one, with a hit on the character on the other side of the insertion offset.
|
||||
* Calling {@code getOtherHit} on trailing(1) would return leading(2).
|
||||
* In general, {@code getOtherHit} for trailing(n) returns
|
||||
* leading(n+1) and {@code getOtherHit} for leading(n)
|
||||
* returns trailing(n-1).
|
||||
* <p>
|
||||
* <strong>Example</strong>:<p>
|
||||
* Converting a graphical point to an insertion point within a text
|
||||
* model
|
||||
* <blockquote><pre>
|
||||
* TextLayout layout = ...;
|
||||
* Point2D.Float hitPoint = ...;
|
||||
* TextHitInfo hitInfo = layout.hitTestChar(hitPoint.x, hitPoint.y);
|
||||
* int insPoint = hitInfo.getInsertionIndex();
|
||||
* // insPoint is relative to layout; may need to adjust for use
|
||||
* // in a text model
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @see TextLayout
|
||||
*/
|
||||
|
||||
public final class TextHitInfo {
|
||||
private int charIndex;
|
||||
private boolean isLeadingEdge;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code TextHitInfo}.
|
||||
* @param charIndex the index of the character hit
|
||||
* @param isLeadingEdge {@code true} if the leading edge of the
|
||||
* character was hit
|
||||
*/
|
||||
private TextHitInfo(int charIndex, boolean isLeadingEdge) {
|
||||
this.charIndex = charIndex;
|
||||
this.isLeadingEdge = isLeadingEdge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the character hit.
|
||||
* @return the index of the character hit.
|
||||
*/
|
||||
public int getCharIndex() {
|
||||
return charIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the leading edge of the character was
|
||||
* hit.
|
||||
* @return {@code true} if the leading edge of the character was
|
||||
* hit; {@code false} otherwise.
|
||||
*/
|
||||
public boolean isLeadingEdge() {
|
||||
return isLeadingEdge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the insertion index. This is the character index if
|
||||
* the leading edge of the character was hit, and one greater
|
||||
* than the character index if the trailing edge was hit.
|
||||
* @return the insertion index.
|
||||
*/
|
||||
public int getInsertionIndex() {
|
||||
return isLeadingEdge ? charIndex : charIndex + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code.
|
||||
* @return the hash code of this {@code TextHitInfo}, which is
|
||||
* also the {@code charIndex} of this {@code TextHitInfo}.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return charIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the specified {@code Object} is a
|
||||
* {@code TextHitInfo} and equals this {@code TextHitInfo}.
|
||||
* @param obj the {@code Object} to test for equality
|
||||
* @return {@code true} if the specified {@code Object}
|
||||
* equals this {@code TextHitInfo}; {@code false} otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
return (obj instanceof TextHitInfo) && equals((TextHitInfo)obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the specified {@code TextHitInfo}
|
||||
* has the same {@code charIndex} and {@code isLeadingEdge}
|
||||
* as this {@code TextHitInfo}. This is not the same as having
|
||||
* the same insertion offset.
|
||||
* @param hitInfo a specified {@code TextHitInfo}
|
||||
* @return {@code true} if the specified {@code TextHitInfo}
|
||||
* has the same {@code charIndex} and {@code isLeadingEdge}
|
||||
* as this {@code TextHitInfo}.
|
||||
*/
|
||||
public boolean equals(TextHitInfo hitInfo) {
|
||||
return hitInfo != null && charIndex == hitInfo.charIndex &&
|
||||
isLeadingEdge == hitInfo.isLeadingEdge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code String} representing the hit for debugging
|
||||
* use only.
|
||||
* @return a {@code String} representing this
|
||||
* {@code TextHitInfo}.
|
||||
*/
|
||||
public String toString() {
|
||||
return "TextHitInfo[" + charIndex + (isLeadingEdge ? "L" : "T")+"]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code TextHitInfo} on the leading edge of the
|
||||
* character at the specified {@code charIndex}.
|
||||
* @param charIndex the index of the character hit
|
||||
* @return a {@code TextHitInfo} on the leading edge of the
|
||||
* character at the specified {@code charIndex}.
|
||||
*/
|
||||
public static TextHitInfo leading(int charIndex) {
|
||||
return new TextHitInfo(charIndex, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a hit on the trailing edge of the character at
|
||||
* the specified {@code charIndex}.
|
||||
* @param charIndex the index of the character hit
|
||||
* @return a {@code TextHitInfo} on the trailing edge of the
|
||||
* character at the specified {@code charIndex}.
|
||||
*/
|
||||
public static TextHitInfo trailing(int charIndex) {
|
||||
return new TextHitInfo(charIndex, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code TextHitInfo} at the specified offset,
|
||||
* associated with the character before the offset.
|
||||
* @param offset an offset associated with the character before
|
||||
* the offset
|
||||
* @return a {@code TextHitInfo} at the specified offset.
|
||||
*/
|
||||
public static TextHitInfo beforeOffset(int offset) {
|
||||
return new TextHitInfo(offset-1, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code TextHitInfo} at the specified offset,
|
||||
* associated with the character after the offset.
|
||||
* @param offset an offset associated with the character after
|
||||
* the offset
|
||||
* @return a {@code TextHitInfo} at the specified offset.
|
||||
*/
|
||||
public static TextHitInfo afterOffset(int offset) {
|
||||
return new TextHitInfo(offset, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code TextHitInfo} on the other side of the
|
||||
* insertion point. This {@code TextHitInfo} remains unchanged.
|
||||
* @return a {@code TextHitInfo} on the other side of the
|
||||
* insertion point.
|
||||
*/
|
||||
public TextHitInfo getOtherHit() {
|
||||
if (isLeadingEdge) {
|
||||
return trailing(charIndex - 1);
|
||||
} else {
|
||||
return leading(charIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code TextHitInfo} whose character index is offset
|
||||
* by {@code delta} from the {@code charIndex} of this
|
||||
* {@code TextHitInfo}. This {@code TextHitInfo} remains
|
||||
* unchanged.
|
||||
* @param delta the value to offset this {@code charIndex}
|
||||
* @return a {@code TextHitInfo} whose {@code charIndex} is
|
||||
* offset by {@code delta} from the {@code charIndex} of
|
||||
* this {@code TextHitInfo}.
|
||||
*/
|
||||
public TextHitInfo getOffsetHit(int delta) {
|
||||
return new TextHitInfo(charIndex + delta, isLeadingEdge);
|
||||
}
|
||||
}
|
240
src/java.desktop/share/classes/java/awt/font/TextJustifier.java
Normal file
240
src/java.desktop/share/classes/java/awt/font/TextJustifier.java
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is
|
||||
* copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
|
||||
* of IBM. These materials are provided under terms of a License
|
||||
* Agreement between Taligent and Sun. This technology is protected
|
||||
* by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
/*
|
||||
* one info for each side of each glyph
|
||||
* separate infos for grow and shrink case
|
||||
* !!! this doesn't really need to be a separate class. If we keep it
|
||||
* separate, probably the newJustify code from TextLayout belongs here as well.
|
||||
*/
|
||||
|
||||
class TextJustifier {
|
||||
private GlyphJustificationInfo[] info;
|
||||
private int start;
|
||||
private int limit;
|
||||
|
||||
static boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Initialize the justifier with an array of infos corresponding to each
|
||||
* glyph. Start and limit indicate the range of the array to examine.
|
||||
*/
|
||||
TextJustifier(GlyphJustificationInfo[] info, int start, int limit) {
|
||||
this.info = info;
|
||||
this.start = start;
|
||||
this.limit = limit;
|
||||
|
||||
if (DEBUG) {
|
||||
System.out.println("start: " + start + ", limit: " + limit);
|
||||
for (int i = start; i < limit; i++) {
|
||||
GlyphJustificationInfo gji = info[i];
|
||||
System.out.println("w: " + gji.weight + ", gp: " +
|
||||
gji.growPriority + ", gll: " +
|
||||
gji.growLeftLimit + ", grl: " +
|
||||
gji.growRightLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final int MAX_PRIORITY = 3;
|
||||
|
||||
/**
|
||||
* Return an array of deltas twice as long as the original info array,
|
||||
* indicating the amount by which each side of each glyph should grow
|
||||
* or shrink.
|
||||
*
|
||||
* Delta should be positive to expand the line, and negative to compress it.
|
||||
*/
|
||||
public float[] justify(float delta) {
|
||||
float[] deltas = new float[info.length * 2];
|
||||
|
||||
boolean grow = delta > 0;
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println("delta: " + delta);
|
||||
|
||||
// make separate passes through glyphs in order of decreasing priority
|
||||
// until justifyDelta is zero or we run out of priorities.
|
||||
int fallbackPriority = -1;
|
||||
for (int p = 0; delta != 0; p++) {
|
||||
/*
|
||||
* special case 'fallback' iteration, set flag and recheck
|
||||
* highest priority
|
||||
*/
|
||||
boolean lastPass = p > MAX_PRIORITY;
|
||||
if (lastPass)
|
||||
p = fallbackPriority;
|
||||
|
||||
// pass through glyphs, first collecting weights and limits
|
||||
float weight = 0;
|
||||
float gslimit = 0;
|
||||
float absorbweight = 0;
|
||||
for (int i = start; i < limit; i++) {
|
||||
GlyphJustificationInfo gi = info[i];
|
||||
if ((grow ? gi.growPriority : gi.shrinkPriority) == p) {
|
||||
if (fallbackPriority == -1) {
|
||||
fallbackPriority = p;
|
||||
}
|
||||
|
||||
if (i != start) { // ignore left of first character
|
||||
weight += gi.weight;
|
||||
if (grow) {
|
||||
gslimit += gi.growLeftLimit;
|
||||
if (gi.growAbsorb) {
|
||||
absorbweight += gi.weight;
|
||||
}
|
||||
} else {
|
||||
gslimit += gi.shrinkLeftLimit;
|
||||
if (gi.shrinkAbsorb) {
|
||||
absorbweight += gi.weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i + 1 != limit) { // ignore right of last character
|
||||
weight += gi.weight;
|
||||
if (grow) {
|
||||
gslimit += gi.growRightLimit;
|
||||
if (gi.growAbsorb) {
|
||||
absorbweight += gi.weight;
|
||||
}
|
||||
} else {
|
||||
gslimit += gi.shrinkRightLimit;
|
||||
if (gi.shrinkAbsorb) {
|
||||
absorbweight += gi.weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// did we hit the limit?
|
||||
if (!grow) {
|
||||
gslimit = -gslimit; // negative for negative deltas
|
||||
}
|
||||
boolean hitLimit = (weight == 0) || (!lastPass && ((delta < 0) == (delta < gslimit)));
|
||||
boolean absorbing = hitLimit && absorbweight > 0;
|
||||
|
||||
// predivide delta by weight
|
||||
float weightedDelta = delta / weight; // not used if weight == 0
|
||||
|
||||
float weightedAbsorb = 0;
|
||||
if (hitLimit && absorbweight > 0) {
|
||||
weightedAbsorb = (delta - gslimit) / absorbweight;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
System.out.println("pass: " + p +
|
||||
", d: " + delta +
|
||||
", l: " + gslimit +
|
||||
", w: " + weight +
|
||||
", aw: " + absorbweight +
|
||||
", wd: " + weightedDelta +
|
||||
", wa: " + weightedAbsorb +
|
||||
", hit: " + (hitLimit ? "y" : "n"));
|
||||
}
|
||||
|
||||
// now allocate this based on ratio of weight to total weight
|
||||
int n = start * 2;
|
||||
for (int i = start; i < limit; i++) {
|
||||
GlyphJustificationInfo gi = info[i];
|
||||
if ((grow ? gi.growPriority : gi.shrinkPriority) == p) {
|
||||
if (i != start) { // ignore left
|
||||
float d;
|
||||
if (hitLimit) {
|
||||
// factor in sign
|
||||
d = grow ? gi.growLeftLimit : -gi.shrinkLeftLimit;
|
||||
if (absorbing) {
|
||||
// sign factored in already
|
||||
d += gi.weight * weightedAbsorb;
|
||||
}
|
||||
} else {
|
||||
// sign factored in already
|
||||
d = gi.weight * weightedDelta;
|
||||
}
|
||||
|
||||
deltas[n] += d;
|
||||
}
|
||||
n++;
|
||||
|
||||
if (i + 1 != limit) { // ignore right
|
||||
float d;
|
||||
if (hitLimit) {
|
||||
d = grow ? gi.growRightLimit : -gi.shrinkRightLimit;
|
||||
if (absorbing) {
|
||||
d += gi.weight * weightedAbsorb;
|
||||
}
|
||||
} else {
|
||||
d = gi.weight * weightedDelta;
|
||||
}
|
||||
|
||||
deltas[n] += d;
|
||||
}
|
||||
n++;
|
||||
} else {
|
||||
n += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lastPass && hitLimit && !absorbing) {
|
||||
delta -= gslimit;
|
||||
} else {
|
||||
delta = 0; // stop iteration
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
float total = 0;
|
||||
for (int i = 0; i < deltas.length; i++) {
|
||||
total += deltas[i];
|
||||
System.out.print(deltas[i] + ", ");
|
||||
if (i % 20 == 9) {
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
System.out.println("\ntotal: " + total);
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
return deltas;
|
||||
}
|
||||
}
|
2724
src/java.desktop/share/classes/java/awt/font/TextLayout.java
Normal file
2724
src/java.desktop/share/classes/java/awt/font/TextLayout.java
Normal file
File diff suppressed because it is too large
Load diff
1437
src/java.desktop/share/classes/java/awt/font/TextLine.java
Normal file
1437
src/java.desktop/share/classes/java/awt/font/TextLine.java
Normal file
File diff suppressed because it is too large
Load diff
764
src/java.desktop/share/classes/java/awt/font/TextMeasurer.java
Normal file
764
src/java.desktop/share/classes/java/awt/font/TextMeasurer.java
Normal file
|
@ -0,0 +1,764 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is
|
||||
* copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
|
||||
* of IBM. These materials are provided under terms of a License
|
||||
* Agreement between Taligent and Sun. This technology is protected
|
||||
* by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
import java.awt.Font;
|
||||
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.text.AttributedCharacterIterator.Attribute;
|
||||
import java.text.AttributedString;
|
||||
import java.text.Bidi;
|
||||
import java.text.BreakIterator;
|
||||
import java.text.CharacterIterator;
|
||||
|
||||
import java.awt.font.FontRenderContext;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import sun.font.AttributeValues;
|
||||
import sun.font.BidiUtils;
|
||||
import sun.font.TextLineComponent;
|
||||
import sun.font.TextLabelFactory;
|
||||
import sun.font.FontResolver;
|
||||
|
||||
/**
|
||||
* The {@code TextMeasurer} class provides the primitive operations
|
||||
* needed for line break: measuring up to a given advance, determining the
|
||||
* advance of a range of characters, and generating a
|
||||
* {@code TextLayout} for a range of characters. It also provides
|
||||
* methods for incremental editing of paragraphs.
|
||||
* <p>
|
||||
* A {@code TextMeasurer} object is constructed with an
|
||||
* {@link java.text.AttributedCharacterIterator AttributedCharacterIterator}
|
||||
* representing a single paragraph of text. The value returned by the
|
||||
* {@link AttributedCharacterIterator#getBeginIndex() getBeginIndex}
|
||||
* method of {@code AttributedCharacterIterator}
|
||||
* defines the absolute index of the first character. The value
|
||||
* returned by the
|
||||
* {@link AttributedCharacterIterator#getEndIndex() getEndIndex}
|
||||
* method of {@code AttributedCharacterIterator} defines the index
|
||||
* past the last character. These values define the range of indexes to
|
||||
* use in calls to the {@code TextMeasurer}. For example, calls to
|
||||
* get the advance of a range of text or the line break of a range of text
|
||||
* must use indexes between the beginning and end index values. Calls to
|
||||
* {@link #insertChar(java.text.AttributedCharacterIterator, int) insertChar}
|
||||
* and
|
||||
* {@link #deleteChar(java.text.AttributedCharacterIterator, int) deleteChar}
|
||||
* reset the {@code TextMeasurer} to use the beginning index and end
|
||||
* index of the {@code AttributedCharacterIterator} passed in those calls.
|
||||
* <p>
|
||||
* Most clients will use the more convenient {@code LineBreakMeasurer},
|
||||
* which implements the standard line break policy (placing as many words
|
||||
* as will fit on each line).
|
||||
*
|
||||
* @author John Raley
|
||||
* @see LineBreakMeasurer
|
||||
* @since 1.3
|
||||
*/
|
||||
|
||||
public final class TextMeasurer implements Cloneable {
|
||||
|
||||
// Number of lines to format to.
|
||||
private static float EST_LINES = (float) 2.1;
|
||||
|
||||
/*
|
||||
static {
|
||||
String s = System.getProperty("estLines");
|
||||
if (s != null) {
|
||||
try {
|
||||
Float f = Float.valueOf(s);
|
||||
EST_LINES = f.floatValue();
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
//System.out.println("EST_LINES="+EST_LINES);
|
||||
}
|
||||
*/
|
||||
|
||||
private FontRenderContext fFrc;
|
||||
|
||||
private int fStart;
|
||||
|
||||
// characters in source text
|
||||
private char[] fChars;
|
||||
|
||||
// Bidi for this paragraph
|
||||
private Bidi fBidi;
|
||||
|
||||
// Levels array for chars in this paragraph - needed to reorder
|
||||
// trailing counterdirectional whitespace
|
||||
private byte[] fLevels;
|
||||
|
||||
// line components in logical order
|
||||
private TextLineComponent[] fComponents;
|
||||
|
||||
// index where components begin
|
||||
private int fComponentStart;
|
||||
|
||||
// index where components end
|
||||
private int fComponentLimit;
|
||||
|
||||
private boolean haveLayoutWindow;
|
||||
|
||||
// used to find valid starting points for line components
|
||||
private BreakIterator fLineBreak = null;
|
||||
private CharArrayIterator charIter = null;
|
||||
int layoutCount = 0;
|
||||
int layoutCharCount = 0;
|
||||
|
||||
// paragraph, with resolved fonts and styles
|
||||
private StyledParagraph fParagraph;
|
||||
|
||||
// paragraph data - same across all layouts
|
||||
private boolean fIsDirectionLTR;
|
||||
private byte fBaseline;
|
||||
private float[] fBaselineOffsets;
|
||||
private float fJustifyRatio = 1;
|
||||
|
||||
/**
|
||||
* Constructs a {@code TextMeasurer} from the source text.
|
||||
* The source text should be a single entire paragraph.
|
||||
* @param text the source paragraph. Cannot be null.
|
||||
* @param frc the information about a graphics device which is needed
|
||||
* to measure the text correctly. Cannot be null.
|
||||
*/
|
||||
public TextMeasurer(AttributedCharacterIterator text, FontRenderContext frc) {
|
||||
|
||||
fFrc = frc;
|
||||
initAll(text);
|
||||
}
|
||||
|
||||
protected Object clone() {
|
||||
TextMeasurer other;
|
||||
try {
|
||||
other = (TextMeasurer) super.clone();
|
||||
}
|
||||
catch(CloneNotSupportedException e) {
|
||||
throw new Error();
|
||||
}
|
||||
if (fComponents != null) {
|
||||
other.fComponents = fComponents.clone();
|
||||
}
|
||||
return other;
|
||||
}
|
||||
|
||||
private void invalidateComponents() {
|
||||
fComponentStart = fComponentLimit = fChars.length;
|
||||
fComponents = null;
|
||||
haveLayoutWindow = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize state, including fChars array, direction, and
|
||||
* fBidi.
|
||||
*/
|
||||
private void initAll(AttributedCharacterIterator text) {
|
||||
|
||||
fStart = text.getBeginIndex();
|
||||
|
||||
// extract chars
|
||||
fChars = new char[text.getEndIndex() - fStart];
|
||||
|
||||
int n = 0;
|
||||
for (char c = text.first();
|
||||
c != CharacterIterator.DONE;
|
||||
c = text.next())
|
||||
{
|
||||
fChars[n++] = c;
|
||||
}
|
||||
|
||||
text.first();
|
||||
|
||||
fBidi = new Bidi(text);
|
||||
if (fBidi.isLeftToRight()) {
|
||||
fBidi = null;
|
||||
}
|
||||
|
||||
text.first();
|
||||
Map<? extends Attribute, ?> paragraphAttrs = text.getAttributes();
|
||||
NumericShaper shaper = AttributeValues.getNumericShaping(paragraphAttrs);
|
||||
if (shaper != null) {
|
||||
shaper.shape(fChars, 0, fChars.length);
|
||||
}
|
||||
|
||||
fParagraph = new StyledParagraph(text, fChars);
|
||||
|
||||
// set paragraph attributes
|
||||
{
|
||||
// If there's an embedded graphic at the start of the
|
||||
// paragraph, look for the first non-graphic character
|
||||
// and use it and its font to initialize the paragraph.
|
||||
// If not, use the first graphic to initialize.
|
||||
fJustifyRatio = AttributeValues.getJustification(paragraphAttrs);
|
||||
|
||||
boolean haveFont = TextLine.advanceToFirstFont(text);
|
||||
|
||||
if (haveFont) {
|
||||
Font defaultFont = TextLine.getFontAtCurrentPos(text);
|
||||
int charsStart = text.getIndex() - text.getBeginIndex();
|
||||
LineMetrics lm = defaultFont.getLineMetrics(fChars, charsStart, charsStart+1, fFrc);
|
||||
fBaseline = (byte) lm.getBaselineIndex();
|
||||
fBaselineOffsets = lm.getBaselineOffsets();
|
||||
}
|
||||
else {
|
||||
// hmmm what to do here? Just try to supply reasonable
|
||||
// values I guess.
|
||||
|
||||
GraphicAttribute graphic = (GraphicAttribute)
|
||||
paragraphAttrs.get(TextAttribute.CHAR_REPLACEMENT);
|
||||
fBaseline = TextLayout.getBaselineFromGraphic(graphic);
|
||||
Hashtable<Attribute, ?> fmap = new Hashtable<>(5, (float)0.9);
|
||||
Font dummyFont = new Font(fmap);
|
||||
LineMetrics lm = dummyFont.getLineMetrics(" ", 0, 1, fFrc);
|
||||
fBaselineOffsets = lm.getBaselineOffsets();
|
||||
}
|
||||
fBaselineOffsets = TextLine.getNormalizedOffsets(fBaselineOffsets, fBaseline);
|
||||
}
|
||||
|
||||
invalidateComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate components for the paragraph. fChars, fBidi should have been
|
||||
* initialized already.
|
||||
*/
|
||||
private void generateComponents(int startingAt, int endingAt) {
|
||||
|
||||
if (collectStats) {
|
||||
formattedChars += (endingAt-startingAt);
|
||||
}
|
||||
int layoutFlags = 0; // no extra info yet, bidi determines run and line direction
|
||||
TextLabelFactory factory = new TextLabelFactory(fFrc, fChars, fBidi, layoutFlags);
|
||||
|
||||
int[] charsLtoV = null;
|
||||
|
||||
if (fBidi != null) {
|
||||
fLevels = BidiUtils.getLevels(fBidi);
|
||||
int[] charsVtoL = BidiUtils.createVisualToLogicalMap(fLevels);
|
||||
charsLtoV = BidiUtils.createInverseMap(charsVtoL);
|
||||
fIsDirectionLTR = fBidi.baseIsLeftToRight();
|
||||
}
|
||||
else {
|
||||
fLevels = null;
|
||||
fIsDirectionLTR = true;
|
||||
}
|
||||
|
||||
try {
|
||||
fComponents = TextLine.getComponents(
|
||||
fParagraph, fChars, startingAt, endingAt, charsLtoV, fLevels, factory);
|
||||
}
|
||||
catch(IllegalArgumentException e) {
|
||||
System.out.println("startingAt="+startingAt+"; endingAt="+endingAt);
|
||||
System.out.println("fComponentLimit="+fComponentLimit);
|
||||
throw e;
|
||||
}
|
||||
|
||||
fComponentStart = startingAt;
|
||||
fComponentLimit = endingAt;
|
||||
//debugFormatCount += (endingAt-startingAt);
|
||||
}
|
||||
|
||||
private int calcLineBreak(final int pos, final float maxAdvance) {
|
||||
|
||||
// either of these statements removes the bug:
|
||||
//generateComponents(0, fChars.length);
|
||||
//generateComponents(pos, fChars.length);
|
||||
|
||||
int startPos = pos;
|
||||
float width = maxAdvance;
|
||||
|
||||
int tlcIndex;
|
||||
int tlcStart = fComponentStart;
|
||||
|
||||
for (tlcIndex = 0; tlcIndex < fComponents.length; tlcIndex++) {
|
||||
int gaLimit = tlcStart + fComponents[tlcIndex].getNumCharacters();
|
||||
if (gaLimit > startPos) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
tlcStart = gaLimit;
|
||||
}
|
||||
}
|
||||
|
||||
// tlcStart is now the start of the tlc at tlcIndex
|
||||
|
||||
for (; tlcIndex < fComponents.length; tlcIndex++) {
|
||||
|
||||
TextLineComponent tlc = fComponents[tlcIndex];
|
||||
int numCharsInGa = tlc.getNumCharacters();
|
||||
|
||||
int lineBreak = tlc.getLineBreakIndex(startPos - tlcStart, width);
|
||||
if (lineBreak == numCharsInGa && tlcIndex < fComponents.length) {
|
||||
width -= tlc.getAdvanceBetween(startPos - tlcStart, lineBreak);
|
||||
tlcStart += numCharsInGa;
|
||||
startPos = tlcStart;
|
||||
}
|
||||
else {
|
||||
return tlcStart + lineBreak;
|
||||
}
|
||||
}
|
||||
|
||||
if (fComponentLimit < fChars.length) {
|
||||
// format more text and try again
|
||||
//if (haveLayoutWindow) {
|
||||
// outOfWindow++;
|
||||
//}
|
||||
|
||||
generateComponents(pos, fChars.length);
|
||||
return calcLineBreak(pos, maxAdvance);
|
||||
}
|
||||
|
||||
return fChars.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* According to the Unicode Bidirectional Behavior specification
|
||||
* (Unicode Standard 2.0, section 3.11), whitespace at the ends
|
||||
* of lines which would naturally flow against the base direction
|
||||
* must be made to flow with the line direction, and moved to the
|
||||
* end of the line. This method returns the start of the sequence
|
||||
* of trailing whitespace characters to move to the end of a
|
||||
* line taken from the given range.
|
||||
*/
|
||||
private int trailingCdWhitespaceStart(int startPos, int limitPos) {
|
||||
|
||||
if (fLevels != null) {
|
||||
// Back up over counterdirectional whitespace
|
||||
final byte baseLevel = (byte) (fIsDirectionLTR? 0 : 1);
|
||||
for (int cdWsStart = limitPos; --cdWsStart >= startPos;) {
|
||||
if ((fLevels[cdWsStart] % 2) == baseLevel ||
|
||||
Character.getDirectionality(fChars[cdWsStart]) != Character.DIRECTIONALITY_WHITESPACE) {
|
||||
return ++cdWsStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return startPos;
|
||||
}
|
||||
|
||||
private TextLineComponent[] makeComponentsOnRange(int startPos,
|
||||
int limitPos) {
|
||||
|
||||
// sigh I really hate to do this here since it's part of the
|
||||
// bidi algorithm.
|
||||
// cdWsStart is the start of the trailing counterdirectional
|
||||
// whitespace
|
||||
final int cdWsStart = trailingCdWhitespaceStart(startPos, limitPos);
|
||||
|
||||
int tlcIndex;
|
||||
int tlcStart = fComponentStart;
|
||||
|
||||
for (tlcIndex = 0; tlcIndex < fComponents.length; tlcIndex++) {
|
||||
int gaLimit = tlcStart + fComponents[tlcIndex].getNumCharacters();
|
||||
if (gaLimit > startPos) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
tlcStart = gaLimit;
|
||||
}
|
||||
}
|
||||
|
||||
// tlcStart is now the start of the tlc at tlcIndex
|
||||
|
||||
int componentCount;
|
||||
{
|
||||
boolean split = false;
|
||||
int compStart = tlcStart;
|
||||
int lim=tlcIndex;
|
||||
for (boolean cont=true; cont; lim++) {
|
||||
int gaLimit = compStart + fComponents[lim].getNumCharacters();
|
||||
if (cdWsStart > Math.max(compStart, startPos)
|
||||
&& cdWsStart < Math.min(gaLimit, limitPos)) {
|
||||
split = true;
|
||||
}
|
||||
if (gaLimit >= limitPos) {
|
||||
cont=false;
|
||||
}
|
||||
else {
|
||||
compStart = gaLimit;
|
||||
}
|
||||
}
|
||||
componentCount = lim-tlcIndex;
|
||||
if (split) {
|
||||
componentCount++;
|
||||
}
|
||||
}
|
||||
|
||||
TextLineComponent[] components = new TextLineComponent[componentCount];
|
||||
int newCompIndex = 0;
|
||||
int linePos = startPos;
|
||||
|
||||
int breakPt = cdWsStart;
|
||||
|
||||
int subsetFlag;
|
||||
if (breakPt == startPos) {
|
||||
subsetFlag = fIsDirectionLTR? TextLineComponent.LEFT_TO_RIGHT :
|
||||
TextLineComponent.RIGHT_TO_LEFT;
|
||||
breakPt = limitPos;
|
||||
}
|
||||
else {
|
||||
subsetFlag = TextLineComponent.UNCHANGED;
|
||||
}
|
||||
|
||||
while (linePos < limitPos) {
|
||||
|
||||
int compLength = fComponents[tlcIndex].getNumCharacters();
|
||||
int tlcLimit = tlcStart + compLength;
|
||||
|
||||
int start = Math.max(linePos, tlcStart);
|
||||
int limit = Math.min(breakPt, tlcLimit);
|
||||
|
||||
components[newCompIndex++] = fComponents[tlcIndex].getSubset(
|
||||
start-tlcStart,
|
||||
limit-tlcStart,
|
||||
subsetFlag);
|
||||
linePos += (limit-start);
|
||||
if (linePos == breakPt) {
|
||||
breakPt = limitPos;
|
||||
subsetFlag = fIsDirectionLTR? TextLineComponent.LEFT_TO_RIGHT :
|
||||
TextLineComponent.RIGHT_TO_LEFT;
|
||||
}
|
||||
if (linePos == tlcLimit) {
|
||||
tlcIndex++;
|
||||
tlcStart = tlcLimit;
|
||||
}
|
||||
}
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
private TextLine makeTextLineOnRange(int startPos, int limitPos) {
|
||||
|
||||
int[] charsLtoV = null;
|
||||
byte[] charLevels = null;
|
||||
|
||||
if (fBidi != null) {
|
||||
Bidi lineBidi = fBidi.createLineBidi(startPos, limitPos);
|
||||
charLevels = BidiUtils.getLevels(lineBidi);
|
||||
int[] charsVtoL = BidiUtils.createVisualToLogicalMap(charLevels);
|
||||
charsLtoV = BidiUtils.createInverseMap(charsVtoL);
|
||||
}
|
||||
|
||||
TextLineComponent[] components = makeComponentsOnRange(startPos, limitPos);
|
||||
|
||||
return new TextLine(fFrc,
|
||||
components,
|
||||
fBaselineOffsets,
|
||||
fChars,
|
||||
startPos,
|
||||
limitPos,
|
||||
charsLtoV,
|
||||
charLevels,
|
||||
fIsDirectionLTR);
|
||||
|
||||
}
|
||||
|
||||
private void ensureComponents(int start, int limit) {
|
||||
|
||||
if (start < fComponentStart || limit > fComponentLimit) {
|
||||
generateComponents(start, limit);
|
||||
}
|
||||
}
|
||||
|
||||
private void makeLayoutWindow(int localStart) {
|
||||
|
||||
int compStart = localStart;
|
||||
int compLimit = fChars.length;
|
||||
|
||||
// If we've already gone past the layout window, format to end of paragraph
|
||||
if (layoutCount > 0 && !haveLayoutWindow) {
|
||||
float avgLineLength = Math.max(layoutCharCount / layoutCount, 1);
|
||||
compLimit = Math.min(localStart + (int)(avgLineLength*EST_LINES), fChars.length);
|
||||
}
|
||||
|
||||
if (localStart > 0 || compLimit < fChars.length) {
|
||||
if (charIter == null) {
|
||||
charIter = new CharArrayIterator(fChars);
|
||||
}
|
||||
else {
|
||||
charIter.reset(fChars);
|
||||
}
|
||||
if (fLineBreak == null) {
|
||||
fLineBreak = BreakIterator.getLineInstance();
|
||||
}
|
||||
fLineBreak.setText(charIter);
|
||||
if (localStart > 0) {
|
||||
if (!fLineBreak.isBoundary(localStart)) {
|
||||
compStart = fLineBreak.preceding(localStart);
|
||||
}
|
||||
}
|
||||
if (compLimit < fChars.length) {
|
||||
if (!fLineBreak.isBoundary(compLimit)) {
|
||||
compLimit = fLineBreak.following(compLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ensureComponents(compStart, compLimit);
|
||||
haveLayoutWindow = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first character which will not fit on
|
||||
* on a line beginning at {@code start} and possible
|
||||
* measuring up to {@code maxAdvance} in graphical width.
|
||||
*
|
||||
* @param start the character index at which to start measuring.
|
||||
* {@code start} is an absolute index, not relative to the
|
||||
* start of the paragraph
|
||||
* @param maxAdvance the graphical width in which the line must fit
|
||||
* @return the index after the last character that will fit
|
||||
* on a line beginning at {@code start}, which is not longer
|
||||
* than {@code maxAdvance} in graphical width
|
||||
* @throws IllegalArgumentException if {@code start} is
|
||||
* less than the beginning of the paragraph.
|
||||
*/
|
||||
public int getLineBreakIndex(int start, float maxAdvance) {
|
||||
|
||||
int localStart = start - fStart;
|
||||
|
||||
if (!haveLayoutWindow ||
|
||||
localStart < fComponentStart ||
|
||||
localStart >= fComponentLimit) {
|
||||
makeLayoutWindow(localStart);
|
||||
}
|
||||
|
||||
return calcLineBreak(localStart, maxAdvance) + fStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the graphical width of a line beginning at {@code start}
|
||||
* and including characters up to {@code limit}.
|
||||
* {@code start} and {@code limit} are absolute indices,
|
||||
* not relative to the start of the paragraph.
|
||||
*
|
||||
* @param start the character index at which to start measuring
|
||||
* @param limit the character index at which to stop measuring
|
||||
* @return the graphical width of a line beginning at {@code start}
|
||||
* and including characters up to {@code limit}
|
||||
* @throws IndexOutOfBoundsException if {@code limit} is less
|
||||
* than {@code start}
|
||||
* @throws IllegalArgumentException if {@code start} or
|
||||
* {@code limit} is not between the beginning of
|
||||
* the paragraph and the end of the paragraph.
|
||||
*/
|
||||
public float getAdvanceBetween(int start, int limit) {
|
||||
|
||||
int localStart = start - fStart;
|
||||
int localLimit = limit - fStart;
|
||||
|
||||
ensureComponents(localStart, localLimit);
|
||||
TextLine line = makeTextLineOnRange(localStart, localLimit);
|
||||
return line.getMetrics().advance;
|
||||
// could cache line in case getLayout is called with same start, limit
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code TextLayout} on the given character range.
|
||||
*
|
||||
* @param start the index of the first character
|
||||
* @param limit the index after the last character. Must be greater
|
||||
* than {@code start}
|
||||
* @return a {@code TextLayout} for the characters beginning at
|
||||
* {@code start} up to (but not including) {@code limit}
|
||||
* @throws IndexOutOfBoundsException if {@code limit} is less
|
||||
* than {@code start}
|
||||
* @throws IllegalArgumentException if {@code start} or
|
||||
* {@code limit} is not between the beginning of
|
||||
* the paragraph and the end of the paragraph.
|
||||
*/
|
||||
public TextLayout getLayout(int start, int limit) {
|
||||
|
||||
int localStart = start - fStart;
|
||||
int localLimit = limit - fStart;
|
||||
|
||||
ensureComponents(localStart, localLimit);
|
||||
TextLine textLine = makeTextLineOnRange(localStart, localLimit);
|
||||
|
||||
if (localLimit < fChars.length) {
|
||||
layoutCharCount += limit-start;
|
||||
layoutCount++;
|
||||
}
|
||||
|
||||
return new TextLayout(textLine,
|
||||
fBaseline,
|
||||
fBaselineOffsets,
|
||||
fJustifyRatio);
|
||||
}
|
||||
|
||||
private int formattedChars = 0;
|
||||
private static boolean wantStats = false;/*"true".equals(System.getProperty("collectStats"));*/
|
||||
private boolean collectStats = false;
|
||||
|
||||
private void printStats() {
|
||||
System.out.println("formattedChars: " + formattedChars);
|
||||
//formattedChars = 0;
|
||||
collectStats = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the {@code TextMeasurer} after a single character has
|
||||
* been inserted
|
||||
* into the paragraph currently represented by this
|
||||
* {@code TextMeasurer}. After this call, this
|
||||
* {@code TextMeasurer} is equivalent to a new
|
||||
* {@code TextMeasurer} created from the text; however, it will
|
||||
* usually be more efficient to update an existing
|
||||
* {@code TextMeasurer} than to create a new one from scratch.
|
||||
*
|
||||
* @param newParagraph the text of the paragraph after performing
|
||||
* the insertion. Cannot be null.
|
||||
* @param insertPos the position in the text where the character was
|
||||
* inserted. Must not be less than the start of
|
||||
* {@code newParagraph}, and must be less than the end of
|
||||
* {@code newParagraph}.
|
||||
* @throws IndexOutOfBoundsException if {@code insertPos} is less
|
||||
* than the start of {@code newParagraph} or greater than
|
||||
* or equal to the end of {@code newParagraph}
|
||||
* @throws NullPointerException if {@code newParagraph} is
|
||||
* {@code null}
|
||||
*/
|
||||
public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) {
|
||||
|
||||
if (collectStats) {
|
||||
printStats();
|
||||
}
|
||||
if (wantStats) {
|
||||
collectStats = true;
|
||||
}
|
||||
|
||||
fStart = newParagraph.getBeginIndex();
|
||||
int end = newParagraph.getEndIndex();
|
||||
if (end - fStart != fChars.length+1) {
|
||||
initAll(newParagraph);
|
||||
}
|
||||
|
||||
char[] newChars = new char[end-fStart];
|
||||
int newCharIndex = insertPos - fStart;
|
||||
System.arraycopy(fChars, 0, newChars, 0, newCharIndex);
|
||||
|
||||
char newChar = newParagraph.setIndex(insertPos);
|
||||
newChars[newCharIndex] = newChar;
|
||||
System.arraycopy(fChars,
|
||||
newCharIndex,
|
||||
newChars,
|
||||
newCharIndex+1,
|
||||
end-insertPos-1);
|
||||
fChars = newChars;
|
||||
|
||||
if (fBidi != null || Bidi.requiresBidi(newChars, newCharIndex, newCharIndex + 1) ||
|
||||
newParagraph.getAttribute(TextAttribute.BIDI_EMBEDDING) != null) {
|
||||
|
||||
fBidi = new Bidi(newParagraph);
|
||||
if (fBidi.isLeftToRight()) {
|
||||
fBidi = null;
|
||||
}
|
||||
}
|
||||
|
||||
fParagraph = StyledParagraph.insertChar(newParagraph,
|
||||
fChars,
|
||||
insertPos,
|
||||
fParagraph);
|
||||
invalidateComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the {@code TextMeasurer} after a single character has
|
||||
* been deleted
|
||||
* from the paragraph currently represented by this
|
||||
* {@code TextMeasurer}. After this call, this
|
||||
* {@code TextMeasurer} is equivalent to a new {@code TextMeasurer}
|
||||
* created from the text; however, it will usually be more efficient
|
||||
* to update an existing {@code TextMeasurer} than to create a new one
|
||||
* from scratch.
|
||||
*
|
||||
* @param newParagraph the text of the paragraph after performing
|
||||
* the deletion. Cannot be null.
|
||||
* @param deletePos the position in the text where the character was removed.
|
||||
* Must not be less than
|
||||
* the start of {@code newParagraph}, and must not be greater than the
|
||||
* end of {@code newParagraph}.
|
||||
* @throws IndexOutOfBoundsException if {@code deletePos} is
|
||||
* less than the start of {@code newParagraph} or greater
|
||||
* than the end of {@code newParagraph}
|
||||
* @throws NullPointerException if {@code newParagraph} is
|
||||
* {@code null}
|
||||
*/
|
||||
public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) {
|
||||
|
||||
fStart = newParagraph.getBeginIndex();
|
||||
int end = newParagraph.getEndIndex();
|
||||
if (end - fStart != fChars.length-1) {
|
||||
initAll(newParagraph);
|
||||
}
|
||||
|
||||
char[] newChars = new char[end-fStart];
|
||||
int changedIndex = deletePos-fStart;
|
||||
|
||||
System.arraycopy(fChars, 0, newChars, 0, deletePos-fStart);
|
||||
System.arraycopy(fChars, changedIndex+1, newChars, changedIndex, end-deletePos);
|
||||
fChars = newChars;
|
||||
|
||||
if (fBidi != null) {
|
||||
fBidi = new Bidi(newParagraph);
|
||||
if (fBidi.isLeftToRight()) {
|
||||
fBidi = null;
|
||||
}
|
||||
}
|
||||
|
||||
fParagraph = StyledParagraph.deleteChar(newParagraph,
|
||||
fChars,
|
||||
deletePos,
|
||||
fParagraph);
|
||||
invalidateComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: This method is only for LineBreakMeasurer's use. It is package-
|
||||
* private because it returns internal data.
|
||||
*/
|
||||
char[] getChars() {
|
||||
|
||||
return fChars;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
|
||||
* (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
|
||||
*
|
||||
* The original version of this source code and documentation is
|
||||
* copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
|
||||
* of IBM. These materials are provided under terms of a License
|
||||
* Agreement between Taligent and Sun. This technology is protected
|
||||
* by multiple US and International patents.
|
||||
*
|
||||
* This notice and attribution to Taligent may not be removed.
|
||||
* Taligent is a registered trademark of Taligent, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
package java.awt.font;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.io.Serializable;
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
/**
|
||||
* The {@code TransformAttribute} class provides an immutable
|
||||
* wrapper for a transform so that it is safe to use as an attribute.
|
||||
*/
|
||||
public final class TransformAttribute implements Serializable {
|
||||
|
||||
/**
|
||||
* The {@code AffineTransform} for this
|
||||
* {@code TransformAttribute}, or {@code null}
|
||||
* if {@code AffineTransform} is the identity transform.
|
||||
*/
|
||||
private AffineTransform transform;
|
||||
|
||||
/**
|
||||
* Wraps the specified transform. The transform is cloned and a
|
||||
* reference to the clone is kept. The original transform is unchanged.
|
||||
* If null is passed as the argument, this constructor behaves as though
|
||||
* it were the identity transform. (Note that it is preferable to use
|
||||
* {@link #IDENTITY} in this case.)
|
||||
* @param transform the specified {@link AffineTransform} to be wrapped,
|
||||
* or null.
|
||||
*/
|
||||
public TransformAttribute(AffineTransform transform) {
|
||||
if (transform != null && !transform.isIdentity()) {
|
||||
this.transform = new AffineTransform(transform);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the wrapped transform.
|
||||
* @return an {@code AffineTransform} that is a copy of the wrapped
|
||||
* transform of this {@code TransformAttribute}.
|
||||
*/
|
||||
public AffineTransform getTransform() {
|
||||
AffineTransform at = transform;
|
||||
return (at == null) ? new AffineTransform() : new AffineTransform(at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the wrapped transform is
|
||||
* an identity transform.
|
||||
* @return {@code true} if the wrapped transform is
|
||||
* an identity transform; {@code false} otherwise.
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean isIdentity() {
|
||||
return transform == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@code TransformAttribute} representing the identity transform.
|
||||
* @since 1.6
|
||||
*/
|
||||
public static final TransformAttribute IDENTITY = new TransformAttribute(null);
|
||||
|
||||
private void writeObject(java.io.ObjectOutputStream s)
|
||||
throws java.lang.ClassNotFoundException,
|
||||
java.io.IOException
|
||||
{
|
||||
// sigh -- 1.3 expects transform is never null, so we need to always write one out
|
||||
if (this.transform == null) {
|
||||
this.transform = new AffineTransform();
|
||||
}
|
||||
s.defaultWriteObject();
|
||||
}
|
||||
|
||||
/*
|
||||
* @since 1.6
|
||||
*/
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
if (transform == null || transform.isIdentity()) {
|
||||
return IDENTITY;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// Added for serial backwards compatibility (4348425)
|
||||
static final long serialVersionUID = 3356247357827709530L;
|
||||
|
||||
/**
|
||||
* @since 1.6
|
||||
*/
|
||||
public int hashCode() {
|
||||
return transform == null ? 0 : transform.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if rhs is a {@code TransformAttribute}
|
||||
* whose transform is equal to this {@code TransformAttribute}'s
|
||||
* transform.
|
||||
* @param rhs the object to compare to
|
||||
* @return {@code true} if the argument is a {@code TransformAttribute}
|
||||
* whose transform is equal to this {@code TransformAttribute}'s
|
||||
* transform.
|
||||
* @since 1.6
|
||||
*/
|
||||
public boolean equals(Object rhs) {
|
||||
if (rhs != null) {
|
||||
try {
|
||||
TransformAttribute that = (TransformAttribute)rhs;
|
||||
if (transform == null) {
|
||||
return that.transform == null;
|
||||
}
|
||||
return transform.equals(that.transform);
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides classes and interface relating to fonts. It contains support for
|
||||
* representing Type 1, Type 1 Multiple Master fonts, OpenType fonts, and
|
||||
* TrueType fonts.
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
package java.awt.font;
|
Loading…
Add table
Add a link
Reference in a new issue