3310 lines · 121.6 KB · Java
RawDownload
     private static final int MINALLOCATED = 8;    private static final int TEXTARRSIZE = 17;    private static double[][] textTxArr = new double[TEXTARRSIZE][];    private static AffineTransform[] textAtArr =        new AffineTransform[TEXTARRSIZE];     static {        for (int i=MINALLOCATED;i<TEXTARRSIZE;i++) {          textTxArr[i] = new double [] {i, 0, 0, i};          textAtArr[i] = new AffineTransform( textTxArr[i]);        }    }     // cached state for various draw[String,Char,Byte] optimizations    public FontInfo checkFontInfo(FontInfo info, Font font,                                  FontRenderContext frc) {        /* Do not create a FontInfo object as part of construction of an         * SG2D as its possible it may never be needed - ie if no text         * is drawn using this SG2D.         */        if (info == null) {            info = new FontInfo();        }         float ptSize = font.getSize2D();        int txFontType;        AffineTransform devAt, textAt=null;        if (font.isTransformed()) {            textAt = font.getTransform();            textAt.scale(ptSize, ptSize);            txFontType = textAt.getType();            info.originX = (float)textAt.getTranslateX();            info.originY = (float)textAt.getTranslateY();            textAt.translate(-info.originX, -info.originY);            if (transformState >= TRANSFORM_TRANSLATESCALE) {                transform.getMatrix(info.devTx = new double[4]);                devAt = new AffineTransform(info.devTx);                textAt.preConcatenate(devAt);            } else {                info.devTx = IDENT_MATRIX;                devAt = IDENT_ATX;            }            textAt.getMatrix(info.glyphTx = new double[4]);            double shearx = textAt.getShearX();            double scaley = textAt.getScaleY();            if (shearx != 0) {                scaley = Math.sqrt(shearx * shearx + scaley * scaley);            }            info.pixelHeight = (int)(Math.abs(scaley)+0.5);        } else {            txFontType = AffineTransform.TYPE_IDENTITY;            info.originX = info.originY = 0;            if (transformState >= TRANSFORM_TRANSLATESCALE) {                transform.getMatrix(info.devTx = new double[4]);                devAt = new AffineTransform(info.devTx);                info.glyphTx = new double[4];                for (int i = 0; i < 4; i++) {                    info.glyphTx[i] = info.devTx[i] * ptSize;                }                textAt = new AffineTransform(info.glyphTx);                double shearx = transform.getShearX();                double scaley = transform.getScaleY();                if (shearx != 0) {                    scaley = Math.sqrt(shearx * shearx + scaley * scaley);                }                info.pixelHeight = (int)(Math.abs(scaley * ptSize)+0.5);            } else {                /* If the double represents a common integral, we                 * may have pre-allocated objects.                 * A "sparse" array be seems to be as fast as a switch                 * even for 3 or 4 pt sizes, and is more flexible.                 * This should perform comparably in single-threaded                 * rendering to the old code which synchronized on the                 * class and scale better on MP systems.                 */                int pszInt = (int)ptSize;                if (ptSize == pszInt &&                    pszInt >= MINALLOCATED && pszInt < TEXTARRSIZE) {                    info.glyphTx = textTxArr[pszInt];                    textAt = textAtArr[pszInt];                    info.pixelHeight = pszInt;                } else {                    info.pixelHeight = (int)(ptSize+0.5);                }                if (textAt == null) {                    info.glyphTx = new double[] {ptSize, 0, 0, ptSize};                    textAt = new AffineTransform(info.glyphTx);                }                 info.devTx = IDENT_MATRIX;                devAt = IDENT_ATX;            }        }         info.font2D = FontUtilities.getFont2D(font);         int fmhint = fractionalMetricsHint;        if (fmhint == SunHints.INTVAL_FRACTIONALMETRICS_DEFAULT) {            fmhint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;        }        info.lcdSubPixPos = false; // conditionally set true in LCD mode.         /* The text anti-aliasing hints that are set by the client need         * to be interpreted for the current state and stored in the         * FontInfo.aahint which is what will actually be used and         * will be one of OFF, ON, LCD_HRGB or LCD_VRGB.         * This is what pipe selection code should typically refer to, not         * textAntialiasHint. This means we are now evaluating the meaning         * of "default" here. Any pipe that really cares about that will         * also need to consult that variable.         * Otherwise these are being used only as args to getStrike,         * and are encapsulated in that object which is part of the         * FontInfo, so we do not need to store them directly as fields         * in the FontInfo object.         * That could change if FontInfo's were more selectively         * revalidated when graphics state changed. Presently this         * method re-evaluates all fields in the fontInfo.         * The strike doesn't need to know the RGB subpixel order. Just         * if its H or V orientation, so if an LCD option is specified we         * always pass in the RGB hint to the strike.         * frc is non-null only if this is a GlyphVector. For reasons         * which are probably a historical mistake the AA hint in a GV         * is honoured when we render, overriding the Graphics setting.         */        int aahint;        if (frc == null) {            aahint = textAntialiasHint;        } else {            aahint = ((SunHints.Value)frc.getAntiAliasingHint()).getIndex();        }        if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT) {            if (antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {                aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;            } else {                aahint = SunHints.INTVAL_TEXT_ANTIALIAS_OFF;            }        } else {            /* If we are in checkFontInfo because a rendering hint has been             * set then all pipes are revalidated. But we can also             * be here because setFont() has been called when the 'gasp'             * hint is set, as then the font size determines the text pipe.             * See comments in SunGraphics2d.setFont(Font).             */            if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_GASP) {                if (info.font2D.useAAForPtSize(info.pixelHeight)) {                    aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;                } else {                    aahint = SunHints.INTVAL_TEXT_ANTIALIAS_OFF;                }            } else if (aahint >= SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB) {                /* loops for default rendering modes are installed in the SG2D                 * constructor. If there are none this will be null.                 * Not all compositing modes update the render loops, so                 * we also test that this is a mode we know should support                 * this. One minor issue is that the loops aren't necessarily                 * installed for a new rendering mode until after this                 * method is called during pipeline validation. So it is                 * theoretically possible that it was set to null for a                 * compositing mode, the composite is then set back to Src,                 * but the loop is still null when this is called and AA=ON                 * is installed instead of an LCD mode.                 * However this is done in the right order in SurfaceData.java                 * so this is not likely to be a problem - but not                 * guaranteed.                 */                if (                    !surfaceData.canRenderLCDText(this)//                    loops.drawGlyphListLCDLoop == null ||//                    compositeState > COMP_ISCOPY ||//                    paintState > PAINT_ALPHACOLOR                      ) {                    aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;                } else {                    info.lcdRGBOrder = true;                    /* Collapse these into just HRGB or VRGB.                     * Pipe selection code needs only to test for these two.                     * Since these both select the same pipe anyway its                     * tempting to collapse into one value. But they are                     * different strikes (glyph caches) so the distinction                     * needs to be made for that purpose.                     */                    if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HBGR) {                        aahint = SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB;                        info.lcdRGBOrder = false;                    } else if                        (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VBGR) {                        aahint = SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB;                        info.lcdRGBOrder = false;                    }                    /* Support subpixel positioning only for the case in                     * which the horizontal resolution is increased                     */                    info.lcdSubPixPos =                        fmhint == SunHints.INTVAL_FRACTIONALMETRICS_ON &&                        aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB;                }            }        }        info.aaHint = aahint;        info.fontStrike = info.font2D.getStrike(font, devAt, textAt,                                                aahint, fmhint);        return info;    }     public static boolean isRotated(double [] mtx) {        if ((mtx[0] == mtx[3]) &&            (mtx[1] == 0.0) &&            (mtx[2] == 0.0) &&            (mtx[0] > 0.0))        {            return false;        }         return true;    }     public void setFont(Font font) {        /* replacing the reference equality test font != this.font with         * !font.equals(this.font) did not yield any measurable difference         * in testing, but there may be yet to be identified cases where it         * is beneficial.         */        if (font != null && font!=this.font/*!font.equals(this.font)*/) {            /* In the GASP AA case the textpipe depends on the glyph size             * as determined by graphics and font transforms as well as the             * font size, and information in the font. But we may invalidate             * the pipe only to find that it made no difference.             * Deferring pipe invalidation to checkFontInfo won't work because             * when called we may already be rendering to the wrong pipe.             * So, if the font is transformed, or the graphics has more than             * a simple scale, we'll take that as enough of a hint to             * revalidate everything. But if they aren't we will             * use the font's point size to query the gasp table and see if             * what it says matches what's currently being used, in which             * case there's no need to invalidate the textpipe.             * This should be sufficient for all typical uses cases.             */            if (textAntialiasHint == SunHints.INTVAL_TEXT_ANTIALIAS_GASP &&                textpipe != invalidpipe &&                (transformState > TRANSFORM_ANY_TRANSLATE ||                 font.isTransformed() ||                 fontInfo == null || // Precaution, if true shouldn't get here                 (fontInfo.aaHint == SunHints.INTVAL_TEXT_ANTIALIAS_ON) !=                     FontUtilities.getFont2D(font).                         useAAForPtSize(font.getSize()))) {                textpipe = invalidpipe;            }            this.font = font;            this.fontMetrics = null;            this.validFontInfo = false;        }    }     public FontInfo getFontInfo() {        if (!validFontInfo) {            this.fontInfo = checkFontInfo(this.fontInfo, font, null);            validFontInfo = true;        }        return this.fontInfo;    }     /* Used by drawGlyphVector which specifies its own font. */    public FontInfo getGVFontInfo(Font font, FontRenderContext frc) {        if (glyphVectorFontInfo != null &&            glyphVectorFontInfo.font == font &&            glyphVectorFRC == frc) {            return glyphVectorFontInfo;        } else {            glyphVectorFRC = frc;            return glyphVectorFontInfo =                checkFontInfo(glyphVectorFontInfo, font, frc);        }    }     public FontMetrics getFontMetrics() {        if (this.fontMetrics != null) {            return this.fontMetrics;        }        /* NB the constructor and the setter disallow "font" being null */        return this.fontMetrics =           FontDesignMetrics.getMetrics(font, getFontRenderContext());    }     public FontMetrics getFontMetrics(Font font) {        if ((this.fontMetrics != null) && (font == this.font)) {            return this.fontMetrics;        }        FontMetrics fm =          FontDesignMetrics.getMetrics(font, getFontRenderContext());         if (this.font == font) {            this.fontMetrics = fm;        }        return fm;    }     /**     * Checks to see if a Path intersects the specified Rectangle in device     * space.  The rendering attributes taken into account include the     * clip, transform, and stroke attributes.     * @param rect The area in device space to check for a hit.     * @param p The path to check for a hit.     * @param onStroke Flag to choose between testing the stroked or     * the filled path.     * @return True if there is a hit, false otherwise.     * @see #setStroke     * @see #fillPath     * @see #drawPath     * @see #transform     * @see #setTransform     * @see #clip     * @see #setClip     */    public boolean hit(Rectangle rect, Shape s, boolean onStroke) {        if (onStroke) {            s = stroke.createStrokedShape(s);        }         s = transformShape(s);        if ((constrainX|constrainY) != 0) {            rect = new Rectangle(rect);            rect.translate(constrainX, constrainY);        }         return s.intersects(rect);    }     /**     * Return the ColorModel associated with this Graphics2D.     */    public ColorModel getDeviceColorModel() {        return surfaceData.getColorModel();    }     /**     * Return the device configuration associated with this Graphics2D.     */    public GraphicsConfiguration getDeviceConfiguration() {        return surfaceData.getDeviceConfiguration();    }     /**     * Return the SurfaceData object assigned to manage the destination     * drawable surface of this Graphics2D.     */    public final SurfaceData getSurfaceData() {        return surfaceData;    }     /**     * Sets the Composite in the current graphics state. Composite is used     * in all drawing methods such as drawImage, drawString, drawPath,     * and fillPath.  It specifies how new pixels are to be combined with     * the existing pixels on the graphics device in the rendering process.     * @param comp The Composite object to be used for drawing.     * @see java.awt.Graphics#setXORMode     * @see java.awt.Graphics#setPaintMode     * @see AlphaComposite     */    public void setComposite(Composite comp) {        if (composite == comp) {            return;        }        int newCompState;        CompositeType newCompType;        if (comp instanceof AlphaComposite) {            AlphaComposite alphacomp = (AlphaComposite) comp;            newCompType = CompositeType.forAlphaComposite(alphacomp);            if (newCompType == CompositeType.SrcOverNoEa) {                if (paintState == PAINT_OPAQUECOLOR ||                    (paintState > PAINT_ALPHACOLOR &&                     paint.getTransparency() == Transparency.OPAQUE))                {                    newCompState = COMP_ISCOPY;                } else {                    newCompState = COMP_ALPHA;                }            } else if (newCompType == CompositeType.SrcNoEa ||                       newCompType == CompositeType.Src ||                       newCompType == CompositeType.Clear)            {                newCompState = COMP_ISCOPY;            } else if (surfaceData.getTransparency() == Transparency.OPAQUE &&                       newCompType == CompositeType.SrcIn)            {                newCompState = COMP_ISCOPY;            } else {                newCompState = COMP_ALPHA;            }        } else if (comp instanceof XORComposite) {            newCompState = COMP_XOR;            newCompType = CompositeType.Xor;        } else if (comp == null) {            throw new IllegalArgumentException("null Composite");        } else {            surfaceData.checkCustomComposite();            newCompState = COMP_CUSTOM;            newCompType = CompositeType.General;        }        if (compositeState != newCompState ||            imageComp != newCompType)        {            compositeState = newCompState;            imageComp = newCompType;            invalidatePipe();            validFontInfo = false;        }        composite = comp;        if (paintState <= PAINT_ALPHACOLOR) {            validateColor();        }    }     /**     * Sets the Paint in the current graphics state.     * @param paint The Paint object to be used to generate color in     * the rendering process.     * @see java.awt.Graphics#setColor     * @see GradientPaint     * @see TexturePaint     */    public void setPaint(Paint paint) {        if (paint instanceof Color) {            setColor((Color) paint);            return;        }        if (paint == null || this.paint == paint) {            return;        }        this.paint = paint;        if (imageComp == CompositeType.SrcOverNoEa) {            // special case where compState depends on opacity of paint            if (paint.getTransparency() == Transparency.OPAQUE) {                if (compositeState != COMP_ISCOPY) {                    compositeState = COMP_ISCOPY;                }            } else {                if (compositeState == COMP_ISCOPY) {                    compositeState = COMP_ALPHA;                }            }        }        Class paintClass = paint.getClass();        if (paintClass == GradientPaint.class) {            paintState = PAINT_GRADIENT;        } else if (paintClass == LinearGradientPaint.class) {            paintState = PAINT_LIN_GRADIENT;        } else if (paintClass == RadialGradientPaint.class) {            paintState = PAINT_RAD_GRADIENT;        } else if (paintClass == TexturePaint.class) {            paintState = PAINT_TEXTURE;        } else {            paintState = PAINT_CUSTOM;        }        validFontInfo = false;        invalidatePipe();    }     static final int NON_UNIFORM_SCALE_MASK =        (AffineTransform.TYPE_GENERAL_TRANSFORM |         AffineTransform.TYPE_GENERAL_SCALE);    public static final double MinPenSizeAA =        sun.java2d.pipe.RenderingEngine.getInstance().getMinimumAAPenSize();    public static final double MinPenSizeAASquared =        (MinPenSizeAA * MinPenSizeAA);    // Since inaccuracies in the trig package can cause us to    // calculated a rotated pen width of just slightly greater    // than 1.0, we add a fudge factor to our comparison value    // here so that we do not misclassify single width lines as    // wide lines under certain rotations.    public static final double MinPenSizeSquared = 1.000000001;     private void validateBasicStroke(BasicStroke bs) {        boolean aa = (antialiasHint == SunHints.INTVAL_ANTIALIAS_ON);        if (transformState < TRANSFORM_TRANSLATESCALE) {            if (aa) {                if (bs.getLineWidth() <= MinPenSizeAA) {                    if (bs.getDashArray() == null) {                        strokeState = STROKE_THIN;                    } else {                        strokeState = STROKE_THINDASHED;                    }                } else {                    strokeState = STROKE_WIDE;                }            } else {                if (bs == defaultStroke) {                    strokeState = STROKE_THIN;                } else if (bs.getLineWidth() <= 1.0f) {                    if (bs.getDashArray() == null) {                        strokeState = STROKE_THIN;                    } else {                        strokeState = STROKE_THINDASHED;                    }                } else {                    strokeState = STROKE_WIDE;                }            }        } else {

Lines 501–1000 of 3310. Previous lines