1935 lines · 69.8 KB · Java
RawDownload
                if (rtl) flags |= FLAG_RUN_RTL;                if (!rtl && !ltr) flags |= FLAG_COMPLEX_GLYPHS;            }        }         return flags;    }     public float[] getGlyphPositions(int start, int count, float[] result) {        if (count < 0) {            throw new IllegalArgumentException("count = " + count);        }        if (start < 0) {            throw new IndexOutOfBoundsException("start = " + start);        }        if (start > glyphs.length + 1 - count) { // watch for overflow            throw new IndexOutOfBoundsException("start + count = " + (start + count));        }         return internalGetGlyphPositions(start, count, 0, result);    }     public Shape getGlyphLogicalBounds(int ix) {        if (ix < 0 || ix >= glyphs.length) {            throw new IndexOutOfBoundsException("ix = " + ix);        }         Shape[] lbcache;        if (lbcacheRef == null || (lbcache = (Shape[])lbcacheRef.get()) == null) {            lbcache = new Shape[glyphs.length];            lbcacheRef = new SoftReference(lbcache);        }         Shape result = lbcache[ix];        if (result == null) {            setFRCTX();            initPositions();             // !!! ought to return a rectangle2d for simple cases, though the following works for all             // get the position, the tx offset, and the x,y advance and x,y adl.  The            // shape is the box formed by adv (width) and adl (height) offset by            // the position plus the tx offset minus the ascent.             ADL adl = new ADL();            GlyphStrike gs = getGlyphStrike(ix);            gs.getADL(adl);             Point2D.Float adv = gs.strike.getGlyphMetrics(glyphs[ix]);             float wx = adv.x;            float wy = adv.y;            float hx = adl.descentX + adl.leadingX + adl.ascentX;            float hy = adl.descentY + adl.leadingY + adl.ascentY;            float x = positions[ix*2] + gs.dx - adl.ascentX;            float y = positions[ix*2+1] + gs.dy - adl.ascentY;             GeneralPath gp = new GeneralPath();            gp.moveTo(x, y);            gp.lineTo(x + wx, y + wy);            gp.lineTo(x + wx + hx, y + wy + hy);            gp.lineTo(x + hx, y + hy);            gp.closePath();             result = new DelegatingShape(gp);            lbcache[ix] = result;        }         return result;    }    private SoftReference lbcacheRef;     public Shape getGlyphVisualBounds(int ix) {        if (ix < 0 || ix >= glyphs.length) {            throw new IndexOutOfBoundsException("ix = " + ix);        }         Shape[] vbcache;        if (vbcacheRef == null || (vbcache = (Shape[])vbcacheRef.get()) == null) {            vbcache = new Shape[glyphs.length];            vbcacheRef = new SoftReference(vbcache);        }         Shape result = vbcache[ix];        if (result == null) {            result = new DelegatingShape(getGlyphOutlineBounds(ix));            vbcache[ix] = result;        }         return result;    }    private SoftReference vbcacheRef;     public Rectangle getGlyphPixelBounds(int index, FontRenderContext renderFRC, float x, float y) {      return getGlyphsPixelBounds(renderFRC, x, y, index, 1);    }     public GlyphMetrics getGlyphMetrics(int ix) {        if (ix < 0 || ix >= glyphs.length) {            throw new IndexOutOfBoundsException("ix = " + ix);        }         Rectangle2D vb = getGlyphVisualBounds(ix).getBounds2D();        Point2D pt = getGlyphPosition(ix);        vb.setRect(vb.getMinX() - pt.getX(),                   vb.getMinY() - pt.getY(),                   vb.getWidth(),                   vb.getHeight());        Point2D.Float adv =            getGlyphStrike(ix).strike.getGlyphMetrics(glyphs[ix]);        GlyphMetrics gm = new GlyphMetrics(true, adv.x, adv.y,                                           vb,                                           GlyphMetrics.STANDARD);        return gm;    }     public GlyphJustificationInfo getGlyphJustificationInfo(int ix) {        if (ix < 0 || ix >= glyphs.length) {            throw new IndexOutOfBoundsException("ix = " + ix);        }         // currently we don't have enough information to do this right.  should        // get info from the font and use real OT/GX justification.  Right now        // sun/font/ExtendedTextSourceLabel assigns one of three infos        // based on whether the char is kanji, space, or other.         return null;    }     public boolean equals(GlyphVector rhs) {        if (this == rhs) {            return true;        }        if (rhs == null) {            return false;        }         try {            StandardGlyphVector other = (StandardGlyphVector)rhs;             if (glyphs.length != other.glyphs.length) {                return false;            }             for (int i = 0; i < glyphs.length; ++i) {                if (glyphs[i] != other.glyphs[i]) {                    return false;                }            }             if (!font.equals(other.font)) {                return false;            }             if (!frc.equals(other.frc)) {                return false;            }             if ((other.positions == null) != (positions == null)) {                if (positions == null) {                    initPositions();                } else {                    other.initPositions();                }            }             if (positions != null) {                for (int i = 0; i < positions.length; ++i) {                    if (positions[i] != other.positions[i]) {                        return false;                    }                }            }             if (gti == null) {                return other.gti == null;            } else {                return gti.equals(other.gti);            }        }        catch (ClassCastException e) {            // assume they are different simply by virtue of the class difference             return false;        }    }     /**     * As a concrete subclass of Object that implements equality, this must     * implement hashCode.     */    public int hashCode() {        return font.hashCode() ^ glyphs.length;    }     /**     * Since we implement equality comparisons for GlyphVector, we implement     * the inherited Object.equals(Object) as well.  GlyphVector should do     * this, and define two glyphvectors as not equal if the classes differ.     */    public boolean equals(Object rhs) {        try {            return equals((GlyphVector)rhs);        }        catch (ClassCastException e) {            return false;        }    }     /**     * Sometimes I wish java had covariant return types...     */    public StandardGlyphVector copy() {        return (StandardGlyphVector)clone();    }     /**     * As a concrete subclass of GlyphVector, this must implement clone.     */    public Object clone() {        // positions, gti are mutable so we have to clone them        // font2d can be shared        // fsref is a cache and can be shared        try {            StandardGlyphVector result = (StandardGlyphVector)super.clone();             result.clearCaches();             if (positions != null) {                result.positions = (float[])positions.clone();            }             if (gti != null) {                result.gti = new GlyphTransformInfo(result, gti);            }             return result;        }        catch (CloneNotSupportedException e) {        }         return this;    }     //////////////////////    // StandardGlyphVector new public methods    /////////////////////     /*     * Set a multiple glyph positions at one time.  GlyphVector only     * provides API to set a single glyph at a time.     */    public void setGlyphPositions(float[] srcPositions, int srcStart,                                  int start, int count) {        if (count < 0) {            throw new IllegalArgumentException("count = " + count);        }         initPositions();        for (int i = start * 2, e = i + count * 2, p = srcStart; i < e; ++i, ++p) {            positions[i] = srcPositions[p];        }         clearCaches();        addFlags(FLAG_HAS_POSITION_ADJUSTMENTS);    }     /**     * Set all the glyph positions, including the 'after last glyph' position.     * The srcPositions array must be of length (numGlyphs + 1) * 2.     */    public void setGlyphPositions(float[] srcPositions) {        int requiredLength = glyphs.length * 2 + 2;        if (srcPositions.length != requiredLength) {            throw new IllegalArgumentException("srcPositions.length != " + requiredLength);        }         positions = (float[])srcPositions.clone();         clearCaches();        addFlags(FLAG_HAS_POSITION_ADJUSTMENTS);    }     /**     * This is a convenience overload that gets all the glyph positions, which     * is what you usually want to do if you're getting more than one.     * !!! should I bother taking result parameter?     */    public float[] getGlyphPositions(float[] result) {        return internalGetGlyphPositions(0, glyphs.length + 1, 0, result);    }     /**     * Get transform information for the requested range of glyphs.     * If no glyphs have a transform, return null.     * If a glyph has no transform (or is the identity transform) its entry in the result array will be null.     * If the passed-in result is null an array will be allocated for the caller.     * Each transform instance in the result array will unique, and independent of the GlyphVector's transform.     */    public AffineTransform[] getGlyphTransforms(int start, int count, AffineTransform[] result) {        if (start < 0 || count < 0 || start + count > glyphs.length) {            throw new IllegalArgumentException("start: " + start + " count: " + count);        }         if (gti == null) {            return null;        }         if (result == null) {            result = new AffineTransform[count];        }         for (int i = 0; i < count; ++i, ++start) {            result[i] = gti.getGlyphTransform(start);        }         return result;    }     /**     * Convenience overload for getGlyphTransforms(int, int, AffineTransform[], int);     */    public AffineTransform[] getGlyphTransforms() {        return getGlyphTransforms(0, glyphs.length, null);    }     /**     * Set a number of glyph transforms.     * Original transforms are unchanged.  The array may contain nulls, and also may     * contain multiple references to the same transform instance.     */    public void setGlyphTransforms(AffineTransform[] srcTransforms, int srcStart, int start, int count) {        for (int i = start, e = start + count; i < e; ++i) {            setGlyphTransform(i, srcTransforms[srcStart + i]);        }    }     /**     * Convenience overload of setGlyphTransforms(AffineTransform[], int, int, int).     */    public void setGlyphTransforms(AffineTransform[] srcTransforms) {        setGlyphTransforms(srcTransforms, 0, 0, glyphs.length);    }     /**     * For each glyph return posx, posy, advx, advy, visx, visy, visw, vish.     */    public float[] getGlyphInfo() {        setFRCTX();        initPositions();        float[] result = new float[glyphs.length * 8];        for (int i = 0, n = 0; i < glyphs.length; ++i, n += 8) {            float x = positions[i*2];            float y = positions[i*2+1];            result[n] = x;            result[n+1] = y;             int glyphID = glyphs[i];            GlyphStrike s = getGlyphStrike(i);            Point2D.Float adv = s.strike.getGlyphMetrics(glyphID);            result[n+2] = adv.x;            result[n+3] = adv.y;             Rectangle2D vb = getGlyphVisualBounds(i).getBounds2D();            result[n+4] = (float)(vb.getMinX());            result[n+5] = (float)(vb.getMinY());            result[n+6] = (float)(vb.getWidth());            result[n+7] = (float)(vb.getHeight());        }        return result;    }     /**     * !!! not used currently, but might be by getPixelbounds?     */    public void pixellate(FontRenderContext renderFRC, Point2D loc, Point pxResult) {        if (renderFRC == null) {            renderFRC = frc;        }         // it is a total pain that you have to copy the transform.         AffineTransform at = renderFRC.getTransform();        at.transform(loc, loc);        pxResult.x = (int)loc.getX(); // but must not behave oddly around zero        pxResult.y = (int)loc.getY();        loc.setLocation(pxResult.x, pxResult.y);        try {            at.inverseTransform(loc, loc);        }        catch (NoninvertibleTransformException e) {            throw new IllegalArgumentException("must be able to invert frc transform");        }    }     //////////////////////    // StandardGlyphVector package private methods    /////////////////////     // used by glyphlist to determine if it needs to allocate/size positions array    // gti always uses positions because the gtx might have translation.  We also    // need positions if the rendering dtx is different from the frctx.     boolean needsPositions(double[] devTX) {        return gti != null ||            (getLayoutFlags() & FLAG_HAS_POSITION_ADJUSTMENTS) != 0 ||            !matchTX(devTX, frctx);    }     // used by glyphList to get strong refs to font strikes for duration of rendering call    // if devTX matches current devTX, we're ready to go    // if we don't have multiple transforms, we're already ok     // !!! I'm not sure fontInfo works so well for glyphvector, since we have to be able to handle    // the multiple-strikes case     /*     * GlyphList calls this to set up its images data.  First it calls needsPositions,     * passing the devTX, to see if it should provide us a positions array to fill.     * It only doesn't need them if we're a simple glyph vector whose frctx matches the     * devtx.     * Then it calls setupGlyphImages.  If we need positions, we make sure we have our     * default positions based on the frctx first. Then we set the devTX, and use     * strikes based on it to generate the images.  Finally, we fill in the positions     * array.     * If we have transforms, we delegate to gti.  It depends on our having first     * initialized the positions and devTX.     */    Object setupGlyphImages(long[] images, float[] positions, double[] devTX) {        initPositions(); // FIRST ensure we have positions based on our frctx        setRenderTransform(devTX); // THEN make sure we are using the desired devTX         if (gti != null) {            return gti.setupGlyphImages(images, positions, dtx);        }         GlyphStrike gs = getDefaultStrike();        gs.strike.getGlyphImagePtrs(glyphs, images, glyphs.length);         if (positions != null) {            if (dtx.isIdentity()) {                System.arraycopy(this.positions, 0, positions, 0, glyphs.length * 2);            } else {                dtx.transform(this.positions, 0, positions, 0, glyphs.length);            }        }         return gs;    }     //////////////////////    // StandardGlyphVector private methods    /////////////////////     // We keep translation in our frctx since getPixelBounds uses it.  But    // GlyphList pulls out the translation and applies it separately, so    // we strip it out when we set the dtx.  Basically nothing uses the    // translation except getPixelBounds.     // called by needsPositions, setRenderTransform    private static boolean matchTX(double[] lhs, AffineTransform rhs) {        return            lhs[0] == rhs.getScaleX() &&            lhs[1] == rhs.getShearY() &&            lhs[2] == rhs.getShearX() &&            lhs[3] == rhs.getScaleY();    }     // returns new tx if old one has translation, otherwise returns old one    private static AffineTransform getNonTranslateTX(AffineTransform tx) {        if (tx.getTranslateX() != 0 || tx.getTranslateY() != 0) {            tx = new AffineTransform(tx.getScaleX(), tx.getShearY(),                                     tx.getShearX(), tx.getScaleY(),                                     0, 0);        }        return tx;    }     private static boolean equalNonTranslateTX(AffineTransform lhs, AffineTransform rhs) {        return lhs.getScaleX() == rhs.getScaleX() &&            lhs.getShearY() == rhs.getShearY() &&            lhs.getShearX() == rhs.getShearX() &&            lhs.getScaleY() == rhs.getScaleY();    }     // called by setupGlyphImages (after needsPositions, so redundant match check?)    private void setRenderTransform(double[] devTX) {        assert(devTX.length == 4);        if (!matchTX(devTX, dtx)) {            resetDTX(new AffineTransform(devTX)); // no translation since devTX len == 4.        }    }     // called by getGlyphsPixelBounds    private final void setDTX(AffineTransform tx) {        if (!equalNonTranslateTX(dtx, tx)) {            resetDTX(getNonTranslateTX(tx));        }    } 

Lines 501–1000 of 1935. Previous lines