Search in sources :

Example 1 with CompositeFont

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;
}
Also used : CompositeFont(sun.font.CompositeFont) FontUIResource(javax.swing.plaf.FontUIResource)

Example 2 with CompositeFont

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>,&nbsp;<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,&nbsp;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);
    }
}
Also used : TrueTypeFont(sun.font.TrueTypeFont) CompositeFont(sun.font.CompositeFont) Font2D(sun.font.Font2D) Rectangle2D(java.awt.geom.Rectangle2D) TextLayout(java.awt.font.TextLayout) Point2D(java.awt.geom.Point2D) PhysicalFont(sun.font.PhysicalFont) AffineTransform(java.awt.geom.AffineTransform)

Example 3 with CompositeFont

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;
    }
}
Also used : CompositeFont(sun.font.CompositeFont) TrueTypeFont(sun.font.TrueTypeFont) Font2D(sun.font.Font2D) AffineTransform(java.awt.geom.AffineTransform)

Example 4 with CompositeFont

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;
}
Also used : TrueTypeFont(sun.font.TrueTypeFont) CompositeFont(sun.font.CompositeFont) Font2D(sun.font.Font2D) TrueTypeFont(sun.font.TrueTypeFont) CompositeFont(sun.font.CompositeFont) Font(java.awt.Font) PhysicalFont(sun.font.PhysicalFont) Point2D(java.awt.geom.Point2D) PhysicalFont(sun.font.PhysicalFont) AffineTransform(java.awt.geom.AffineTransform)

Example 5 with CompositeFont

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;
}
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)

Aggregations

CompositeFont (sun.font.CompositeFont)5 AffineTransform (java.awt.geom.AffineTransform)4 Font2D (sun.font.Font2D)4 Point2D (java.awt.geom.Point2D)3 TrueTypeFont (sun.font.TrueTypeFont)3 Font (java.awt.Font)2 Rectangle2D (java.awt.geom.Rectangle2D)2 PhysicalFont (sun.font.PhysicalFont)2 Paint (java.awt.Paint)1 FontRenderContext (java.awt.font.FontRenderContext)1 GlyphVector (java.awt.font.GlyphVector)1 TextAttribute (java.awt.font.TextAttribute)1 TextLayout (java.awt.font.TextLayout)1 RoundRectangle2D (java.awt.geom.RoundRectangle2D)1 Hashtable (java.util.Hashtable)1 FontUIResource (javax.swing.plaf.FontUIResource)1 Font2DHandle (sun.font.Font2DHandle)1