use of sun.font.Font2DHandle 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