1896 lines · 75.9 KB · Java
RawDownload
         draw(new Polygon(xPoints, yPoints, nPoints));    }     /**     * Draws the outline of a polygon defined by the specified     * <code>Polygon</code> object.     * @param        p the polygon to draw.     * @see          java.awt.Graphics#fillPolygon     * @see          java.awt.Graphics#drawPolyline     */    public void drawPolygon(Polygon p) {        draw(p);    }      /**     * Fills a closed polygon defined by     * arrays of <i>x</i> and <i>y</i> coordinates.     * <p>     * This method draws the polygon defined by <code>nPoint</code> line     * segments, where the first <code>nPoint&nbsp;-&nbsp;1</code>     * line segments are line segments from     * <code>(xPoints[i&nbsp;-&nbsp;1],&nbsp;yPoints[i&nbsp;-&nbsp;1])</code>     * to <code>(xPoints[i],&nbsp;yPoints[i])</code>, for     * 1&nbsp;&le;&nbsp;<i>i</i>&nbsp;&le;&nbsp;<code>nPoints</code>.     * The figure is automatically closed by drawing a line connecting     * the final point to the first point, if those points are different.     * <p>     * The area inside the polygon is defined using an     * even-odd fill rule, also known as the alternating rule.     * @param        xPoints   a an array of <code>x</code> coordinates.     * @param        yPoints   a an array of <code>y</code> coordinates.     * @param        nPoints   a the total number of points.     * @see          java.awt.Graphics#drawPolygon(int[], int[], int)     */    public void fillPolygon(int xPoints[], int yPoints[],                            int nPoints) {         fill(new Polygon(xPoints, yPoints, nPoints));    }      /**     * Fills the polygon defined by the specified Polygon object with     * the graphics context's current color.     * <p>     * The area inside the polygon is defined using an     * even-odd fill rule, also known as the alternating rule.     * @param        p the polygon to fill.     * @see          java.awt.Graphics#drawPolygon(int[], int[], int)     */    public void fillPolygon(Polygon p) {         fill(p);    }     /**     * Draws the text given by the specified string, using this     * graphics context's current font and color. The baseline of the     * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in this     * graphics context's coordinate system.     * @param       str      the string to be drawn.     * @param       x        the <i>x</i> coordinate.     * @param       y        the <i>y</i> coordinate.     * @see         java.awt.Graphics#drawBytes     * @see         java.awt.Graphics#drawChars     * @since       JDK1.0     */    public void drawString(String str, int x, int y) {        drawString(str, (float) x, (float) y);    }     public void drawString(String str, float x, float y) {        if (str.length() == 0) {            return;        }        TextLayout layout =            new TextLayout(str, getFont(), getFontRenderContext());        layout.draw(this, x, y);    }     protected void drawString(String str, float x, float y,                              Font font, FontRenderContext frc, float w) {        TextLayout layout =            new TextLayout(str, font, frc);        Shape textShape =            layout.getOutline(AffineTransform.getTranslateInstance(x, y));        fill(textShape);    }     /**     * Draws the text given by the specified iterator, using this     * graphics context's current color. The iterator has to specify a font     * for each character. The baseline of the     * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in this     * graphics context's coordinate system.     * @param       iterator the iterator whose text is to be drawn     * @param       x        the <i>x</i> coordinate.     * @param       y        the <i>y</i> coordinate.     * @see         java.awt.Graphics#drawBytes     * @see         java.awt.Graphics#drawChars     */    public void drawString(AttributedCharacterIterator iterator,                           int x, int y) {        drawString(iterator, (float) x, (float) y);    }    public void drawString(AttributedCharacterIterator iterator,                           float x, float y) {        if (iterator == null) {            throw                new NullPointerException("attributedcharacteriterator is null");        }        TextLayout layout =            new TextLayout(iterator, getFontRenderContext());        layout.draw(this, x, y);    }     /**     * Draws a GlyphVector.     * The rendering attributes applied include the clip, transform,     * paint or color, and composite attributes.  The GlyphVector specifies     * individual glyphs from a Font.     * @param g The GlyphVector to be drawn.     * @param x,y The coordinates where the glyphs should be drawn.     * @see #setPaint     * @see java.awt.Graphics#setColor     * @see #transform     * @see #setTransform     * @see #setComposite     * @see #clip     * @see #setClip     */    public void drawGlyphVector(GlyphVector g,                                float x,                                float y) {         /* We should not reach here if printingGlyphVector is already true.         * Add an assert so this can be tested if need be.         * But also ensure that we do at least render properly by filling         * the outline.         */        if (printingGlyphVector) {            assert !printingGlyphVector; // ie false.            fill(g.getOutline(x, y));            return;        }         try {            printingGlyphVector = true;            if (RasterPrinterJob.shapeTextProp ||                !printedSimpleGlyphVector(g, x, y)) {                fill(g.getOutline(x, y));            }        } finally {            printingGlyphVector = false;        }    }     protected static SoftReference<Hashtable<Font2DHandle,Object>>        fontMapRef = new SoftReference<Hashtable<Font2DHandle,Object>>(null);     protected int platformFontCount(Font font, String str) {        return 0;    }     /**     * Default implementation returns false.     * Callers of this method must always be prepared for this,     * and delegate to outlines or some other solution.     */    protected boolean printGlyphVector(GlyphVector gv, float x, float y) {        return false;    }     /* 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;    }     /* The same codes must be in the same positions for this to return true.     * This would look cleaner if it took the original GV as a parameter but     * we already have the codes and will need to get the positions array     * too in most cases anyway. So its cheaper to pass them in.     * This call wouldn't be necessary if layout didn't always set the     * FLAG_HAS_POSITION_ADJUSTMENTS even if the default advances are used     * and there was no re-ordering (this should be fixed some day).     */    private boolean samePositions(GlyphVector gv, int[] gvcodes,                                  int[] origCodes, float[] origPositions) {         int numGlyphs = gv.getNumGlyphs();        float[] gvpos = gv.getGlyphPositions(0, numGlyphs, null);         /* this shouldn't happen here, but just in case */        if (numGlyphs != gvcodes.length ||  /* real paranoia here */            origCodes.length != gvcodes.length ||            origPositions.length != gvpos.length) {            return false;        }         for (int i=0; i<numGlyphs; i++) {            if (gvcodes[i] != origCodes[i] || gvpos[i] != origPositions[i]) {                return false;            }        }        return true;    }     protected boolean canDrawStringToWidth() {        return false;    }     /* return an array which can map glyphs back to char codes.     * Glyphs which aren't mapped from a simple unicode code point     * will have no mapping in this array, and will be assumed to be

Lines 501–1000 of 1896. Previous lines