下面列出了java.awt.font.GlyphVector#getGlyphPosition ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public static void main(String[] args)
{
Font defaultFont = new Font(null);
FontRenderContext defaultFrc = new FontRenderContext(new AffineTransform(),
true, true);
GlyphVector gv = defaultFont.createGlyphVector(defaultFrc, "test");
//this causes the bounds to be cached
//which is necessary to trigger the bug
gv.getGlyphLogicalBounds(0);
//this correctly gets the position of the overall advance
Point2D glyphPosition = gv.getGlyphPosition(gv.getNumGlyphs());
// this sets the position of the overall advance,
// but also incorrectly tries to clear the bounds cache
// of a specific glyph indexed by the glyphIndex parameter
// even if the glyphIndex represents the overall advance
// (i.e. if glyphIndex == getNumGlyphs())
gv.setGlyphPosition(gv.getNumGlyphs(), glyphPosition);
}
public GlyphElement(GlyphVector gv, int index) {
glyphCode = gv.getGlyphCode(index);
transform = gv.getGlyphTransform(index);
outline = new ShapeSerializationWrapper(gv.getGlyphOutline(index));
position = new Point2DSerializationWrapper(
gv.getGlyphPosition(index));
logicalBounds = new ShapeSerializationWrapper(
gv.getGlyphLogicalBounds(index));
GlyphJustificationInfo gji = gv.getGlyphJustificationInfo(index);
justificationInfo = gji == null ? null
: new GlyphJustificationInfoSerializationWrapper(gji);
glyphMetrics = new GlyphMetricsSerializationWrapper(
gv.getGlyphMetrics(index));
visualBounds = new ShapeSerializationWrapper(
gv.getGlyphVisualBounds(index));
}
protected BufferedImage createImage(Color bgColor) {
BufferedImage bufferedImage = new BufferedImage(END_X, END_Y,
BufferedImage.TYPE_INT_RGB);
// create graphics and graphics2d
final Graphics graphics = bufferedImage.getGraphics();
final Graphics2D g2d = (Graphics2D) graphics;
// set the background color
g2d.setBackground(bgColor == null ? Color.gray : bgColor);
g2d.clearRect(START_X, START_Y, END_X, END_Y);
// create a pattern for the background
createPattern(g2d);
// set the fonts and font rendering hints
Font font = new Font("Helvetica", Font.ITALIC, 30);
g2d.setFont(font);
FontRenderContext frc = g2d.getFontRenderContext();
g2d.translate(10, 24);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(3));
// sets the foreground color
g2d.setPaint(Color.DARK_GRAY);
GlyphVector gv = font.createGlyphVector(frc, message);
int numGlyphs = gv.getNumGlyphs();
for (int ii = 0; ii < numGlyphs; ii++) {
AffineTransform at;
Point2D p = gv.getGlyphPosition(ii);
at = AffineTransform.getTranslateInstance(p.getX(), p.getY());
at.rotate(Math.PI / 8);
Shape shape = gv.getGlyphOutline(ii);
Shape sss = at.createTransformedShape(shape);
g2d.fill(sss);
}
return blurImage(bufferedImage);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
double scaleFactorX, double scaleFactorY,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
AffineTransform.getScaleInstance(scaleFactorX, scaleFactorY);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
double scaleFactorX, double scaleFactorY,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
AffineTransform.getScaleInstance(scaleFactorX, scaleFactorY);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
AffineTransform deviceTransform,
double scaleFactorX,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
new AffineTransform(deviceTransform);
advanceTransform.rotate(rotation*Math.PI/1800.0);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
double scaleFactorX, double scaleFactorY,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
AffineTransform.getScaleInstance(scaleFactorX, scaleFactorY);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
double scaleFactorX, double scaleFactorY,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
AffineTransform.getScaleInstance(scaleFactorX, scaleFactorY);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
double scaleFactorX, double scaleFactorY,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
AffineTransform.getScaleInstance(scaleFactorX, scaleFactorY);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
double scaleFactorX, double scaleFactorY,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
AffineTransform.getScaleInstance(scaleFactorX, scaleFactorY);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
double scaleFactorX, double scaleFactorY,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
AffineTransform.getScaleInstance(scaleFactorX, scaleFactorY);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
AffineTransform deviceTransform,
double scaleFactorX,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
new AffineTransform(deviceTransform);
advanceTransform.rotate(rotation*Math.PI/1800.0);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
AffineTransform deviceTransform,
double scaleFactorX,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
new AffineTransform(deviceTransform);
advanceTransform.rotate(rotation*Math.PI/1800.0);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
double scaleFactorX, double scaleFactorY,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
AffineTransform.getScaleInstance(scaleFactorX, scaleFactorY);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
AffineTransform deviceTransform,
double scaleFactorX,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
new AffineTransform(deviceTransform);
advanceTransform.rotate(rotation*Math.PI/1800.0);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
private void textOut(String str,
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
AffineTransform deviceTransform,
double scaleFactorX,
float userx, float usery,
float devx, float devy, float targetW) {
String family = font2D.getFamilyName(null);
int style = font.getStyle() | font2D.getStyle();
WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
rotation, awScale);
if (!setFont) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
float[] glyphPos = null;
if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
/* If there is a 1:1 char->glyph mapping then char positions
* are the same as glyph positions and we can tell GDI
* where to place the glyphs.
* On drawing we remove control chars so these need to be
* removed now so the string and positions are the same length.
* For other cases we need to pass glyph codes to GDI.
*/
str = wPrinterJob.removeControlChars(str);
char[] chars = str.toCharArray();
int len = chars.length;
GlyphVector gv = null;
if (!FontUtilities.isComplexText(chars, 0, len)) {
gv = font.createGlyphVector(frc, str);
}
if (gv == null) {
super.drawString(str, userx, usery, font, frc, targetW);
return;
}
glyphPos = gv.getGlyphPositions(0, len, null);
Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
/* GDI advances must not include device space rotation.
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
new AffineTransform(deviceTransform);
advanceTransform.rotate(rotation*Math.PI/1800.0);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
glyphAdvPos, 0, //destination
glyphPos.length/2); //num points
glyphPos = glyphAdvPos;
}
wPrinterJob.textOut(str, devx, devy, glyphPos);
}
@Override
public Shape createStrokedShape ( final Shape shape )
{
final FontRenderContext frc = new FontRenderContext ( null, true, true );
final GlyphVector glyphVector = font.createGlyphVector ( frc, text );
final GeneralPath result = new GeneralPath ();
final PathIterator it = new FlatteningPathIterator ( shape.getPathIterator ( null ), FLATNESS );
final float[] points = new float[ 6 ];
float moveX = 0;
float moveY = 0;
float lastX = 0;
float lastY = 0;
float thisX;
float thisY;
int type;
float next = 0;
int currentChar = 0;
final int length = glyphVector.getNumGlyphs ();
if ( length == 0 )
{
return result;
}
final float factor = stretchToFit ? measurePathLength ( shape ) / ( float ) glyphVector.getLogicalBounds ().getWidth () : 1.0f;
float nextAdvance = 0;
while ( currentChar < length && !it.isDone () )
{
type = it.currentSegment ( points );
switch ( type )
{
case PathIterator.SEG_MOVETO:
moveX = lastX = points[ 0 ];
moveY = lastY = points[ 1 ];
result.moveTo ( moveX, moveY );
nextAdvance = glyphVector.getGlyphMetrics ( currentChar ).getAdvance () * 0.5f;
next = nextAdvance;
break;
case PathIterator.SEG_CLOSE:
points[ 0 ] = moveX;
points[ 1 ] = moveY;
// Fall into....
case PathIterator.SEG_LINETO:
thisX = points[ 0 ];
thisY = points[ 1 ];
final float dx = thisX - lastX;
final float dy = thisY - lastY;
final float distance = ( float ) Math.sqrt ( dx * dx + dy * dy );
if ( distance >= next )
{
final float r = 1.0f / distance;
final float angle = ( float ) Math.atan2 ( dy, dx );
while ( currentChar < length && distance >= next )
{
final Shape glyph = glyphVector.getGlyphOutline ( currentChar );
final Point2D p = glyphVector.getGlyphPosition ( currentChar );
final float px = ( float ) p.getX ();
final float py = ( float ) p.getY ();
final float x = lastX + next * dx * r;
final float y = lastY + next * dy * r;
final float advance = nextAdvance;
nextAdvance =
currentChar < length - 1 ? glyphVector.getGlyphMetrics ( currentChar + 1 ).getAdvance () * 0.5f : 0;
t.setToTranslation ( x, y );
t.rotate ( angle );
t.translate ( -px - advance, -py );
result.append ( t.createTransformedShape ( glyph ), false );
next += ( advance + nextAdvance ) * factor;
currentChar++;
if ( repeat )
{
currentChar %= length;
}
}
}
next -= distance;
lastX = thisX;
lastY = thisY;
break;
}
it.next ();
}
return result;
}