Search in sources :

Example 61 with FontRenderContext

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;
}
Also used : ArrayList(java.util.ArrayList) LineBreakMeasurer(java.awt.font.LineBreakMeasurer) AttributedString(java.text.AttributedString) Font(java.awt.Font) AttributedString(java.text.AttributedString) NamePair(org.compiere.util.NamePair) ValueNamePair(org.compiere.util.ValueNamePair) KeyNamePair(org.compiere.util.KeyNamePair) Dimension(java.awt.Dimension) Point(java.awt.Point) Point(java.awt.Point) TextLayout(java.awt.font.TextLayout) AttributedCharacterIterator(java.text.AttributedCharacterIterator) FontRenderContext(java.awt.font.FontRenderContext)

Example 62 with FontRenderContext

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);
    }
}
Also used : GlyphVector(java.awt.font.GlyphVector) Rectangle2D(java.awt.geom.Rectangle2D) FontRenderContext(java.awt.font.FontRenderContext)

Example 63 with FontRenderContext

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;
}
Also used : FontRenderContext(java.awt.font.FontRenderContext) Font(java.awt.Font) SuppressFBWarnings(edu.umd.cs.findbugs.annotations.SuppressFBWarnings)

Example 64 with FontRenderContext

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;
}
Also used : Font2D(sun.font.Font2D) TextAttribute(java.awt.font.TextAttribute) Font(java.awt.Font) CompositeFont(sun.font.CompositeFont) Point2D(java.awt.geom.Point2D) Font2DHandle(sun.font.Font2DHandle) CompositeFont(sun.font.CompositeFont) GlyphVector(java.awt.font.GlyphVector) Hashtable(java.util.Hashtable) Rectangle2D(java.awt.geom.Rectangle2D) RoundRectangle2D(java.awt.geom.RoundRectangle2D) Paint(java.awt.Paint) AffineTransform(java.awt.geom.AffineTransform) FontRenderContext(java.awt.font.FontRenderContext)

Example 65 with FontRenderContext

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:
    }
}
Also used : FontRenderContext(java.awt.font.FontRenderContext) FontInfo(sun.java2d.loops.FontInfo)

Aggregations

FontRenderContext (java.awt.font.FontRenderContext)79 Font (java.awt.Font)27 TextLayout (java.awt.font.TextLayout)25 GlyphVector (java.awt.font.GlyphVector)18 Graphics2D (java.awt.Graphics2D)17 Rectangle2D (java.awt.geom.Rectangle2D)17 AttributedString (java.text.AttributedString)14 AffineTransform (java.awt.geom.AffineTransform)13 Paint (java.awt.Paint)8 LineBreakMeasurer (java.awt.font.LineBreakMeasurer)7 AttributedCharacterIterator (java.text.AttributedCharacterIterator)7 Color (java.awt.Color)5 Shape (java.awt.Shape)5 LineMetrics (java.awt.font.LineMetrics)5 BufferedImage (java.awt.image.BufferedImage)5 ArrayList (java.util.ArrayList)5 Point (java.awt.Point)4 BasicStroke (java.awt.BasicStroke)3 FontMetrics (java.awt.FontMetrics)3 Rectangle (java.awt.Rectangle)3