/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/**
* Standard implementation of GlyphVector used by Font, GlyphList, and
* SunGraphics2D.
*
* The main issues involve the semantics of the various transforms
* (font, glyph, device) and their effect on rendering and metrics.
*
* Very, very unfortunately, the translation component of the font
* transform affects where the text gets rendered. It offsets the
* rendering origin. None of the other metrics of the glyphvector
* are affected, making them inconsistent with the rendering behavior.
* I think the translation component of the font would be better
* interpreted as the translation component of a per-glyph transform,
* but I don't know if this is possible to change.
*
* After the font transform is applied, the glyph transform is
* applied. This makes glyph transforms relative to font transforms,
* if the font transform changes, the glyph transform will have the
* same (relative) effect on the outline of the glyph. The outline
* and logical bounds are passed through the glyph transform before
* being returned. The glyph metrics ignore the glyph transform, but
* provide the outline bounds and the advance vector of the glyph (the
* latter will be rotated if the font is rotated). The default layout
* places each glyph at the end of the advance vector of the previous
* glyph, and since the glyph transform translates the advance vector,
* this means a glyph transform affects the positions of all
* subsequent glyphs if defaultLayout is called after setting a glyph
* transform. In the glyph info array, the bounds are the outline
* bounds including the glyph transform, and the positions are as
* computed, and the advances are the deltas between the positions.
*
* (There's a bug in the logical bounds of a rotated glyph for
* composite fonts, it's not to spec (in 1.4.0, 1.4.1, 1.4.2). The
* problem is that the rotated composite doesn't handle the multiple
* ascents and descents properly in both x and y. You end up with
* a rotated advance vector but an unrotated ascent and descent.)
*
* Finally, the whole thing is transformed by the device transform to
* position it on the page.
*
* Another bug: The glyph outline seems to ignore fractional point
* size information, but the images (and advances) don't ignore it.
*
* Small fonts drawn at large magnification have odd advances when
* fractional metrics is off-- that's because the advances depend on
* the frc. When the frc is scaled appropriately, the advances are
* fine. FM or a large frc (high numbers) make the advances right.
*
* The buffer aa flag doesn't affect rendering, the glyph vector
* renders as AA if aa is set in its frc, and as non-aa if aa is not
* set in its frc.
*
* font rotation, baseline, vertical etc.
*
* Font rotation and baseline Line metrics should be measured along a
* unit vector pi/4 cc from the baseline vector. For 'horizontal'
* fonts the baseline vector is the x vector passed through the font
* transform (ignoring translation), for 'vertical' it is the y
* vector. This definition makes ascent, descent, etc independent of
* shear, so shearing can be used to simulate italic. This means no
* fonts have 'negative ascents' or 'zero ascents' etc.
*
* Having a coordinate system with orthogonal axes where one is
* parallel to the baseline means we could use rectangles and interpret
* them in terms of this coordinate system. Unfortunately there
* is support for rotated fonts in the jdk already so maintaining
* the semantics of existing code (getlogical bounds, etc) might
* be difficult.
*
* A font transform transforms both the baseline and all the glyphs
* in the font, so it does not rotate the glyph w.r.t the baseline.
* If you do want to rotate individual glyphs, you need to apply a
* glyph transform. If performDefaultLayout is called after this,
* the transformed glyph advances will affect the glyph positions.
*
* useful additions
* - select vertical metrics - glyphs are rotated pi/4 cc and vertical
* metrics are used to align them to the baseline.
* - define baseline for font (glyph rotation not linked to baseline)
* - define extra space (delta between each glyph along baseline)
* - define offset (delta from 'true' baseline, impacts ascent and
* descent as these are still computed from true basline and pinned
* to zero, used in superscript).
*/
// transforms information
// !!! can we get rid of any of this extra stuff?
/////////////////////////////
// Constructors and Factory methods
/////////////////////////////
}
}
}
if (font.hasLayoutAttributes()) {
return values.getTracking();
}
return 0;
}
// used by GlyphLayout to construct a glyphvector
// this code should go into layout
if (track != 0) {
if (font.isTransformed()) {
}
// how do we know its a base glyph
// for now, it is if the natural advance of the glyph is non-zero
if (inc != 0) {
float delta = 0;
}
}
}
}
}
}
this.charIndices = indices;
initFontData();
}
c != CharacterIterator.DONE;
}
}
// !!! find callers of this
// should be able to fully init from raw data, e.g. charmap, flags too.
this.flags = UNINITIALIZED_FLAGS;
initFontData();
this.userGlyphs = glyphs;
}
/* This is called from the rendering loop. FontInfo is supplied
* because a GV caches a strike and glyph images suitable for its FRC.
* LCD text isn't currently supported on all surfaces, in which case
* standard AA must be used. This is most likely to occur when LCD text
* is requested and the surface is some non-standard type or hardward
* surface for which there are no accelerated loops.
* We can detect this as being AA=="ON" in the FontInfo and AA!="ON"
* and AA!="GASP" in the FRC - since this only occurs for LCD text we don't
* need to check any more precisely what value is in the FRC.
*/
if (aaHint != VALUE_TEXT_ANTIALIAS_ON &&
/* We need to create a new GV with AA==ON for rendering */
}
}
if (gv instanceof StandardGlyphVector) {
return (StandardGlyphVector)gv;
}
}
/////////////////////////////
// GlyphVector API
/////////////////////////////
return this.font;
}
return this.frc;
}
public void performDefaultLayout() {
}
}
public int getNumGlyphs() {
}
return userGlyphs[glyphIndex];
}
if (count < 0) {
}
if (start < 0) {
}
}
}
// if arraycopy were faster, we wouldn't code this
for (int i = 0; i < count; ++i) {
}
return result;
}
}
if (charIndices == null) {
}
return ix;
}
return charIndices[ix];
}
}
}
if (charIndices == null) {
i < count; ++i, --n) {
result[i] = n;
}
} else {
result[i] = n;
}
}
} else {
for (int i = 0; i < count; ++i) {
}
}
return result;
}
// !!! not cached, assume TextLayout will cache if necessary
// !!! reexamine for per-glyph-transforms
// !!! revisit for text-on-a-path, vertical
setFRCTX();
// horiz only for now...
minX = 0;
maxX = 0;
}
}
// !!! not cached, assume TextLayout will cache if necessary
} else {
}
}
}
}
return result;
}
// !!! not cached, assume TextLayout will cache if necessary
// !!! fontStrike needs a method for this
}
}
}
// relative to gv origin
}
// relative to gv origin offset by x, y
}
ix *= 2;
}
}
}
}
return null; // spec'd as returning null
}
}
return;
}
gti = new GlyphTransformInfo(this);
}
}
}
public int getLayoutFlags() {
if (flags == UNINITIALIZED_FLAGS) {
flags = 0;
boolean ltr = true;
boolean rtl = true;
int cx = charIndices[i];
}
}
}
return flags;
}
if (count < 0) {
}
if (start < 0) {
}
}
}
}
}
setFRCTX();
// !!! ought to return a rectangle2d for simple cases, though the following works for all
// get the position, the tx offset, and the x,y advance and x,y adl. The
// shape is the box formed by adv (width) and adl (height) offset by
// the position plus the tx offset minus the ascent.
}
return result;
}
}
}
}
return result;
}
}
}
vb,
return gm;
}
}
// currently we don't have enough information to do this right. should
// sun/font/ExtendedTextSourceLabel assigns one of three infos
// based on whether the char is kanji, space, or other.
return null;
}
if (this == rhs) {
return true;
}
return false;
}
try {
return false;
}
return false;
}
}
return false;
}
return false;
}
} else {
}
}
return false;
}
}
}
} else {
}
}
catch (ClassCastException e) {
// assume they are different simply by virtue of the class difference
return false;
}
}
/**
* As a concrete subclass of Object that implements equality, this must
* implement hashCode.
*/
public int hashCode() {
}
/**
* Since we implement equality comparisons for GlyphVector, we implement
* the inherited Object.equals(Object) as well. GlyphVector should do
* this, and define two glyphvectors as not equal if the classes differ.
*/
try {
}
catch (ClassCastException e) {
return false;
}
}
/**
* Sometimes I wish java had covariant return types...
*/
return (StandardGlyphVector)clone();
}
/**
* As a concrete subclass of GlyphVector, this must implement clone.
*/
// positions, gti are mutable so we have to clone them
// font2d can be shared
// fsref is a cache and can be shared
try {
}
}
return result;
}
catch (CloneNotSupportedException e) {
}
return this;
}
//////////////////////
// StandardGlyphVector new public methods
/////////////////////
/*
* Set a multiple glyph positions at one time. GlyphVector only
* provides API to set a single glyph at a time.
*/
if (count < 0) {
}
positions[i] = srcPositions[p];
}
clearCaches();
}
/**
* Set all the glyph positions, including the 'after last glyph' position.
* The srcPositions array must be of length (numGlyphs + 1) * 2.
*/
}
clearCaches();
}
/**
* This is a convenience overload that gets all the glyph positions, which
* is what you usually want to do if you're getting more than one.
* !!! should I bother taking result parameter?
*/
}
/**
* Get transform information for the requested range of glyphs.
* If no glyphs have a transform, return null.
* If a glyph has no transform (or is the identity transform) its entry in the result array will be null.
* If the passed-in result is null an array will be allocated for the caller.
* Each transform instance in the result array will unique, and independent of the GlyphVector's transform.
*/
}
return null;
}
}
}
return result;
}
/**
* Convenience overload for getGlyphTransforms(int, int, AffineTransform[], int);
*/
}
/**
* Set a number of glyph transforms.
* Original transforms are unchanged. The array may contain nulls, and also may
* contain multiple references to the same transform instance.
*/
public void setGlyphTransforms(AffineTransform[] srcTransforms, int srcStart, int start, int count) {
}
}
/**
* Convenience overload of setGlyphTransforms(AffineTransform[], int, int, int).
*/
}
/**
* For each glyph return posx, posy, advx, advy, visx, visy, visw, vish.
*/
public float[] getGlyphInfo() {
setFRCTX();
float x = positions[i*2];
result[n] = x;
result[n+1] = y;
GlyphStrike s = getGlyphStrike(i);
}
return result;
}
/**
* !!! not used currently, but might be by getPixelbounds?
*/
}
// it is a total pain that you have to copy the transform.
try {
}
catch (NoninvertibleTransformException e) {
throw new IllegalArgumentException("must be able to invert frc transform");
}
}
//////////////////////
// StandardGlyphVector package private methods
/////////////////////
// gti always uses positions because the gtx might have translation. We also
// need positions if the rendering dtx is different from the frctx.
}
// used by glyphList to get strong refs to font strikes for duration of rendering call
// if devTX matches current devTX, we're ready to go
// if we don't have multiple transforms, we're already ok
// !!! I'm not sure fontInfo works so well for glyphvector, since we have to be able to handle
// the multiple-strikes case
/*
* GlyphList calls this to set up its images data. First it calls needsPositions,
* passing the devTX, to see if it should provide us a positions array to fill.
* It only doesn't need them if we're a simple glyph vector whose frctx matches the
* devtx.
* Then it calls setupGlyphImages. If we need positions, we make sure we have our
* default positions based on the frctx first. Then we set the devTX, and use
* strikes based on it to generate the images. Finally, we fill in the positions
* array.
* If we have transforms, we delegate to gti. It depends on our having first
* initialized the positions and devTX.
*/
initPositions(); // FIRST ensure we have positions based on our frctx
}
if (dtx.isIdentity()) {
} else {
}
}
return gs;
}
//////////////////////
// StandardGlyphVector private methods
/////////////////////
// We keep translation in our frctx since getPixelBounds uses it. But
// GlyphList pulls out the translation and applies it separately, so
// we strip it out when we set the dtx. Basically nothing uses the
// translation except getPixelBounds.
// called by needsPositions, setRenderTransform
return
}
// returns new tx if old one has translation, otherwise returns old one
0, 0);
}
return tx;
}
}
// called by setupGlyphImages (after needsPositions, so redundant match check?)
}
}
// called by getGlyphsPixelBounds
}
}
// called by most functions
private final void setFRCTX() {
}
}
/**
* Change the dtx for the strike refs we use. Keeps a reference to the at. At
* must not contain translation.
* Called by setRenderTransform, setDTX, initFontData.
*/
if (!dtx.isIdentity()) {
try {
}
catch (NoninvertibleTransformException e) {
// we needn't care for rendering
}
}
}
}
/**
* Utility used by getStandardGV.
* Constructs a StandardGlyphVector from a generic glyph vector.
* Do not call this from new contexts without considering the comment
* about "userGlyphs".
*/
initFontData();
if (gv instanceof StandardGlyphVector) {
/* userGlyphs will be OK because this is a private constructor
* and the returned instance is used only for rendering.
* It's not constructable by user code, nor returned to the
* application. So we know "userGlyphs" are valid as having
* been either already validated or are the result of layout.
*/
this.glyphs = userGlyphs;
} else {
}
}
}
for (int i = 0; i < nGlyphs; ++i) {
}
}
}
/* Before asking the Font we see if the glyph code is
* FFFE or FFFF which are special values that we should be internally
* ready to handle as meaning invisible glyphs. The Font would report
* those as the missing glyph.
*/
for (int i=0; i<len; i++) {
} else {
}
}
return vglyphs;
}
// utility used by constructors
throw new ArrayIndexOutOfBoundsException("start or count out of bounds");
}
}
// !!! change mapper interface?
if (start != 0) {
}
initFontData(); // sets up font2D
// !!! no layout for now, should add checks
// !!! need to support creating a StandardGlyphVector from a TextMeasurer's info...
/* Glyphs obtained here are already validated by the font */
userGlyphs = glyphs;
}
private void initFontData() {
if (font.isTransformed()) {
}
} else {
}
}
/**
* Copy glyph position data into a result array starting at the indicated
* offset in the array. If the passed-in result array is null, a new
* array will be allocated and returned.
*
* This is an internal method and does no extra argument checking.
*
* @param start the index of the first glyph to get
* @param count the number of glyphs to get
* @param offset the offset into result at which to put the data
* @param result an array to hold the x,y positions
* @return the modified position array
*/
}
// System.arraycopy is slow for stuff like this
}
return result;
}
setFRCTX();
}
/**
* Used by getOutline, getGlyphsOutline
*/
setFRCTX();
}
return result;
}
private Rectangle getGlyphsPixelBounds(FontRenderContext frc, float x, float y, int start, int count) {
initPositions(); // FIRST ensure we have positions based on our frctx
} else {
}
}
int n = start * 2;
while (--count >= 0) {
if (!r.isEmpty()) {
} else {
}
}
}
}
if (lbcacheRef != null) {
}
}
if (vbcacheRef != null) {
}
}
}
private void clearCaches() {
lbcacheRef = null;
vbcacheRef = null;
}
// internal use only for possible future extension
/**
* A flag used with getLayoutFlags that indicates whether this <code>GlyphVector</code> uses
* a vertical baseline.
*/
/**
* A flag used with getLayoutFlags that indicates whether this <code>GlyphVector</code> uses
* vertical glyph metrics. A <code>GlyphVector</code> can use vertical metrics on a
* horizontal line, or vice versa.
*/
/**
* A flag used with getLayoutFlags that indicates whether this <code>GlyphVector</code> uses
* the 'alternate orientation.' Glyphs have a default orientation given a
* particular baseline and metrics orientation, this is the orientation appropriate
* for left-to-right text. For example, the letter 'A' can have four orientations,
* with the point at 12, 3, 6, or 9 'o clock. The following table shows where the
* point displays for different values of vertical baseline (vb), vertical
* metrics (vm) and alternate orientation (fo):<br>
* <blockquote>
* vb vm ao
* -- -- -- --
* f f f 12 ^ horizontal metrics on horizontal lines
* f f t 6 v
* f t f 9 < vertical metrics on horizontal lines
* f t t 3 >
* t f f 3 > horizontal metrics on vertical lines
* t f t 9 <
* t t f 12 ^ vertical metrics on vertical lines
* t t t 6 v
* </blockquote>
*/
/**
* Ensure that the positions array exists and holds position data.
* If the array is null, this allocates it and sets default positions.
*/
private void initPositions() {
setFRCTX();
if (track != 0) {
}
if (font.isTransformed()) {
}
}
}
}
}
}
/**
* OR newFlags with existing flags. First computes existing flags if needed.
*/
}
/**
* AND the complement of clearedFlags with existing flags. First computes existing flags if needed.
*/
}
// general utility methods
// encapsulate the test to check whether we have per-glyph transforms
return getDefaultStrike();
} else {
}
}
// encapsulate access to cached default glyph strike
}
}
return gs;
}
/////////////////////
// Internal utility classes
/////////////////////
// !!! I have this as a separate class instead of just inside SGV,
// but I previously didn't bother. Now I'm trying this again.
// Probably still not worth it, but I'd like to keep sgv's small in the common case.
static final class GlyphTransformInfo {
// used when first setting a transform
}
// used when cloning a glyph vector, need to set back link
}
// used in sgv equality
return false;
}
if (rhs == this) {
return true;
}
return false;
}
return false;
}
// slow since we end up processing the same transforms multiple
// times, but since transforms can be in any order, we either do
// this or create a mapping. Equality tests aren't common so
// leave it like this.
return false;
}
if (tix != 0) {
tix *= 6;
rix *= 6;
for (int j = 6; j > 0; --j) {
return false;
}
}
}
}
return true;
}
// implements sgv.setGlyphTransform
// we store all the glyph transforms as a double array, and for each glyph there
// is an entry in the txIndices array indicating which transform to use. 0 means
// there's no transform, 1 means use the first transform (the 6 doubles at offset
// 0), 2 means use the second transform (the 6 doubles at offset 6), etc.
//
// Since this can be called multiple times, and since the number of transforms
// affects the time it takes to construct the glyphs, we try to keep the arrays as
// compact as possible, by removing transforms that are no longer used, and reusing
// transforms where we already have them.
double[] temp = new double[6];
boolean isIdentity = true;
// Fill in temp
}
else {
isIdentity = false;
}
if (isIdentity) { // no change
return;
}
transforms = temp;
} else {
boolean addSlot = false; // assume we're not growing
int newIndex = -1;
if (isIdentity) {
} else {
addSlot = true; // assume no match
int i;
loop:
for (int j = 0; j < 6; ++j) {
if (transforms[i + j] != temp[j]) {
continue loop;
}
}
addSlot = false;
break;
}
}
// if we're using the same transform, nothing to do
// see if we are removing last use of the old slot
boolean removeSlot = false;
if (oldIndex != 0) {
removeSlot = true;
removeSlot = false;
break;
}
}
}
} else if (removeSlot) {
transforms = null;
strikesRef = null;
return;
}
transforms = ttemp;
// clean up indices
indices[i] -= 1;
}
}
--newIndex;
}
} else if (addSlot) {
transforms = ttemp;
}
}
}
strikesRef = null;
}
// implements sgv.getGlyphTransform
if (index == 0) {
return null;
}
transforms[x + 1],
transforms[x + 2],
transforms[x + 3],
transforms[x + 4],
transforms[x + 5]);
}
int transformCount() {
if (transforms == null) {
return 0;
}
}
/**
* The strike cache works like this.
*
* -Each glyph is thought of as having a transform, usually identity.
* -Each request for a strike is based on a device transform, either the
* one in the frc or the rendering transform.
* -For general info, strikes are held with soft references.
* -When rendering, strikes must be held with hard references for the
* duration of the rendering call. GlyphList will have to hold this
* info along with the image and position info, but toss the strike info
* when done.
* -Build the strike cache as needed. If the dev transform we want to use
* has changed from the last time it is built, the cache is flushed by
* the caller before these methods are called.
*
* Use a tx that doesn't include translation components of dst tx.
*/
for (int i = 0; i < len; ++i) {
}
return sl;
}
int n = start * 2;
while (--count >= 0) {
if (!r.isEmpty()) {
} else {
}
}
}
}
}
return sgv.getDefaultStrike();
}
return null;
}
if (!haveAllStrikes) {
getStrikeAtIndex(strikes, i);
}
haveAllStrikes = true;
}
return strikes;
}
if (strikesRef != null) {
}
haveAllStrikes = false;
}
return strikes;
}
if (strikeIndex == 0) {
} else {
}
}
return strike;
}
}
// This adjusts the metrics by the translation components of the glyph
// transform. It is done here since the translation is not known by the
// strike.
// It adjusts the position of the image and the advance.
public static final class GlyphStrike {
float dx;
float dy;
float dx = 0;
float dy = 0;
}
if (!dtx.isIdentity()) {
}
}
if (aaHint == VALUE_TEXT_ANTIALIAS_GASP) {
/* Must pass in the calculated point size for rendering.
* If the glyph tx is anything other than identity or a
* simple translate, calculate the transformed point size.
*/
if (!tx.isIdentity() &&
if (shearx != 0) {
ptSize =
} else {
}
}
}
tx,
}
}
}
}
++ix;
}
// !!! change this API? Creates unnecessary garbage. Also the name doesn't quite fit.
// strike.addGlyphAdvance(Point2D.Float adv); // hey, whaddya know, matches my api :-)
}
} else {
}
/* Since x is the logical advance of the glyph to this point.
* Because of the way that Rectangle.union is specified, this
* means that subsequent unioning of a rect including that
* will be affected, even if the glyph is empty. So skip such
* cases. This alone isn't a complete solution since x==0
* may also not be what is wanted. The code that does the
* unioning also needs to be aware to ignore empty glyphs.
*/
}
return result;
}
// !!! fontStrike needs a method for this. For that matter, GeneralPath does.
} else {
}
}
}
}
buf = new StringBuffer();
}
try {
if (i > 0) {
}
}
if (i > 0) {
}
}
}
if (charIndices != null) {
if (i > 0) {
}
}
}
if (getLayoutFlags() == 0) {
} else {
}
}
}
}
}
}
catch(Exception e) {
}
return buf;
}
static class ADL {
public float ascentX;
public float ascentY;
public float descentX;
public float descentY;
public float leadingX;
public float leadingY;
}
result = new StringBuffer();
}
return result;
}
}
}