use of sun.font.CompositeFont in project jdk8u_jdk by JetBrains.
the class X11FontManager method getFontConfigFUIR.
@Override
protected FontUIResource getFontConfigFUIR(String family, int style, int size) {
CompositeFont font2D = getFontConfigManager().getFontConfigFont(family, style);
if (font2D == null) {
// Not expected, just a precaution.
return new FontUIResource(family, style, size);
}
/* The name of the font will be that of the physical font in slot,
* but by setting the handle to that of the CompositeFont it
* renders as that CompositeFont.
* It also needs to be marked as a created font which is the
* current mechanism to signal that deriveFont etc must copy
* the handle from the original font.
*/
FontUIResource fuir = new FontUIResource(font2D.getFamilyName(null), style, size);
FontAccess.getFontAccess().setFont2D(fuir, font2D.handle);
FontAccess.getFontAccess().setCreatedFont(fuir);
return fuir;
}
use of sun.font.CompositeFont in project jdk8u_jdk by JetBrains.
the class WPathGraphics method drawString.
/**
* Renders the text specified by the specified <code>String</code>,
* using the current <code>Font</code> and <code>Paint</code> attributes
* in the <code>Graphics2D</code> context.
* The baseline of the first character is at position
* (<i>x</i>, <i>y</i>) in the User Space.
* The rendering attributes applied include the <code>Clip</code>,
* <code>Transform</code>, <code>Paint</code>, <code>Font</code> and
* <code>Composite</code> attributes. For characters in script systems
* such as Hebrew and Arabic, the glyphs can be rendered from right to
* left, in which case the coordinate supplied is the location of the
* leftmost character on the baseline.
* @param s the <code>String</code> to be rendered
* @param x, y the coordinates where the <code>String</code>
* should be rendered
* @see #setPaint
* @see java.awt.Graphics#setColor
* @see java.awt.Graphics#setFont
* @see #setTransform
* @see #setComposite
* @see #setClip
*/
@Override
public void drawString(String str, float x, float y, Font font, FontRenderContext frc, float targetW) {
if (str.length() == 0) {
return;
}
if (WPrinterJob.shapeTextProp) {
super.drawString(str, x, y, font, frc, targetW);
return;
}
/* If the Font has layout attributes we need to delegate to TextLayout.
* TextLayout renders text as GlyphVectors. We try to print those
* using printer fonts - ie using Postscript text operators so
* we may be reinvoked. In that case the "!printingGlyphVector" test
* prevents us recursing and instead sends us into the body of the
* method where we can safely ignore layout attributes as those
* are already handled by TextLayout.
* Similarly if layout is needed based on the text, then we
* delegate to TextLayout if possible, or failing that we delegate
* upwards to filled shapes.
*/
boolean layoutNeeded = strNeedsTextLayout(str, font);
if ((font.hasLayoutAttributes() || layoutNeeded) && !printingGlyphVector) {
TextLayout layout = new TextLayout(str, font, frc);
layout.draw(this, x, y);
return;
} else if (layoutNeeded) {
super.drawString(str, x, y, font, frc, targetW);
return;
}
AffineTransform deviceTransform = getTransform();
AffineTransform fontTransform = new AffineTransform(deviceTransform);
fontTransform.concatenate(font.getTransform());
int transformType = fontTransform.getType();
/* Use GDI for the text if the graphics transform is something
* for which we can obtain a suitable GDI font.
* A flip or shearing transform on the graphics or a transform
* on the font force us to decompose the text into a shape.
*/
boolean directToGDI = ((transformType != AffineTransform.TYPE_GENERAL_TRANSFORM) && ((transformType & AffineTransform.TYPE_FLIP) == 0));
WPrinterJob wPrinterJob = (WPrinterJob) getPrinterJob();
try {
wPrinterJob.setTextColor((Color) getPaint());
} catch (ClassCastException e) {
// peek should detect such paints.
directToGDI = false;
}
if (!directToGDI) {
super.drawString(str, x, y, font, frc, targetW);
return;
}
/* Now we have checked everything is OK to go through GDI as text
* with the exception of testing GDI can find and use the font. That
* is handled in the textOut() call.
*/
/* Compute the starting position of the string in
* device space.
*/
Point2D.Float userpos = new Point2D.Float(x, y);
Point2D.Float devpos = new Point2D.Float();
/* Already have the translate from the deviceTransform,
* but the font may have a translation component too.
*/
if (font.isTransformed()) {
AffineTransform fontTx = font.getTransform();
float translateX = (float) (fontTx.getTranslateX());
float translateY = (float) (fontTx.getTranslateY());
if (Math.abs(translateX) < 0.00001)
translateX = 0f;
if (Math.abs(translateY) < 0.00001)
translateY = 0f;
userpos.x += translateX;
userpos.y += translateY;
}
deviceTransform.transform(userpos, devpos);
if (getClip() != null) {
deviceClip(getClip().getPathIterator(deviceTransform));
}
/* Get the font size in device coordinates.
* The size needed is the font height scaled to device space.
* Although we have already tested that there is no shear,
* there may be a non-uniform scale, so the width of the font
* does not scale equally with the height. That is handled
* by specifying an 'average width' scale to GDI.
*/
float fontSize = font.getSize2D();
double devResX = wPrinterJob.getXRes();
double devResY = wPrinterJob.getYRes();
double fontDevScaleY = devResY / DEFAULT_USER_RES;
int orient = getPageFormat().getOrientation();
if (orient == PageFormat.LANDSCAPE || orient == PageFormat.REVERSE_LANDSCAPE) {
double tmp = devResX;
devResX = devResY;
devResY = tmp;
}
double devScaleX = devResX / DEFAULT_USER_RES;
double devScaleY = devResY / DEFAULT_USER_RES;
fontTransform.scale(1.0 / devScaleX, 1.0 / devScaleY);
Point2D.Double pty = new Point2D.Double(0.0, 1.0);
fontTransform.deltaTransform(pty, pty);
double scaleFactorY = Math.sqrt(pty.x * pty.x + pty.y * pty.y);
float scaledFontSizeY = (float) (fontSize * scaleFactorY * fontDevScaleY);
Point2D.Double ptx = new Point2D.Double(1.0, 0.0);
fontTransform.deltaTransform(ptx, ptx);
double scaleFactorX = Math.sqrt(ptx.x * ptx.x + ptx.y * ptx.y);
float awScale = getAwScale(scaleFactorX, scaleFactorY);
int iangle = getAngle(ptx);
ptx = new Point2D.Double(1.0, 0.0);
deviceTransform.deltaTransform(ptx, ptx);
double advanceScaleX = Math.sqrt(ptx.x * ptx.x + ptx.y * ptx.y);
pty = new Point2D.Double(0.0, 1.0);
deviceTransform.deltaTransform(pty, pty);
double advanceScaleY = Math.sqrt(pty.x * pty.x + pty.y * pty.y);
Font2D font2D = FontUtilities.getFont2D(font);
if (font2D instanceof TrueTypeFont) {
textOut(str, font, (TrueTypeFont) font2D, frc, scaledFontSizeY, iangle, awScale, advanceScaleX, advanceScaleY, x, y, devpos.x, devpos.y, targetW);
} else if (font2D instanceof CompositeFont) {
/* Composite fonts are made up of multiple fonts and each
* substring that uses a particular component font needs to
* be separately sent to GDI.
* This works for standard composite fonts, alternate ones,
* Fonts that are a physical font backed by a standard composite,
* and with fallback fonts.
*/
CompositeFont compFont = (CompositeFont) font2D;
float userx = x, usery = y;
float devx = devpos.x, devy = devpos.y;
char[] chars = str.toCharArray();
int len = chars.length;
int[] glyphs = new int[len];
compFont.getMapper().charsToGlyphs(len, chars, glyphs);
int startChar = 0, endChar = 0, slot = 0;
while (endChar < len) {
startChar = endChar;
slot = glyphs[startChar] >>> 24;
while (endChar < len && ((glyphs[endChar] >>> 24) == slot)) {
endChar++;
}
String substr = new String(chars, startChar, endChar - startChar);
PhysicalFont slotFont = compFont.getSlotFont(slot);
textOut(substr, font, slotFont, frc, scaledFontSizeY, iangle, awScale, advanceScaleX, advanceScaleY, userx, usery, devx, devy, 0f);
Rectangle2D bds = font.getStringBounds(substr, frc);
float xAdvance = (float) bds.getWidth();
userx += xAdvance;
userpos.x += xAdvance;
deviceTransform.transform(userpos, devpos);
devx = devpos.x;
devy = devpos.y;
}
} else {
super.drawString(str, x, y, font, frc, targetW);
}
}
use of sun.font.CompositeFont in project jdk8u_jdk by JetBrains.
the class WPathGraphics method platformFontCount.
/* A return value of 0 would mean font not available to GDI, or the
* it can't be used for this string.
* A return of 1 means it is suitable, including for composites.
* We check that the transform in effect is doable with GDI, and that
* this is a composite font AWT can handle, or a physical font GDI
* can handle directly. Its possible that some strings may ultimately
* fail the more stringent tests in drawString but this is rare and
* also that method will always succeed, as if the font isn't available
* it will use outlines via a superclass call. Also it is only called for
* the default render context (as canDrawStringToWidth() will return
* false. That is why it ignores the frc and width arguments.
*/
@Override
protected int platformFontCount(Font font, String str) {
AffineTransform deviceTransform = getTransform();
AffineTransform fontTransform = new AffineTransform(deviceTransform);
fontTransform.concatenate(getFont().getTransform());
int transformType = fontTransform.getType();
/* Test if GDI can handle the transform */
boolean directToGDI = ((transformType != AffineTransform.TYPE_GENERAL_TRANSFORM) && ((transformType & AffineTransform.TYPE_FLIP) == 0));
if (!directToGDI) {
return 0;
}
/* Since all windows fonts are available, and the JRE fonts
* are also registered. Only the Font.createFont() case is presently
* unknown to GDI. Those can be registered too, although that
* code does not exist yet, it can be added too, so we should not
* fail that case. Just do a quick check whether its a TrueTypeFont
* - ie not a Type1 font etc, and let drawString() resolve the rest.
*/
Font2D font2D = FontUtilities.getFont2D(font);
if (font2D instanceof CompositeFont || font2D instanceof TrueTypeFont) {
return 1;
} else {
return 0;
}
}
use of sun.font.CompositeFont in project jdk8u_jdk by JetBrains.
the class WPathGraphics method printGlyphVector.
/** return true if the Graphics instance can directly print
* this glyphvector
*/
@Override
protected boolean printGlyphVector(GlyphVector gv, float x, float y) {
/* We don't want to try to handle per-glyph transforms. GDI can't
* handle per-glyph rotations, etc. There's no way to express it
* in a single call, so just bail for this uncommon case.
*/
if ((gv.getLayoutFlags() & GlyphVector.FLAG_HAS_TRANSFORMS) != 0) {
return false;
}
if (gv.getNumGlyphs() == 0) {
// nothing to do.
return true;
}
AffineTransform deviceTransform = getTransform();
AffineTransform fontTransform = new AffineTransform(deviceTransform);
Font font = gv.getFont();
fontTransform.concatenate(font.getTransform());
int transformType = fontTransform.getType();
/* Use GDI for the text if the graphics transform is something
* for which we can obtain a suitable GDI font.
* A flip or shearing transform on the graphics or a transform
* on the font force us to decompose the text into a shape.
*/
boolean directToGDI = ((transformType != AffineTransform.TYPE_GENERAL_TRANSFORM) && ((transformType & AffineTransform.TYPE_FLIP) == 0));
WPrinterJob wPrinterJob = (WPrinterJob) getPrinterJob();
try {
wPrinterJob.setTextColor((Color) getPaint());
} catch (ClassCastException e) {
// peek should detect such paints.
directToGDI = false;
}
if (WPrinterJob.shapeTextProp || !directToGDI) {
return false;
}
/* Compute the starting position of the string in
* device space.
*/
Point2D.Float userpos = new Point2D.Float(x, y);
/* Add the position of the first glyph - its not always 0,0 */
Point2D g0pos = gv.getGlyphPosition(0);
userpos.x += (float) g0pos.getX();
userpos.y += (float) g0pos.getY();
Point2D.Float devpos = new Point2D.Float();
/* Already have the translate from the deviceTransform,
* but the font may have a translation component too.
*/
if (font.isTransformed()) {
AffineTransform fontTx = font.getTransform();
float translateX = (float) (fontTx.getTranslateX());
float translateY = (float) (fontTx.getTranslateY());
if (Math.abs(translateX) < 0.00001)
translateX = 0f;
if (Math.abs(translateY) < 0.00001)
translateY = 0f;
userpos.x += translateX;
userpos.y += translateY;
}
deviceTransform.transform(userpos, devpos);
if (getClip() != null) {
deviceClip(getClip().getPathIterator(deviceTransform));
}
/* Get the font size in device coordinates.
* The size needed is the font height scaled to device space.
* Although we have already tested that there is no shear,
* there may be a non-uniform scale, so the width of the font
* does not scale equally with the height. That is handled
* by specifying an 'average width' scale to GDI.
*/
float fontSize = font.getSize2D();
double devResX = wPrinterJob.getXRes();
double devResY = wPrinterJob.getYRes();
double fontDevScaleY = devResY / DEFAULT_USER_RES;
int orient = getPageFormat().getOrientation();
if (orient == PageFormat.LANDSCAPE || orient == PageFormat.REVERSE_LANDSCAPE) {
double tmp = devResX;
devResX = devResY;
devResY = tmp;
}
double devScaleX = devResX / DEFAULT_USER_RES;
double devScaleY = devResY / DEFAULT_USER_RES;
fontTransform.scale(1.0 / devScaleX, 1.0 / devScaleY);
Point2D.Double pty = new Point2D.Double(0.0, 1.0);
fontTransform.deltaTransform(pty, pty);
double scaleFactorY = Math.sqrt(pty.x * pty.x + pty.y * pty.y);
float scaledFontSizeY = (float) (fontSize * scaleFactorY * fontDevScaleY);
Point2D.Double ptx = new Point2D.Double(1.0, 0.0);
fontTransform.deltaTransform(ptx, ptx);
double scaleFactorX = Math.sqrt(ptx.x * ptx.x + ptx.y * ptx.y);
float awScale = getAwScale(scaleFactorX, scaleFactorY);
int iangle = getAngle(ptx);
ptx = new Point2D.Double(1.0, 0.0);
deviceTransform.deltaTransform(ptx, ptx);
double advanceScaleX = Math.sqrt(ptx.x * ptx.x + ptx.y * ptx.y);
pty = new Point2D.Double(0.0, 1.0);
deviceTransform.deltaTransform(pty, pty);
double advanceScaleY = Math.sqrt(pty.x * pty.x + pty.y * pty.y);
int numGlyphs = gv.getNumGlyphs();
int[] glyphCodes = gv.getGlyphCodes(0, numGlyphs, null);
float[] glyphPos = gv.getGlyphPositions(0, numGlyphs, null);
/* layout replaces glyphs which have been combined away
* with 0xfffe or 0xffff. These are supposed to be invisible
* and we need to handle this here as GDI will interpret it
* as a missing glyph. We'll do it here by compacting the
* glyph codes array, but we have to do it in conjunction with
* compacting the positions/advances arrays too AND updating
* the number of glyphs ..
* Note that since the slot number for composites is in the
* significant byte we need to mask out that for comparison of
* the invisible glyph.
*/
int invisibleGlyphCnt = 0;
for (int gc = 0; gc < numGlyphs; gc++) {
if ((glyphCodes[gc] & 0xffff) >= CharToGlyphMapper.INVISIBLE_GLYPHS) {
invisibleGlyphCnt++;
}
}
if (invisibleGlyphCnt > 0) {
int visibleGlyphCnt = numGlyphs - invisibleGlyphCnt;
int[] visibleGlyphCodes = new int[visibleGlyphCnt];
float[] visiblePositions = new float[visibleGlyphCnt * 2];
int index = 0;
for (int i = 0; i < numGlyphs; i++) {
if ((glyphCodes[i] & 0xffff) < CharToGlyphMapper.INVISIBLE_GLYPHS) {
visibleGlyphCodes[index] = glyphCodes[i];
visiblePositions[index * 2] = glyphPos[i * 2];
visiblePositions[index * 2 + 1] = glyphPos[i * 2 + 1];
index++;
}
}
numGlyphs = visibleGlyphCnt;
glyphCodes = visibleGlyphCodes;
glyphPos = visiblePositions;
}
/* To get GDI to rotate glyphs we need to specify the angle
* of rotation to GDI when creating the HFONT. This implicitly
* also rotates the baseline, and this adjusts the X & Y advances
* of the glyphs accordingly.
* When we specify the advances, they are in device space, so
* we don't want any further interpretation applied by GDI, but
* since as noted the advances are interpreted in the HFONT's
* coordinate space, our advances would be rotated again.
* We don't have any way to tell GDI to rotate only the glyphs and
* not the advances, so we need to account for this in the advances
* we supply, by supplying unrotated advances.
* Note that "iangle" is in the opposite direction to 2D's normal
* direction of rotation, so this rotation inverts the
* rotation element of the deviceTransform.
*/
AffineTransform advanceTransform = AffineTransform.getScaleInstance(advanceScaleX, advanceScaleY);
float[] glyphAdvPos = new float[glyphPos.length];
//source
advanceTransform.transform(//source
glyphPos, //source
0, //destination
glyphAdvPos, //destination
0, //num points
glyphPos.length / 2);
Font2D font2D = FontUtilities.getFont2D(font);
if (font2D instanceof TrueTypeFont) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
if (!wPrinterJob.setFont(family, scaledFontSizeY, style, iangle, awScale)) {
return false;
}
wPrinterJob.glyphsOut(glyphCodes, devpos.x, devpos.y, glyphAdvPos);
} else if (font2D instanceof CompositeFont) {
/* Composite fonts are made up of multiple fonts and each
* substring that uses a particular component font needs to
* be separately sent to GDI.
* This works for standard composite fonts, alternate ones,
* Fonts that are a physical font backed by a standard composite,
* and with fallback fonts.
*/
CompositeFont compFont = (CompositeFont) font2D;
float userx = x, usery = y;
float devx = devpos.x, devy = devpos.y;
int start = 0, end = 0, slot = 0;
while (end < numGlyphs) {
start = end;
slot = glyphCodes[start] >>> 24;
while (end < numGlyphs && ((glyphCodes[end] >>> 24) == slot)) {
end++;
}
/* If we can't get the font, bail to outlines.
* But we should always be able to get all fonts for
* Composites, so this is unlikely, so any overstriking
* if only one slot is unavailable is not worth worrying
* about.
*/
PhysicalFont slotFont = compFont.getSlotFont(slot);
if (!(slotFont instanceof TrueTypeFont)) {
return false;
}
String family = slotFont.getFamilyName(null);
int style = font.getStyle() | slotFont.getStyle();
if (!wPrinterJob.setFont(family, scaledFontSizeY, style, iangle, awScale)) {
return false;
}
int[] glyphs = Arrays.copyOfRange(glyphCodes, start, end);
float[] posns = Arrays.copyOfRange(glyphAdvPos, start * 2, end * 2);
if (start != 0) {
Point2D.Float p = new Point2D.Float(x + glyphPos[start * 2], y + glyphPos[start * 2 + 1]);
deviceTransform.transform(p, p);
devx = p.x;
devy = p.y;
}
wPrinterJob.glyphsOut(glyphs, devx, devy, posns);
}
} else {
return false;
}
return true;
}
use of sun.font.CompositeFont in project jdk8u_jdk by JetBrains.
the class PathGraphics method printedSimpleGlyphVector.
/* GlyphVectors are usually encountered because TextLayout is in use.
* Some times TextLayout is needed to handle complex text or some
* rendering attributes trigger it.
* We try to print GlyphVectors by reconstituting into a String,
* as that is most recoverable for applications that export to formats
* such as Postscript or PDF. In some cases (eg where its not complex
* text and its just that positions aren't what we'd expect) we print
* one character at a time. positioning individually.
* Failing that, if we can directly send glyph codes to the printer
* then we do that (printGlyphVector).
* As a last resort we return false and let the caller print as filled
* shapes.
*/
boolean printedSimpleGlyphVector(GlyphVector g, float x, float y) {
int flags = g.getLayoutFlags();
/* We can't handle RTL, re-ordering, complex glyphs etc by
* reconstituting glyphs into a String. So if any flags besides
* position adjustments are set, see if we can directly
* print the GlyphVector as glyph codes, using the positions
* layout has assigned. If that fails return false;
*/
if (flags != 0 && flags != GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS) {
return printGlyphVector(g, x, y);
}
Font font = g.getFont();
Font2D font2D = FontUtilities.getFont2D(font);
if (font2D.handle.font2D != font2D) {
/* suspicious, may be a bad font. lets bail */
return false;
}
Hashtable<Font2DHandle, Object> fontMap;
synchronized (PathGraphics.class) {
fontMap = fontMapRef.get();
if (fontMap == null) {
fontMap = new Hashtable<Font2DHandle, Object>();
fontMapRef = new SoftReference<Hashtable<Font2DHandle, Object>>(fontMap);
}
}
int numGlyphs = g.getNumGlyphs();
int[] glyphCodes = g.getGlyphCodes(0, numGlyphs, null);
char[] glyphToCharMap = null;
char[][] mapArray = null;
CompositeFont cf = null;
/* Build the needed maps for this font in a synchronized block */
synchronized (fontMap) {
if (font2D instanceof CompositeFont) {
cf = (CompositeFont) font2D;
int numSlots = cf.getNumSlots();
mapArray = (char[][]) fontMap.get(font2D.handle);
if (mapArray == null) {
mapArray = new char[numSlots][];
fontMap.put(font2D.handle, mapArray);
}
for (int i = 0; i < numGlyphs; i++) {
int slot = glyphCodes[i] >>> 24;
if (slot >= numSlots) {
/* shouldn't happen */
return false;
}
if (mapArray[slot] == null) {
Font2D slotFont = cf.getSlotFont(slot);
char[] map = (char[]) fontMap.get(slotFont.handle);
if (map == null) {
map = getGlyphToCharMapForFont(slotFont);
}
mapArray[slot] = map;
}
}
} else {
glyphToCharMap = (char[]) fontMap.get(font2D.handle);
if (glyphToCharMap == null) {
glyphToCharMap = getGlyphToCharMapForFont(font2D);
fontMap.put(font2D.handle, glyphToCharMap);
}
}
}
char[] chars = new char[numGlyphs];
if (cf != null) {
for (int i = 0; i < numGlyphs; i++) {
int gc = glyphCodes[i];
char[] map = mapArray[gc >>> 24];
gc = gc & 0xffffff;
if (map == null) {
return false;
}
/* X11 symbol & dingbats fonts used only for global metrics,
* so the glyph codes we have really refer to Lucida Sans
* Regular.
* So its possible the glyph code may appear out of range.
* Note that later on we double-check the glyph codes that
* we get from re-creating the GV from the string are the
* same as those we started with.
*
* If the glyphcode is INVISIBLE_GLYPH_ID then this may
* be \t, \n or \r which are mapped to that by layout.
* This is a case we can handle. It doesn't matter what
* character we use (we use \n) so long as layout maps it
* back to this in the verification, since the invisible
* glyph isn't visible :)
*/
char ch;
if (gc == CharToGlyphMapper.INVISIBLE_GLYPH_ID) {
ch = '\n';
} else if (gc < 0 || gc >= map.length) {
return false;
} else {
ch = map[gc];
}
if (ch != CharToGlyphMapper.INVISIBLE_GLYPH_ID) {
chars[i] = ch;
} else {
return false;
}
}
} else {
for (int i = 0; i < numGlyphs; i++) {
int gc = glyphCodes[i];
char ch;
if (gc == CharToGlyphMapper.INVISIBLE_GLYPH_ID) {
ch = '\n';
} else if (gc < 0 || gc >= glyphToCharMap.length) {
return false;
} else {
ch = glyphToCharMap[gc];
}
if (ch != CharToGlyphMapper.INVISIBLE_GLYPH_ID) {
chars[i] = ch;
} else {
return false;
}
}
}
FontRenderContext gvFrc = g.getFontRenderContext();
GlyphVector gv2 = font.createGlyphVector(gvFrc, chars);
if (gv2.getNumGlyphs() != numGlyphs) {
return printGlyphVector(g, x, y);
}
int[] glyphCodes2 = gv2.getGlyphCodes(0, numGlyphs, null);
/*
* Needed to double-check remapping of X11 symbol & dingbats.
*/
for (int i = 0; i < numGlyphs; i++) {
if (glyphCodes[i] != glyphCodes2[i]) {
return printGlyphVector(g, x, y);
}
}
FontRenderContext g2dFrc = getFontRenderContext();
boolean compatibleFRC = gvFrc.equals(g2dFrc);
/* If differ only in specifying A-A or a translation, these are
* also compatible FRC's, and we can do one drawString call.
*/
if (!compatibleFRC && gvFrc.usesFractionalMetrics() == g2dFrc.usesFractionalMetrics()) {
AffineTransform gvAT = gvFrc.getTransform();
AffineTransform g2dAT = getTransform();
double[] gvMatrix = new double[4];
double[] g2dMatrix = new double[4];
gvAT.getMatrix(gvMatrix);
g2dAT.getMatrix(g2dMatrix);
compatibleFRC = true;
for (int i = 0; i < 4; i++) {
if (gvMatrix[i] != g2dMatrix[i]) {
compatibleFRC = false;
break;
}
}
}
String str = new String(chars, 0, numGlyphs);
int numFonts = platformFontCount(font, str);
if (numFonts == 0) {
return false;
}
float[] positions = g.getGlyphPositions(0, numGlyphs, null);
boolean noPositionAdjustments = ((flags & GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS) == 0) || samePositions(gv2, glyphCodes2, glyphCodes, positions);
/* We have to consider that the application may be directly
* creating a GlyphVector, rather than one being created by
* TextLayout or indirectly from drawString. In such a case, if the
* font has layout attributes, the text may measure differently
* when we reconstitute it into a String and ask for the length that
* drawString would use. For example, KERNING will be applied in such
* a case but that Font attribute is not applied when the application
* directly created a GlyphVector. So in this case we need to verify
* that the text measures the same in both cases - ie that the
* layout attribute has no effect. If it does we can't always
* use the drawString call unless we can coerce the drawString call
* into measuring and displaying the string to the same length.
* That is the case where there is only one font used and we can
* specify the overall advance of the string. (See below).
*/
Point2D gvAdvancePt = g.getGlyphPosition(numGlyphs);
float gvAdvanceX = (float) gvAdvancePt.getX();
boolean layoutAffectsAdvance = false;
if (font.hasLayoutAttributes() && printingGlyphVector && noPositionAdjustments) {
/* If TRACKING is in use then the glyph vector will report
* position adjustments, then that ought to be sufficient to
* tell us we can't just ask native to do "drawString". But layout
* always sets the position adjustment flag, so we don't believe
* it and verify the positions are really different than
* createGlyphVector() (with no layout) would create. However
* inconsistently, TRACKING is applied when creating a GlyphVector,
* since it doesn't actually require "layout" (even though its
* considered a layout attribute), it just requires a fractional
* tweak to the[default]advances. So we need to specifically
* check for tracking until such time as as we can trust
* the GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS bit.
*/
Map<TextAttribute, ?> map = font.getAttributes();
Object o = map.get(TextAttribute.TRACKING);
boolean tracking = o != null && (o instanceof Number) && (((Number) o).floatValue() != 0f);
if (tracking) {
noPositionAdjustments = false;
} else {
Rectangle2D bounds = font.getStringBounds(str, gvFrc);
float strAdvanceX = (float) bounds.getWidth();
if (Math.abs(strAdvanceX - gvAdvanceX) > 0.00001) {
layoutAffectsAdvance = true;
}
}
}
if (compatibleFRC && noPositionAdjustments && !layoutAffectsAdvance) {
drawString(str, x, y, font, gvFrc, 0f);
return true;
}
/* If positions have not been explicitly assigned, we can
* ask the string to be drawn adjusted to this width.
* This call is supported only in the PS generator.
* GDI has API to specify the advance for each glyph in a
* string which could be used here too, but that is not yet
* implemented, and we'd need to update the signature of the
* drawString method to take the advances (ie relative positions)
* and use that instead of the width.
*/
if (numFonts == 1 && canDrawStringToWidth() && noPositionAdjustments) {
drawString(str, x, y, font, gvFrc, gvAdvanceX);
return true;
}
/* In some scripts chars drawn individually do not have the
* same representation (glyphs) as when combined with other chars.
* The logic here is erring on the side of caution, in particular
* in including supplementary characters.
*/
if (FontUtilities.isComplexText(chars, 0, chars.length)) {
return printGlyphVector(g, x, y);
}
/* If we reach here we have mapped all the glyphs back
* one-to-one to simple unicode chars that we know are in the font.
* We can call "drawChars" on each one of them in turn, setting
* the position based on the glyph positions.
* There's typically overhead in this. If numGlyphs is 'large',
* it may even be better to try printGlyphVector() in this case.
* This may be less recoverable for apps, but sophisticated apps
* should be able to recover the text from simple glyph vectors
* and we can avoid penalising the more common case - although
* this is already a minority case.
*/
if (numGlyphs > 10 && printGlyphVector(g, x, y)) {
return true;
}
for (int i = 0; i < numGlyphs; i++) {
String s = new String(chars, i, 1);
drawString(s, x + positions[i * 2], y + positions[i * 2 + 1], font, gvFrc, 0f);
}
return true;
}
Aggregations