use of java.awt.font.FontRenderContext in project adempiere by adempiere.
the class TableElement method calculateSize.
/**************************************************************************
* Layout and Calculate Size.
* Set p_width & p_height
* @return true if calculated
*/
protected boolean calculateSize() {
if (p_sizeCalculated)
return true;
p_width = 0;
// reset
m_printRows = new ArrayList<ArrayList<ArrayList<Object>>>(m_data.length);
// Max Column Width = 50% of available width (used if maxWidth not set)
float dynMxColumnWidth = m_firstPage.width / 2;
// Width caolculation
int rows = m_data.length;
int cols = m_columnHeader.length;
// Data Sizes and Header Sizes
Dimension2DImpl[][] dataSizes = new Dimension2DImpl[rows][cols];
Dimension2DImpl[] headerSizes = new Dimension2DImpl[cols];
FontRenderContext frc = new FontRenderContext(null, true, true);
// data columns - rows
for (int dataCol = 0; dataCol < cols; dataCol++) {
int col = dataCol;
// Print below existing column
if (m_additionalLines.containsKey(new Integer(dataCol))) {
col = ((Integer) m_additionalLines.get(new Integer(dataCol))).intValue();
log.finest("DataColumn=" + dataCol + ", BelowColumn=" + col);
}
float colWidth = 0;
for (int row = 0; row < rows; row++) {
Object dataItem = m_data[row][dataCol];
if (dataItem == null) {
dataSizes[row][dataCol] = new Dimension2DImpl();
continue;
}
String string = dataItem.toString();
if (string.length() == 0) {
dataSizes[row][dataCol] = new Dimension2DImpl();
continue;
}
Font font = getFont(row, dataCol);
// Print below existing column = (col != dataCol)
addPrintLines(row, col, dataItem);
// don't print
dataSizes[row][dataCol] = new Dimension2DImpl();
if (dataItem instanceof Boolean) {
dataSizes[row][col].addBelow(LayoutEngine.IMAGE_SIZE);
continue;
} else if (dataItem instanceof ImageElement) {
dataSizes[row][col].addBelow(new Dimension((int) ((ImageElement) dataItem).getWidth(), (int) ((ImageElement) dataItem).getHeight()));
// Adjust the column width - teo_sarca, [ 1673620 ]
float width = (float) Math.ceil(dataSizes[row][col].getWidth());
if (colWidth < width)
colWidth = width;
continue;
} else if (dataItem instanceof BarcodeElement) {
dataSizes[row][col].addBelow(new Dimension((int) ((BarcodeElement) dataItem).getWidth(), (int) ((BarcodeElement) dataItem).getHeight()));
// Check if the overflow is allowed - teo_sarca, [ 1673590 ]
if (!((BarcodeElement) dataItem).isAllowOverflow()) {
float width = (float) Math.ceil(dataSizes[row][col].getWidth());
if (colWidth < width)
colWidth = width;
}
continue;
}
// No Width Limitations
if (m_columnMaxWidth[col] == 0 || m_columnMaxWidth[col] == -1) {
// if (HTMLElement.isHTML(string))
// log.finest( "HTML (no) r=" + row + ",c=" + dataCol);
TextLayout layout = new TextLayout(string, font, frc);
// buffer
float width = layout.getAdvance() + 2;
float height = layout.getAscent() + layout.getDescent() + layout.getLeading();
if (width > dynMxColumnWidth)
m_columnMaxWidth[col] = (int) Math.ceil(dynMxColumnWidth);
else if (colWidth < width)
colWidth = width;
if (dataSizes[row][col] == null) {
dataSizes[row][col] = new Dimension2DImpl();
log.log(Level.WARNING, "No Size for r=" + row + ",c=" + col);
}
dataSizes[row][col].addBelow(width, height);
}
// Width limitations
if (m_columnMaxWidth[col] != 0 && m_columnMaxWidth[col] != -1) {
float height = 0;
//
if (HTMLElement.isHTML(string)) {
// log.finest( "HTML (limit) r=" + row + ",c=" + dataCol);
HTMLRenderer renderer = HTMLRenderer.get(string);
colWidth = renderer.getWidth();
if (// one line only
m_columnMaxHeight[col] == -1)
height = renderer.getHeightOneLine();
else
height = renderer.getHeight();
renderer.setAllocation((int) colWidth, (int) height);
// log.finest( "calculateSize HTML - " + renderer.getAllocation());
// replace for printing
m_data[row][dataCol] = renderer;
} else {
String[] lines = Pattern.compile("$", Pattern.MULTILINE).split(string);
for (int lineNo = 0; lineNo < lines.length; lineNo++) {
AttributedString aString = new AttributedString(lines[lineNo]);
aString.addAttribute(TextAttribute.FONT, font);
AttributedCharacterIterator iter = aString.getIterator();
LineBreakMeasurer measurer = new LineBreakMeasurer(iter, frc);
while (measurer.getPosition() < iter.getEndIndex()) {
TextLayout layout = measurer.nextLayout(Math.abs(m_columnMaxWidth[col]));
float width = layout.getAdvance();
if (colWidth < width)
colWidth = width;
float lineHeight = layout.getAscent() + layout.getDescent() + layout.getLeading();
if (// one line only
m_columnMaxHeight[col] == -1) {
height = lineHeight;
break;
} else if (m_columnMaxHeight[col] == 0 || (height + lineHeight) <= m_columnMaxHeight[col])
height += lineHeight;
}
}
// for all lines
}
if (m_fixedWidth[col])
colWidth = Math.abs(m_columnMaxWidth[col]);
dataSizes[row][col].addBelow(colWidth, height);
}
dataSizes[row][col].roundUp();
if (dataItem instanceof NamePair)
m_rowColDrillDown.put(new Point(row, col), (NamePair) dataItem);
//
log.finest("Col=" + col + ", row=" + row + " => " + dataSizes[row][col] + " - ColWidth=" + colWidth);
}
// for all data rows
// Column Width for Header
String string = "";
if (m_columnHeader[dataCol] != null)
string = m_columnHeader[dataCol].toString();
// Print below existing column
if (col != dataCol)
headerSizes[dataCol] = new Dimension2DImpl();
else if (// suppress Null
colWidth == 0 && m_columnMaxWidth[dataCol] < 0 || string.length() == 0)
headerSizes[dataCol] = new Dimension2DImpl();
else {
Font font = getFont(HEADER_ROW, dataCol);
if (!font.isBold())
font = new Font(font.getName(), Font.BOLD, font.getSize());
// No Width Limitations
if (m_columnMaxWidth[dataCol] == 0 || m_columnMaxWidth[dataCol] == -1 || !m_multiLineHeader) {
TextLayout layout = new TextLayout(string, font, frc);
// buffer
float width = layout.getAdvance() + 3;
float height = layout.getAscent() + layout.getDescent() + layout.getLeading();
if (width > dynMxColumnWidth)
m_columnMaxWidth[dataCol] = (int) Math.ceil(dynMxColumnWidth);
else if (colWidth < width)
colWidth = width;
headerSizes[dataCol] = new Dimension2DImpl(width, height);
}
// Width limitations
if (m_columnMaxWidth[dataCol] != 0 && m_columnMaxWidth[dataCol] != -1) {
float height = 0;
//
String[] lines = Pattern.compile("$", Pattern.MULTILINE).split(string);
for (int lineNo = 0; lineNo < lines.length; lineNo++) {
AttributedString aString = new AttributedString(lines[lineNo]);
aString.addAttribute(TextAttribute.FONT, font);
AttributedCharacterIterator iter = aString.getIterator();
LineBreakMeasurer measurer = new LineBreakMeasurer(iter, frc);
colWidth = Math.abs(m_columnMaxWidth[dataCol]);
while (measurer.getPosition() < iter.getEndIndex()) {
TextLayout layout = measurer.nextLayout(colWidth);
float lineHeight = layout.getAscent() + layout.getDescent() + layout.getLeading();
if (// one line only
!m_multiLineHeader) {
height = lineHeight;
break;
} else
/*if (m_columnMaxHeight[dataCol] == 0
|| (height + lineHeight) <= m_columnMaxHeight[dataCol])*/
height += lineHeight;
}
}
// for all header lines
headerSizes[dataCol] = new Dimension2DImpl(colWidth, height);
}
}
// headerSize
headerSizes[dataCol].roundUp();
colWidth = (float) Math.ceil(colWidth);
// Round Column Width
if (dataCol == 0)
colWidth += m_tFormat.getVLineStroke().floatValue();
if (colWidth != 0)
colWidth += (2 * H_GAP) + m_tFormat.getVLineStroke().floatValue();
// Print below existing column
if (col != dataCol) {
// for the data column
m_columnWidths.add(new Float(0.0));
Float origWidth = (Float) m_columnWidths.get(col);
if (origWidth == null)
log.log(Level.SEVERE, "Column " + dataCol + " below " + col + " - no value for orig width");
else {
if (origWidth.compareTo(new Float(colWidth)) >= 0) {
log.finest("Same Width - Col=" + col + " - OrigWidth=" + origWidth + " - Width=" + colWidth + " - Total=" + p_width);
} else {
m_columnWidths.set(col, new Float(colWidth));
p_width += (colWidth - origWidth.floatValue());
log.finest("New Width - Col=" + col + " - OrigWidth=" + origWidth + " - Width=" + colWidth + " - Total=" + p_width);
}
}
} else // Add new Column
{
m_columnWidths.add(new Float(colWidth));
p_width += colWidth;
log.finest("Width - Col=" + dataCol + " - Width=" + colWidth + " - Total=" + p_width);
}
}
// for all columns
// Height **********
p_height = 0;
for (int row = 0; row < rows; row++) {
float rowHeight = 0f;
for (int col = 0; col < cols; col++) {
if (// max
dataSizes[row][col].height > rowHeight)
rowHeight = (float) dataSizes[row][col].height;
}
// for all columns
rowHeight += m_tFormat.getLineStroke().floatValue() + (2 * V_GAP);
m_rowHeights.add(new Float(rowHeight));
p_height += rowHeight;
}
// for all rows
// HeaderRow
m_headerHeight = 0;
for (int col = 0; col < cols; col++) {
if (headerSizes[col].height > m_headerHeight)
m_headerHeight = (int) headerSizes[col].height;
}
// for all columns
// Thick lines
m_headerHeight += (4 * m_tFormat.getLineStroke().floatValue()) + (2 * V_GAP);
p_height += m_headerHeight;
// Last row Lines
// last fat line
p_height += m_tFormat.getLineStroke().floatValue();
// Page Layout *******************************************************
log.fine("FirstPage=" + m_firstPage + ", NextPages=" + m_nextPages);
// One Page on Y | Axis
if (m_firstPage.height >= p_height && m_pageBreak.size() == 0) {
log.finest("Page Y=1 - PageHeight=" + m_firstPage.height + " - TableHeight=" + p_height);
// Y
m_firstRowOnPage.add(new Integer(0));
// Y index only
m_pageHeight.add(new Float(p_height));
} else // multiple pages on Y | Axis
{
float availableHeight = 0f;
float usedHeight = 0f;
boolean firstPage = true;
int addlRows = 0;
// for all rows
for (int dataRow = 0; dataRow < m_rowHeights.size(); dataRow++) {
float rowHeight = ((Float) m_rowHeights.get(dataRow)).floatValue();
// Y page break before
boolean pageBreak = isPageBreak(dataRow);
//adjust for lastrow
if (dataRow + 1 == m_rowHeights.size()) {
availableHeight -= m_tFormat.getLineStroke().floatValue();
}
if (!pageBreak && availableHeight < rowHeight) {
if (availableHeight > 40 && rowHeight > 40) {
log.finest("- Split (leave on current) Row=" + dataRow + " - Available=" + availableHeight + ", RowHeight=" + rowHeight);
// if (splitRow (dataRow))
// addlRows += 1;
}
// else
pageBreak = true;
}
if (pageBreak) {
availableHeight = firstPage ? m_firstPage.height : m_nextPages.height;
// Y
m_firstRowOnPage.add(new Integer(dataRow + addlRows));
if (!firstPage) {
// Y index only
m_pageHeight.add(new Float(usedHeight));
log.finest("Page Y=" + m_pageHeight.size() + " - PageHeight=" + usedHeight);
}
log.finest("Page Y=" + m_firstRowOnPage.size() + " - Row=" + dataRow + " - force=" + isPageBreak(dataRow));
firstPage = false;
//
availableHeight -= m_headerHeight;
usedHeight += m_headerHeight;
}
availableHeight -= rowHeight;
usedHeight += rowHeight;
if (availableHeight < 0) {
log.finest("- Split (move to next) Row=" + dataRow + " - Available=" + availableHeight + ", RowHeight=" + rowHeight);
}
log.finest("Page Y=" + m_pageHeight.size() + ", Row=" + dataRow + ",AddlRows=" + addlRows + ", Height=" + rowHeight + " - Available=" + availableHeight + ", Used=" + usedHeight);
}
// for all rows
// Y index only
m_pageHeight.add(new Float(usedHeight));
log.finest("Page Y=" + m_pageHeight.size() + " - PageHeight=" + usedHeight);
}
// One page on - X Axis
if (m_firstPage.width >= p_width) {
log.finest("Page X=1 - PageWidth=" + m_firstPage.width + " - TableWidth=" + p_width);
// X
m_firstColumnOnPage.add(new Integer(0));
//
distributeColumns(m_firstPage.width - (int) p_width, 0, m_columnWidths.size());
} else // multiple pages on - X Axis
{
int availableWidth = 0;
int lastStart = 0;
for (int col = 0; col < m_columnWidths.size(); col++) {
int columnWidth = ((Float) m_columnWidths.get(col)).intValue();
// X page preak
if (availableWidth < columnWidth) {
if (col != 0)
distributeColumns(availableWidth, lastStart, col);
//
// X
m_firstColumnOnPage.add(new Integer(col));
log.finest("Page X=" + m_firstColumnOnPage.size() + " - Col=" + col);
lastStart = col;
// Width is the same on all pages
availableWidth = m_firstPage.width;
//
for (int repCol = 0; repCol < m_repeatedColumns && col > repCol; repCol++) {
float repColumnWidth = ((Float) m_columnWidths.get(repCol)).floatValue();
// leave 50% of space available for non repeated columns
if (availableWidth < m_firstPage.width * 0.5)
break;
availableWidth -= repColumnWidth;
}
}
// pageBreak
availableWidth -= columnWidth;
}
// for acc columns
}
// multiple - X pages
log.fine("Pages=" + getPageCount() + " X=" + m_firstColumnOnPage.size() + "/Y=" + m_firstRowOnPage.size() + " - Width=" + p_width + ", Height=" + p_height);
return true;
}
use of java.awt.font.FontRenderContext in project android_frameworks_base by ResurrectionRemix.
the class BidiRenderer method render.
/**
* Renders the text to the right of the bounds with the given font.
* @param font The font to render the text with.
*/
private void render(int start, int limit, Font font, int flag, float[] advances, int advancesIndex, boolean draw) {
FontRenderContext frc;
if (mGraphics != null) {
frc = mGraphics.getFontRenderContext();
} else {
frc = Toolkit.getDefaultToolkit().getFontMetrics(font).getFontRenderContext();
// Metrics obtained this way don't have anti-aliasing set. So,
// we create a new FontRenderContext with anti-aliasing set.
frc = new FontRenderContext(font.getTransform(), mPaint.isAntiAliased(), frc.usesFractionalMetrics());
}
GlyphVector gv = font.layoutGlyphVector(frc, mText, start, limit, flag);
int ng = gv.getNumGlyphs();
int[] ci = gv.getGlyphCharIndices(0, ng, null);
if (advances != null) {
for (int i = 0; i < ng; i++) {
int adv_idx = advancesIndex + ci[i];
advances[adv_idx] += gv.getGlyphMetrics(i).getAdvanceX();
}
}
if (draw && mGraphics != null) {
mGraphics.drawGlyphVector(gv, mBounds.right, mBaseline);
}
// Update the bounds.
Rectangle2D awtBounds = gv.getLogicalBounds();
RectF bounds = awtRectToAndroidRect(awtBounds, mBounds.right, mBaseline);
// coordinates from the bounds as an offset.
if (Math.abs(mBounds.right - mBounds.left) == 0) {
mBounds = bounds;
} else {
mBounds.union(bounds);
}
}
use of java.awt.font.FontRenderContext in project JMRI by JMRI.
the class FontComboUtil method prepareFontLists.
/**
* Method to initialise the font lists on first access
*/
@SuppressFBWarnings(value = "FE_FLOATING_POINT_EQUALITY", justification = "font sizes are really quantized")
public static synchronized void prepareFontLists() {
if (prepared) {
// Normally we shouldn't get here except when the initialisation
// thread has taken a bit longer than normal.
log.debug("Subsequent call - no need to prepare");
return;
}
log.debug("Prepare font lists...");
// Initialise the font lists
monospaced = new ArrayList<>();
proportional = new ArrayList<>();
character = new ArrayList<>();
symbol = new ArrayList<>();
all = new ArrayList<>();
// Create a font render context to use for the comparison
FontRenderContext frc = new FontRenderContext(null, false, false);
// Loop through all available font families
for (String s : GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()) {
// Add to the 'all' fonts list
all.add(s);
// Retrieve a plain version of the current font family
Font f = new Font(s, Font.PLAIN, 12);
// Check that a few different characters can be displayed
if (f.canDisplay('F') && f.canDisplay('b') && f.canDisplay('8')) {
// It's not a symbol font - add to the character font list
character.add(s);
// Check if the widths of a 'narrow' letter (I)
// a 'wide' letter (W) and a 'space' ( ) are the same.
double w;
// next line is the FE_FLOATING_POINT_EQUALITY annotated above
if (f.getStringBounds("I", frc).getWidth() == (w = f.getStringBounds("W", frc).getWidth()) && w == f.getStringBounds(" ", frc).getWidth()) {
// Yes, they're all the same width - add to the monospaced list
monospaced.add(s);
} else {
// No, they're different widths - add to the proportional list
proportional.add(s);
}
} else {
// It's a symbol font - add to the symbol font list
symbol.add(s);
}
}
log.debug("...font lists built");
prepared = true;
}
use of java.awt.font.FontRenderContext 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;
}
use of java.awt.font.FontRenderContext in project jdk8u_jdk by JetBrains.
the class X11TextRenderer method drawGlyphVector.
/*
* Override super class method to call the AA pipe if
* AA is specified in the GlyphVector's FontRenderContext
*/
public void drawGlyphVector(SunGraphics2D sg2d, GlyphVector g, float x, float y) {
FontRenderContext frc = g.getFontRenderContext();
FontInfo info = sg2d.getGVFontInfo(g.getFont(), frc);
switch(info.aaHint) {
case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
super.drawGlyphVector(sg2d, g, x, y);
return;
case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
sg2d.surfaceData.aaTextRenderer.drawGlyphVector(sg2d, g, x, y);
return;
case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
sg2d.surfaceData.lcdTextRenderer.drawGlyphVector(sg2d, g, x, y);
return;
default:
}
}
Aggregations