src/share/classes/sun/font/StandardGlyphVector.java

Print this page




 136 public class StandardGlyphVector extends GlyphVector {
 137     private Font font;
 138     private FontRenderContext frc;
 139     private int[] glyphs; // always
 140     private int[] userGlyphs; // used to return glyphs to the client.
 141     private float[] positions; // only if not default advances
 142     private int[] charIndices;  // only if interesting
 143     private int flags; // indicates whether positions, charIndices is interesting
 144 
 145     private static final int UNINITIALIZED_FLAGS = -1;
 146 
 147     // transforms information
 148     private GlyphTransformInfo gti; // information about per-glyph transforms
 149 
 150     // !!! can we get rid of any of this extra stuff?
 151     private AffineTransform ftx;   // font transform without translation
 152     private AffineTransform dtx;   // device transform used for strike calculations, no translation
 153     private AffineTransform invdtx; // inverse of dtx or null if dtx is identity
 154     private AffineTransform frctx; // font render context transform, wish we could just share it
 155     private Font2D font2D;         // basic strike-independent stuff
 156     private SoftReference fsref;   // font strike reference for glyphs with no per-glyph transform
 157 
 158     /////////////////////////////
 159     // Constructors and Factory methods
 160     /////////////////////////////
 161 
 162     public StandardGlyphVector(Font font, String str, FontRenderContext frc) {
 163         init(font, str.toCharArray(), 0, str.length(), frc, UNINITIALIZED_FLAGS);
 164     }
 165 
 166     public StandardGlyphVector(Font font, char[] text, FontRenderContext frc) {
 167         init(font, text, 0, text.length, frc, UNINITIALIZED_FLAGS);
 168     }
 169 
 170     public StandardGlyphVector(Font font, char[] text, int start, int count,
 171                                FontRenderContext frc) {
 172         init(font, text, start, count, frc, UNINITIALIZED_FLAGS);
 173     }
 174 
 175     private float getTracking(Font font) {
 176         if (font.hasLayoutAttributes()) {


 509     public float[] getGlyphPositions(int start, int count, float[] result) {
 510         if (count < 0) {
 511             throw new IllegalArgumentException("count = " + count);
 512         }
 513         if (start < 0) {
 514             throw new IndexOutOfBoundsException("start = " + start);
 515         }
 516         if (start > glyphs.length + 1 - count) { // watch for overflow
 517             throw new IndexOutOfBoundsException("start + count = " + (start + count));
 518         }
 519 
 520         return internalGetGlyphPositions(start, count, 0, result);
 521     }
 522 
 523     public Shape getGlyphLogicalBounds(int ix) {
 524         if (ix < 0 || ix >= glyphs.length) {
 525             throw new IndexOutOfBoundsException("ix = " + ix);
 526         }
 527 
 528         Shape[] lbcache;
 529         if (lbcacheRef == null || (lbcache = (Shape[])lbcacheRef.get()) == null) {
 530             lbcache = new Shape[glyphs.length];
 531             lbcacheRef = new SoftReference(lbcache);
 532         }
 533 
 534         Shape result = lbcache[ix];
 535         if (result == null) {
 536             setFRCTX();
 537             initPositions();
 538 
 539             // !!! ought to return a rectangle2d for simple cases, though the following works for all
 540 
 541             // get the position, the tx offset, and the x,y advance and x,y adl.  The
 542             // shape is the box formed by adv (width) and adl (height) offset by
 543             // the position plus the tx offset minus the ascent.
 544 
 545             ADL adl = new ADL();
 546             GlyphStrike gs = getGlyphStrike(ix);
 547             gs.getADL(adl);
 548 
 549             Point2D.Float adv = gs.strike.getGlyphMetrics(glyphs[ix]);
 550 
 551             float wx = adv.x;
 552             float wy = adv.y;
 553             float hx = adl.descentX + adl.leadingX + adl.ascentX;
 554             float hy = adl.descentY + adl.leadingY + adl.ascentY;
 555             float x = positions[ix*2] + gs.dx - adl.ascentX;
 556             float y = positions[ix*2+1] + gs.dy - adl.ascentY;
 557 
 558             GeneralPath gp = new GeneralPath();
 559             gp.moveTo(x, y);
 560             gp.lineTo(x + wx, y + wy);
 561             gp.lineTo(x + wx + hx, y + wy + hy);
 562             gp.lineTo(x + hx, y + hy);
 563             gp.closePath();
 564 
 565             result = new DelegatingShape(gp);
 566             lbcache[ix] = result;
 567         }
 568 
 569         return result;
 570     }
 571     private SoftReference lbcacheRef;
 572 
 573     public Shape getGlyphVisualBounds(int ix) {
 574         if (ix < 0 || ix >= glyphs.length) {
 575             throw new IndexOutOfBoundsException("ix = " + ix);
 576         }
 577 
 578         Shape[] vbcache;
 579         if (vbcacheRef == null || (vbcache = (Shape[])vbcacheRef.get()) == null) {
 580             vbcache = new Shape[glyphs.length];
 581             vbcacheRef = new SoftReference(vbcache);
 582         }
 583 
 584         Shape result = vbcache[ix];
 585         if (result == null) {
 586             result = new DelegatingShape(getGlyphOutlineBounds(ix));
 587             vbcache[ix] = result;
 588         }
 589 
 590         return result;
 591     }
 592     private SoftReference vbcacheRef;
 593 
 594     public Rectangle getGlyphPixelBounds(int index, FontRenderContext renderFRC, float x, float y) {
 595       return getGlyphsPixelBounds(renderFRC, x, y, index, 1);
 596     }
 597 
 598     public GlyphMetrics getGlyphMetrics(int ix) {
 599         if (ix < 0 || ix >= glyphs.length) {
 600             throw new IndexOutOfBoundsException("ix = " + ix);
 601         }
 602 
 603         Rectangle2D vb = getGlyphVisualBounds(ix).getBounds2D();
 604         Point2D pt = getGlyphPosition(ix);
 605         vb.setRect(vb.getMinX() - pt.getX(),
 606                    vb.getMinY() - pt.getY(),
 607                    vb.getWidth(),
 608                    vb.getHeight());
 609         Point2D.Float adv =
 610             getGlyphStrike(ix).strike.getGlyphMetrics(glyphs[ix]);
 611         GlyphMetrics gm = new GlyphMetrics(true, adv.x, adv.y,
 612                                            vb,


1213         Point2D.Float pt = new Point.Float();
1214         int n = start * 2;
1215         while (--count >= 0) {
1216             pt.x = x + positions[n++];
1217             pt.y = y + positions[n++];
1218             tx.transform(pt, pt);
1219             fs.getGlyphImageBounds(glyphs[start++], pt, r);
1220             if (!r.isEmpty()) {
1221                 if (result == null) {
1222                     result = new Rectangle(r);
1223                 } else {
1224                     result.add(r);
1225                 }
1226             }
1227         }
1228         return result != null ? result : r;
1229     }
1230 
1231     private void clearCaches(int ix) {
1232         if (lbcacheRef != null) {
1233             Shape[] lbcache = (Shape[])lbcacheRef.get();
1234             if (lbcache != null) {
1235                 lbcache[ix] = null;
1236             }
1237         }
1238 
1239         if (vbcacheRef != null) {
1240             Shape[] vbcache = (Shape[])vbcacheRef.get();
1241             if (vbcache != null) {
1242                 vbcache[ix] = null;
1243             }
1244         }
1245     }
1246 
1247     private void clearCaches() {
1248         lbcacheRef = null;
1249         vbcacheRef = null;
1250     }
1251 
1252     // internal use only for possible future extension
1253 
1254     /**
1255      * A flag used with getLayoutFlags that indicates whether this <code>GlyphVector</code> uses
1256      * a vertical baseline.
1257      */
1258     public static final int FLAG_USES_VERTICAL_BASELINE = 128;
1259 
1260     /**


1340      */
1341     private void clearFlags(int clearedFlags) {
1342         flags = getLayoutFlags() & ~clearedFlags;
1343     }
1344 
1345     // general utility methods
1346 
1347     // encapsulate the test to check whether we have per-glyph transforms
1348     private GlyphStrike getGlyphStrike(int ix) {
1349         if (gti == null) {
1350             return getDefaultStrike();
1351         } else {
1352             return gti.getStrike(ix);
1353         }
1354     }
1355 
1356     // encapsulate access to cached default glyph strike
1357     private GlyphStrike getDefaultStrike() {
1358         GlyphStrike gs = null;
1359         if (fsref != null) {
1360             gs = (GlyphStrike)fsref.get();
1361         }
1362         if (gs == null) {
1363             gs = GlyphStrike.create(this, dtx, null);
1364             fsref = new SoftReference(gs);
1365         }
1366         return gs;
1367     }
1368 
1369 
1370     /////////////////////
1371     // Internal utility classes
1372     /////////////////////
1373 
1374     // !!! I have this as a separate class instead of just inside SGV,
1375     // but I previously didn't bother.  Now I'm trying this again.
1376     // Probably still not worth it, but I'd like to keep sgv's small in the common case.
1377 
1378     static final class GlyphTransformInfo {
1379         StandardGlyphVector sgv;  // reference back to glyph vector - yuck
1380         int[] indices;            // index into unique strikes
1381         double[] transforms;      // six doubles per unique transform, because AT is a pain to manipulate
1382         SoftReference strikesRef; // ref to unique strikes, one per transform
1383         boolean haveAllStrikes;   // true if the strike array has been filled by getStrikes().
1384 
1385         // used when first setting a transform
1386         GlyphTransformInfo(StandardGlyphVector sgv) {
1387             this.sgv = sgv;
1388         }
1389 
1390         // used when cloning a glyph vector, need to set back link
1391         GlyphTransformInfo(StandardGlyphVector sgv, GlyphTransformInfo rhs) {
1392             this.sgv = sgv;
1393 
1394             this.indices = rhs.indices == null ? null : rhs.indices.clone();
1395             this.transforms = rhs.transforms == null ? null : rhs.transforms.clone();
1396             this.strikesRef = null; // can't share cache, so rather than clone, we just null out
1397         }
1398 
1399         // used in sgv equality
1400         public boolean equals(GlyphTransformInfo rhs) {
1401             if (rhs == null) {
1402                 return false;


1636 
1637         private GlyphStrike[] getAllStrikes() {
1638             if (indices == null) {
1639                 return null;
1640             }
1641 
1642             GlyphStrike[] strikes = getStrikeArray();
1643             if (!haveAllStrikes) {
1644                 for (int i = 0; i < strikes.length; ++i) {
1645                     getStrikeAtIndex(strikes, i);
1646                 }
1647                 haveAllStrikes = true;
1648             }
1649 
1650             return strikes;
1651         }
1652 
1653         private GlyphStrike[] getStrikeArray() {
1654             GlyphStrike[] strikes = null;
1655             if (strikesRef != null) {
1656                 strikes = (GlyphStrike[])strikesRef.get();
1657             }
1658             if (strikes == null) {
1659                 haveAllStrikes = false;
1660                 strikes = new GlyphStrike[transformCount() + 1];
1661                 strikesRef = new SoftReference(strikes);
1662             }
1663 
1664             return strikes;
1665         }
1666 
1667         private GlyphStrike getStrikeAtIndex(GlyphStrike[] strikes, int strikeIndex) {
1668             GlyphStrike strike = strikes[strikeIndex];
1669             if (strike == null) {
1670                 if (strikeIndex == 0) {
1671                     strike = sgv.getDefaultStrike();
1672                 } else {
1673                     int ix = (strikeIndex - 1) * 6;
1674                     AffineTransform gtx = new AffineTransform(transforms[ix],
1675                                                               transforms[ix+1],
1676                                                               transforms[ix+2],
1677                                                               transforms[ix+3],
1678                                                               transforms[ix+4],
1679                                                               transforms[ix+5]);
1680 
1681                     strike = GlyphStrike.create(sgv, sgv.dtx, gtx);




 136 public class StandardGlyphVector extends GlyphVector {
 137     private Font font;
 138     private FontRenderContext frc;
 139     private int[] glyphs; // always
 140     private int[] userGlyphs; // used to return glyphs to the client.
 141     private float[] positions; // only if not default advances
 142     private int[] charIndices;  // only if interesting
 143     private int flags; // indicates whether positions, charIndices is interesting
 144 
 145     private static final int UNINITIALIZED_FLAGS = -1;
 146 
 147     // transforms information
 148     private GlyphTransformInfo gti; // information about per-glyph transforms
 149 
 150     // !!! can we get rid of any of this extra stuff?
 151     private AffineTransform ftx;   // font transform without translation
 152     private AffineTransform dtx;   // device transform used for strike calculations, no translation
 153     private AffineTransform invdtx; // inverse of dtx or null if dtx is identity
 154     private AffineTransform frctx; // font render context transform, wish we could just share it
 155     private Font2D font2D;         // basic strike-independent stuff
 156     private SoftReference<GlyphStrike> fsref;   // font strike reference for glyphs with no per-glyph transform
 157 
 158     /////////////////////////////
 159     // Constructors and Factory methods
 160     /////////////////////////////
 161 
 162     public StandardGlyphVector(Font font, String str, FontRenderContext frc) {
 163         init(font, str.toCharArray(), 0, str.length(), frc, UNINITIALIZED_FLAGS);
 164     }
 165 
 166     public StandardGlyphVector(Font font, char[] text, FontRenderContext frc) {
 167         init(font, text, 0, text.length, frc, UNINITIALIZED_FLAGS);
 168     }
 169 
 170     public StandardGlyphVector(Font font, char[] text, int start, int count,
 171                                FontRenderContext frc) {
 172         init(font, text, start, count, frc, UNINITIALIZED_FLAGS);
 173     }
 174 
 175     private float getTracking(Font font) {
 176         if (font.hasLayoutAttributes()) {


 509     public float[] getGlyphPositions(int start, int count, float[] result) {
 510         if (count < 0) {
 511             throw new IllegalArgumentException("count = " + count);
 512         }
 513         if (start < 0) {
 514             throw new IndexOutOfBoundsException("start = " + start);
 515         }
 516         if (start > glyphs.length + 1 - count) { // watch for overflow
 517             throw new IndexOutOfBoundsException("start + count = " + (start + count));
 518         }
 519 
 520         return internalGetGlyphPositions(start, count, 0, result);
 521     }
 522 
 523     public Shape getGlyphLogicalBounds(int ix) {
 524         if (ix < 0 || ix >= glyphs.length) {
 525             throw new IndexOutOfBoundsException("ix = " + ix);
 526         }
 527 
 528         Shape[] lbcache;
 529         if (lbcacheRef == null || (lbcache = lbcacheRef.get()) == null) {
 530             lbcache = new Shape[glyphs.length];
 531             lbcacheRef = new SoftReference<>(lbcache);
 532         }
 533 
 534         Shape result = lbcache[ix];
 535         if (result == null) {
 536             setFRCTX();
 537             initPositions();
 538 
 539             // !!! ought to return a rectangle2d for simple cases, though the following works for all
 540 
 541             // get the position, the tx offset, and the x,y advance and x,y adl.  The
 542             // shape is the box formed by adv (width) and adl (height) offset by
 543             // the position plus the tx offset minus the ascent.
 544 
 545             ADL adl = new ADL();
 546             GlyphStrike gs = getGlyphStrike(ix);
 547             gs.getADL(adl);
 548 
 549             Point2D.Float adv = gs.strike.getGlyphMetrics(glyphs[ix]);
 550 
 551             float wx = adv.x;
 552             float wy = adv.y;
 553             float hx = adl.descentX + adl.leadingX + adl.ascentX;
 554             float hy = adl.descentY + adl.leadingY + adl.ascentY;
 555             float x = positions[ix*2] + gs.dx - adl.ascentX;
 556             float y = positions[ix*2+1] + gs.dy - adl.ascentY;
 557 
 558             GeneralPath gp = new GeneralPath();
 559             gp.moveTo(x, y);
 560             gp.lineTo(x + wx, y + wy);
 561             gp.lineTo(x + wx + hx, y + wy + hy);
 562             gp.lineTo(x + hx, y + hy);
 563             gp.closePath();
 564 
 565             result = new DelegatingShape(gp);
 566             lbcache[ix] = result;
 567         }
 568 
 569         return result;
 570     }
 571     private SoftReference<Shape[]> lbcacheRef;
 572 
 573     public Shape getGlyphVisualBounds(int ix) {
 574         if (ix < 0 || ix >= glyphs.length) {
 575             throw new IndexOutOfBoundsException("ix = " + ix);
 576         }
 577 
 578         Shape[] vbcache;
 579         if (vbcacheRef == null || (vbcache = vbcacheRef.get()) == null) {
 580             vbcache = new Shape[glyphs.length];
 581             vbcacheRef = new SoftReference<>(vbcache);
 582         }
 583 
 584         Shape result = vbcache[ix];
 585         if (result == null) {
 586             result = new DelegatingShape(getGlyphOutlineBounds(ix));
 587             vbcache[ix] = result;
 588         }
 589 
 590         return result;
 591     }
 592     private SoftReference<Shape[]> vbcacheRef;
 593 
 594     public Rectangle getGlyphPixelBounds(int index, FontRenderContext renderFRC, float x, float y) {
 595       return getGlyphsPixelBounds(renderFRC, x, y, index, 1);
 596     }
 597 
 598     public GlyphMetrics getGlyphMetrics(int ix) {
 599         if (ix < 0 || ix >= glyphs.length) {
 600             throw new IndexOutOfBoundsException("ix = " + ix);
 601         }
 602 
 603         Rectangle2D vb = getGlyphVisualBounds(ix).getBounds2D();
 604         Point2D pt = getGlyphPosition(ix);
 605         vb.setRect(vb.getMinX() - pt.getX(),
 606                    vb.getMinY() - pt.getY(),
 607                    vb.getWidth(),
 608                    vb.getHeight());
 609         Point2D.Float adv =
 610             getGlyphStrike(ix).strike.getGlyphMetrics(glyphs[ix]);
 611         GlyphMetrics gm = new GlyphMetrics(true, adv.x, adv.y,
 612                                            vb,


1213         Point2D.Float pt = new Point.Float();
1214         int n = start * 2;
1215         while (--count >= 0) {
1216             pt.x = x + positions[n++];
1217             pt.y = y + positions[n++];
1218             tx.transform(pt, pt);
1219             fs.getGlyphImageBounds(glyphs[start++], pt, r);
1220             if (!r.isEmpty()) {
1221                 if (result == null) {
1222                     result = new Rectangle(r);
1223                 } else {
1224                     result.add(r);
1225                 }
1226             }
1227         }
1228         return result != null ? result : r;
1229     }
1230 
1231     private void clearCaches(int ix) {
1232         if (lbcacheRef != null) {
1233             Shape[] lbcache = lbcacheRef.get();
1234             if (lbcache != null) {
1235                 lbcache[ix] = null;
1236             }
1237         }
1238 
1239         if (vbcacheRef != null) {
1240             Shape[] vbcache = vbcacheRef.get();
1241             if (vbcache != null) {
1242                 vbcache[ix] = null;
1243             }
1244         }
1245     }
1246 
1247     private void clearCaches() {
1248         lbcacheRef = null;
1249         vbcacheRef = null;
1250     }
1251 
1252     // internal use only for possible future extension
1253 
1254     /**
1255      * A flag used with getLayoutFlags that indicates whether this <code>GlyphVector</code> uses
1256      * a vertical baseline.
1257      */
1258     public static final int FLAG_USES_VERTICAL_BASELINE = 128;
1259 
1260     /**


1340      */
1341     private void clearFlags(int clearedFlags) {
1342         flags = getLayoutFlags() & ~clearedFlags;
1343     }
1344 
1345     // general utility methods
1346 
1347     // encapsulate the test to check whether we have per-glyph transforms
1348     private GlyphStrike getGlyphStrike(int ix) {
1349         if (gti == null) {
1350             return getDefaultStrike();
1351         } else {
1352             return gti.getStrike(ix);
1353         }
1354     }
1355 
1356     // encapsulate access to cached default glyph strike
1357     private GlyphStrike getDefaultStrike() {
1358         GlyphStrike gs = null;
1359         if (fsref != null) {
1360             gs = fsref.get();
1361         }
1362         if (gs == null) {
1363             gs = GlyphStrike.create(this, dtx, null);
1364             fsref = new SoftReference<>(gs);
1365         }
1366         return gs;
1367     }
1368 
1369 
1370     /////////////////////
1371     // Internal utility classes
1372     /////////////////////
1373 
1374     // !!! I have this as a separate class instead of just inside SGV,
1375     // but I previously didn't bother.  Now I'm trying this again.
1376     // Probably still not worth it, but I'd like to keep sgv's small in the common case.
1377 
1378     static final class GlyphTransformInfo {
1379         StandardGlyphVector sgv;  // reference back to glyph vector - yuck
1380         int[] indices;            // index into unique strikes
1381         double[] transforms;      // six doubles per unique transform, because AT is a pain to manipulate
1382         SoftReference<GlyphStrike[]> strikesRef; // ref to unique strikes, one per transform
1383         boolean haveAllStrikes;   // true if the strike array has been filled by getStrikes().
1384 
1385         // used when first setting a transform
1386         GlyphTransformInfo(StandardGlyphVector sgv) {
1387             this.sgv = sgv;
1388         }
1389 
1390         // used when cloning a glyph vector, need to set back link
1391         GlyphTransformInfo(StandardGlyphVector sgv, GlyphTransformInfo rhs) {
1392             this.sgv = sgv;
1393 
1394             this.indices = rhs.indices == null ? null : rhs.indices.clone();
1395             this.transforms = rhs.transforms == null ? null : rhs.transforms.clone();
1396             this.strikesRef = null; // can't share cache, so rather than clone, we just null out
1397         }
1398 
1399         // used in sgv equality
1400         public boolean equals(GlyphTransformInfo rhs) {
1401             if (rhs == null) {
1402                 return false;


1636 
1637         private GlyphStrike[] getAllStrikes() {
1638             if (indices == null) {
1639                 return null;
1640             }
1641 
1642             GlyphStrike[] strikes = getStrikeArray();
1643             if (!haveAllStrikes) {
1644                 for (int i = 0; i < strikes.length; ++i) {
1645                     getStrikeAtIndex(strikes, i);
1646                 }
1647                 haveAllStrikes = true;
1648             }
1649 
1650             return strikes;
1651         }
1652 
1653         private GlyphStrike[] getStrikeArray() {
1654             GlyphStrike[] strikes = null;
1655             if (strikesRef != null) {
1656                 strikes = strikesRef.get();
1657             }
1658             if (strikes == null) {
1659                 haveAllStrikes = false;
1660                 strikes = new GlyphStrike[transformCount() + 1];
1661                 strikesRef = new SoftReference<>(strikes);
1662             }
1663 
1664             return strikes;
1665         }
1666 
1667         private GlyphStrike getStrikeAtIndex(GlyphStrike[] strikes, int strikeIndex) {
1668             GlyphStrike strike = strikes[strikeIndex];
1669             if (strike == null) {
1670                 if (strikeIndex == 0) {
1671                     strike = sgv.getDefaultStrike();
1672                 } else {
1673                     int ix = (strikeIndex - 1) * 6;
1674                     AffineTransform gtx = new AffineTransform(transforms[ix],
1675                                                               transforms[ix+1],
1676                                                               transforms[ix+2],
1677                                                               transforms[ix+3],
1678                                                               transforms[ix+4],
1679                                                               transforms[ix+5]);
1680 
1681                     strike = GlyphStrike.create(sgv, sgv.dtx, gtx);