src/windows/classes/sun/awt/windows/WPathGraphics.java

Print this page
rev 1297 : [mq]: fontmanager.patch


  48 
  49 import java.awt.image.BufferedImage;
  50 import java.awt.image.ColorModel;
  51 import java.awt.image.DataBuffer;
  52 import java.awt.image.IndexColorModel;
  53 import java.awt.image.WritableRaster;
  54 import sun.awt.image.ByteComponentRaster;
  55 import sun.awt.image.BytePackedRaster;
  56 
  57 import java.awt.print.PageFormat;
  58 import java.awt.print.Printable;
  59 import java.awt.print.PrinterException;
  60 import java.awt.print.PrinterJob;
  61 
  62 import java.util.Arrays;
  63 
  64 import sun.font.CharToGlyphMapper;
  65 import sun.font.CompositeFont;
  66 import sun.font.Font2D;
  67 import sun.font.FontManager;


  68 import sun.font.PhysicalFont;
  69 import sun.font.TrueTypeFont;
  70 
  71 import sun.print.PathGraphics;
  72 import sun.print.ProxyGraphics2D;
  73 
  74 class WPathGraphics extends PathGraphics {
  75 
  76     /**
  77      * For a drawing application the initial user space
  78      * resolution is 72dpi.
  79      */
  80     private static final int DEFAULT_USER_RES = 72;
  81 
  82     private static final float MIN_DEVICE_LINEWIDTH = 1.2f;
  83     private static final float MAX_THINLINE_INCHES = 0.014f;
  84 
  85     /* Note that preferGDITextLayout implies useGDITextLayout.
  86      * "prefer" is used to override cases where would otherwise
  87      * choose not to use it. Note that non-layout factors may


 277         fontTransform.concatenate(getFont().getTransform());
 278         int transformType = fontTransform.getType();
 279 
 280         /* Test if GDI can handle the transform */
 281         boolean directToGDI = ((transformType !=
 282                                AffineTransform.TYPE_GENERAL_TRANSFORM)
 283                                && ((transformType & AffineTransform.TYPE_FLIP)
 284                                    == 0));
 285 
 286         if (!directToGDI) {
 287             return 0;
 288         }
 289 
 290         /* Since all windows fonts are available, and the JRE fonts
 291          * are also registered. Only the Font.createFont() case is presently
 292          * unknown to GDI. Those can be registered too, although that
 293          * code does not exist yet, it can be added too, so we should not
 294          * fail that case. Just do a quick check whether its a TrueTypeFont
 295          * - ie not a Type1 font etc, and let drawString() resolve the rest.
 296          */
 297         Font2D font2D = FontManager.getFont2D(font);
 298         if (font2D instanceof CompositeFont ||
 299             font2D instanceof TrueTypeFont) {
 300             return 1;
 301         } else {
 302             return 0;
 303         }
 304     }
 305 
 306     private static boolean isXP() {
 307         String osVersion = System.getProperty("os.version");
 308         if (osVersion != null) {
 309             Float version = Float.valueOf(osVersion);
 310             return (version.floatValue() >= 5.1f);
 311         } else {
 312             return false;
 313         }
 314     }
 315 
 316     /* In case GDI doesn't handle shaping or BIDI consistently with
 317      * 2D's TextLayout, we can detect these cases and redelegate up to
 318      * be drawn via TextLayout, which in is rendered as runs of
 319      * GlyphVectors, to which we can assign positions for each glyph.
 320      */
 321     private boolean strNeedsTextLayout(String str, Font font) {
 322         char[] chars = str.toCharArray();
 323         boolean isComplex = FontManager.isComplexText(chars, 0, chars.length);
 324         if (!isComplex) {
 325             return false;
 326         } else if (!useGDITextLayout) {
 327             return true;
 328         } else {
 329             if (preferGDITextLayout ||
 330                 (isXP() && FontManager.textLayoutIsCompatible(font))) {
 331                 return false;
 332             } else {
 333                 return true;
 334             }
 335         }
 336     }
 337 




















 338     private int getAngle(Point2D.Double pt) {
 339         /* Get the rotation in 1/10'ths degree (as needed by Windows)
 340          * so that GDI can draw the text rotated.
 341          * This calculation is only valid for a uniform scale, no shearing.
 342          */
 343         double angle = Math.toDegrees(Math.atan2(pt.y, pt.x));
 344         if (angle < 0.0) {
 345             angle+= 360.0;
 346         }
 347         /* Windows specifies the rotation anti-clockwise from the x-axis
 348          * of the device, 2D specifies +ve rotation towards the y-axis
 349          * Since the 2D y-axis runs from top-to-bottom, windows angle of
 350          * rotation here is opposite than 2D's, so the rotation needed
 351          * needs to be recalculated in the opposite direction.
 352          */
 353         if (angle != 0.0) {
 354             angle = 360.0 - angle;
 355         }
 356         return (int)Math.round(angle * 10.0);
 357     }


 481          * Although we have already tested that there is no shear,
 482          * there may be a non-uniform scale, so the width of the font
 483          * does not scale equally with the height. That is handled
 484          * by specifying an 'average width' scale to GDI.
 485          */
 486         float fontSize = font.getSize2D();
 487 
 488         Point2D.Double pty = new Point2D.Double(0.0, 1.0);
 489         fontTransform.deltaTransform(pty, pty);
 490         double scaleFactorY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
 491         float scaledFontSizeY = (float)(fontSize * scaleFactorY);
 492 
 493         Point2D.Double ptx = new Point2D.Double(1.0, 0.0);
 494         fontTransform.deltaTransform(ptx, ptx);
 495         double scaleFactorX = Math.sqrt(ptx.x*ptx.x+ptx.y*ptx.y);
 496         float scaledFontSizeX = (float)(fontSize * scaleFactorX);
 497 
 498         float awScale = getAwScale(scaleFactorX, scaleFactorY);
 499         int iangle = getAngle(ptx);
 500 
 501         Font2D font2D = FontManager.getFont2D(font);
 502         if (font2D instanceof TrueTypeFont) {
 503             textOut(str, font, (TrueTypeFont)font2D, frc,
 504                     scaledFontSizeY, iangle, awScale,
 505                     deviceTransform, scaleFactorX,
 506                     x, y, devpos.x, devpos.y, targetW);
 507         } else if (font2D instanceof CompositeFont) {
 508             /* Composite fonts are made up of multiple fonts and each
 509              * substring that uses a particular component font needs to
 510              * be separately sent to GDI.
 511              * This works for standard composite fonts, alternate ones,
 512              * Fonts that are a physical font backed by a standard composite,
 513              * and with fallback fonts.
 514              */
 515             CompositeFont compFont = (CompositeFont)font2D;
 516             float userx = x, usery = y;
 517             float devx = devpos.x, devy = devpos.y;
 518             char[] chars = str.toCharArray();
 519             int len = chars.length;
 520             int[] glyphs = new int[len];
 521             compFont.getMapper().charsToGlyphs(len, chars, glyphs);


 676          * When we specify the advances, they are in device space, so
 677          * we don't want any further interpretation applied by GDI, but
 678          * since as noted the advances are interpreted in the HFONT's
 679          * coordinate space, our advances would be rotated again.
 680          * We don't have any way to tell GDI to rotate only the glyphs and
 681          * not the advances, so we need to account for this in the advances
 682          * we supply, by supplying unrotated advances.
 683          * Note that "iangle" is in the opposite direction to 2D's normal
 684          * direction of rotation, so this rotation inverts the
 685          * rotation element of the deviceTransform.
 686          */
 687         AffineTransform advanceTransform =
 688             new AffineTransform(deviceTransform);
 689         advanceTransform.rotate(iangle*Math.PI/1800.0);
 690         float[] glyphAdvPos = new float[glyphPos.length];
 691 
 692         advanceTransform.transform(glyphPos, 0,         //source
 693                                    glyphAdvPos, 0,      //destination
 694                                    glyphPos.length/2);  //num points
 695 
 696         Font2D font2D = FontManager.getFont2D(font);
 697         if (font2D instanceof TrueTypeFont) {
 698             String family = font2D.getFamilyName(null);
 699             int style = font.getStyle() | font2D.getStyle();
 700             if (!wPrinterJob.setFont(family, scaledFontSizeY, style,
 701                                      iangle, awScale)) {
 702                 return false;
 703             }
 704             wPrinterJob.glyphsOut(glyphCodes, devpos.x, devpos.y, glyphAdvPos);
 705 
 706         } else if (font2D instanceof CompositeFont) {
 707             /* Composite fonts are made up of multiple fonts and each
 708              * substring that uses a particular component font needs to
 709              * be separately sent to GDI.
 710              * This works for standard composite fonts, alternate ones,
 711              * Fonts that are a physical font backed by a standard composite,
 712              * and with fallback fonts.
 713              */
 714             CompositeFont compFont = (CompositeFont)font2D;
 715             float userx = x, usery = y;
 716             float devx = devpos.x, devy = devpos.y;


 775          boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
 776                                                rotation, awScale);
 777          if (!setFont) {
 778              super.drawString(str, userx, usery, font, frc, targetW);
 779              return;
 780          }
 781 
 782          float[] glyphPos = null;
 783          if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
 784              /* If there is a 1:1 char->glyph mapping then char positions
 785               * are the same as glyph positions and we can tell GDI
 786               * where to place the glyphs.
 787               * On drawing we remove control chars so these need to be
 788               * removed now so the string and positions are the same length.
 789               * For other cases we need to pass glyph codes to GDI.
 790               */
 791              str = wPrinterJob.removeControlChars(str);
 792              char[] chars = str.toCharArray();
 793              int len = chars.length;
 794              GlyphVector gv = null;
 795              if (!FontManager.isComplexText(chars, 0, len)) {
 796                  gv = font.createGlyphVector(frc, str);
 797              }
 798              if (gv == null) {
 799                  super.drawString(str, userx, usery, font, frc, targetW);
 800                  return;
 801              }
 802              glyphPos = gv.getGlyphPositions(0, len, null);
 803              Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
 804 
 805              /* GDI advances must not include device space rotation.
 806               * See earlier comment in printGlyphVector() for details.
 807               */
 808              AffineTransform advanceTransform =
 809                new AffineTransform(deviceTransform);
 810              advanceTransform.rotate(rotation*Math.PI/1800.0);
 811              float[] glyphAdvPos = new float[glyphPos.length];
 812 
 813              advanceTransform.transform(glyphPos, 0,         //source
 814                                         glyphAdvPos, 0,      //destination
 815                                         glyphPos.length/2);  //num points




  48 
  49 import java.awt.image.BufferedImage;
  50 import java.awt.image.ColorModel;
  51 import java.awt.image.DataBuffer;
  52 import java.awt.image.IndexColorModel;
  53 import java.awt.image.WritableRaster;
  54 import sun.awt.image.ByteComponentRaster;
  55 import sun.awt.image.BytePackedRaster;
  56 
  57 import java.awt.print.PageFormat;
  58 import java.awt.print.Printable;
  59 import java.awt.print.PrinterException;
  60 import java.awt.print.PrinterJob;
  61 
  62 import java.util.Arrays;
  63 
  64 import sun.font.CharToGlyphMapper;
  65 import sun.font.CompositeFont;
  66 import sun.font.Font2D;
  67 import sun.font.FontManager;
  68 import sun.font.FontManagerFactory;
  69 import sun.font.FontUtilities;
  70 import sun.font.PhysicalFont;
  71 import sun.font.TrueTypeFont;
  72 
  73 import sun.print.PathGraphics;
  74 import sun.print.ProxyGraphics2D;
  75 
  76 class WPathGraphics extends PathGraphics {
  77 
  78     /**
  79      * For a drawing application the initial user space
  80      * resolution is 72dpi.
  81      */
  82     private static final int DEFAULT_USER_RES = 72;
  83 
  84     private static final float MIN_DEVICE_LINEWIDTH = 1.2f;
  85     private static final float MAX_THINLINE_INCHES = 0.014f;
  86 
  87     /* Note that preferGDITextLayout implies useGDITextLayout.
  88      * "prefer" is used to override cases where would otherwise
  89      * choose not to use it. Note that non-layout factors may


 279         fontTransform.concatenate(getFont().getTransform());
 280         int transformType = fontTransform.getType();
 281 
 282         /* Test if GDI can handle the transform */
 283         boolean directToGDI = ((transformType !=
 284                                AffineTransform.TYPE_GENERAL_TRANSFORM)
 285                                && ((transformType & AffineTransform.TYPE_FLIP)
 286                                    == 0));
 287 
 288         if (!directToGDI) {
 289             return 0;
 290         }
 291 
 292         /* Since all windows fonts are available, and the JRE fonts
 293          * are also registered. Only the Font.createFont() case is presently
 294          * unknown to GDI. Those can be registered too, although that
 295          * code does not exist yet, it can be added too, so we should not
 296          * fail that case. Just do a quick check whether its a TrueTypeFont
 297          * - ie not a Type1 font etc, and let drawString() resolve the rest.
 298          */
 299         Font2D font2D = FontUtilities.getFont2D(font);
 300         if (font2D instanceof CompositeFont ||
 301             font2D instanceof TrueTypeFont) {
 302             return 1;
 303         } else {
 304             return 0;
 305         }
 306     }
 307 
 308     private static boolean isXP() {
 309         String osVersion = System.getProperty("os.version");
 310         if (osVersion != null) {
 311             Float version = Float.valueOf(osVersion);
 312             return (version.floatValue() >= 5.1f);
 313         } else {
 314             return false;
 315         }
 316     }
 317 
 318     /* In case GDI doesn't handle shaping or BIDI consistently with
 319      * 2D's TextLayout, we can detect these cases and redelegate up to
 320      * be drawn via TextLayout, which in is rendered as runs of
 321      * GlyphVectors, to which we can assign positions for each glyph.
 322      */
 323     private boolean strNeedsTextLayout(String str, Font font) {
 324         char[] chars = str.toCharArray();
 325         boolean isComplex = FontUtilities.isComplexText(chars, 0, chars.length);
 326         if (!isComplex) {
 327             return false;
 328         } else if (!useGDITextLayout) {
 329             return true;
 330         } else {
 331             if (preferGDITextLayout ||
 332                 (isXP() && textLayoutIsCompatible(font))) {
 333                 return false;
 334             } else {
 335                 return true;
 336             }
 337         }
 338     }
 339 
 340     /**
 341      * Used by windows printing to assess if a font is likely to
 342      * be layout compatible with JDK
 343      * TrueType fonts should be, but if they have no GPOS table,
 344      * but do have a GSUB table, then they are probably older
 345      * fonts GDI handles differently.
 346      */
 347     private boolean textLayoutIsCompatible(Font font) {
 348 
 349         Font2D font2D = FontUtilities.getFont2D(font);
 350         if (font2D instanceof TrueTypeFont) {
 351             TrueTypeFont ttf = (TrueTypeFont)font2D;
 352             return
 353                 ttf.getDirectoryEntry(TrueTypeFont.GSUBTag) == null ||
 354                 ttf.getDirectoryEntry(TrueTypeFont.GPOSTag) != null;
 355         } else {
 356             return false;
 357         }
 358     }
 359 
 360     private int getAngle(Point2D.Double pt) {
 361         /* Get the rotation in 1/10'ths degree (as needed by Windows)
 362          * so that GDI can draw the text rotated.
 363          * This calculation is only valid for a uniform scale, no shearing.
 364          */
 365         double angle = Math.toDegrees(Math.atan2(pt.y, pt.x));
 366         if (angle < 0.0) {
 367             angle+= 360.0;
 368         }
 369         /* Windows specifies the rotation anti-clockwise from the x-axis
 370          * of the device, 2D specifies +ve rotation towards the y-axis
 371          * Since the 2D y-axis runs from top-to-bottom, windows angle of
 372          * rotation here is opposite than 2D's, so the rotation needed
 373          * needs to be recalculated in the opposite direction.
 374          */
 375         if (angle != 0.0) {
 376             angle = 360.0 - angle;
 377         }
 378         return (int)Math.round(angle * 10.0);
 379     }


 503          * Although we have already tested that there is no shear,
 504          * there may be a non-uniform scale, so the width of the font
 505          * does not scale equally with the height. That is handled
 506          * by specifying an 'average width' scale to GDI.
 507          */
 508         float fontSize = font.getSize2D();
 509 
 510         Point2D.Double pty = new Point2D.Double(0.0, 1.0);
 511         fontTransform.deltaTransform(pty, pty);
 512         double scaleFactorY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
 513         float scaledFontSizeY = (float)(fontSize * scaleFactorY);
 514 
 515         Point2D.Double ptx = new Point2D.Double(1.0, 0.0);
 516         fontTransform.deltaTransform(ptx, ptx);
 517         double scaleFactorX = Math.sqrt(ptx.x*ptx.x+ptx.y*ptx.y);
 518         float scaledFontSizeX = (float)(fontSize * scaleFactorX);
 519 
 520         float awScale = getAwScale(scaleFactorX, scaleFactorY);
 521         int iangle = getAngle(ptx);
 522 
 523         Font2D font2D = FontUtilities.getFont2D(font);
 524         if (font2D instanceof TrueTypeFont) {
 525             textOut(str, font, (TrueTypeFont)font2D, frc,
 526                     scaledFontSizeY, iangle, awScale,
 527                     deviceTransform, scaleFactorX,
 528                     x, y, devpos.x, devpos.y, targetW);
 529         } else if (font2D instanceof CompositeFont) {
 530             /* Composite fonts are made up of multiple fonts and each
 531              * substring that uses a particular component font needs to
 532              * be separately sent to GDI.
 533              * This works for standard composite fonts, alternate ones,
 534              * Fonts that are a physical font backed by a standard composite,
 535              * and with fallback fonts.
 536              */
 537             CompositeFont compFont = (CompositeFont)font2D;
 538             float userx = x, usery = y;
 539             float devx = devpos.x, devy = devpos.y;
 540             char[] chars = str.toCharArray();
 541             int len = chars.length;
 542             int[] glyphs = new int[len];
 543             compFont.getMapper().charsToGlyphs(len, chars, glyphs);


 698          * When we specify the advances, they are in device space, so
 699          * we don't want any further interpretation applied by GDI, but
 700          * since as noted the advances are interpreted in the HFONT's
 701          * coordinate space, our advances would be rotated again.
 702          * We don't have any way to tell GDI to rotate only the glyphs and
 703          * not the advances, so we need to account for this in the advances
 704          * we supply, by supplying unrotated advances.
 705          * Note that "iangle" is in the opposite direction to 2D's normal
 706          * direction of rotation, so this rotation inverts the
 707          * rotation element of the deviceTransform.
 708          */
 709         AffineTransform advanceTransform =
 710             new AffineTransform(deviceTransform);
 711         advanceTransform.rotate(iangle*Math.PI/1800.0);
 712         float[] glyphAdvPos = new float[glyphPos.length];
 713 
 714         advanceTransform.transform(glyphPos, 0,         //source
 715                                    glyphAdvPos, 0,      //destination
 716                                    glyphPos.length/2);  //num points
 717 
 718         Font2D font2D = FontUtilities.getFont2D(font);
 719         if (font2D instanceof TrueTypeFont) {
 720             String family = font2D.getFamilyName(null);
 721             int style = font.getStyle() | font2D.getStyle();
 722             if (!wPrinterJob.setFont(family, scaledFontSizeY, style,
 723                                      iangle, awScale)) {
 724                 return false;
 725             }
 726             wPrinterJob.glyphsOut(glyphCodes, devpos.x, devpos.y, glyphAdvPos);
 727 
 728         } else if (font2D instanceof CompositeFont) {
 729             /* Composite fonts are made up of multiple fonts and each
 730              * substring that uses a particular component font needs to
 731              * be separately sent to GDI.
 732              * This works for standard composite fonts, alternate ones,
 733              * Fonts that are a physical font backed by a standard composite,
 734              * and with fallback fonts.
 735              */
 736             CompositeFont compFont = (CompositeFont)font2D;
 737             float userx = x, usery = y;
 738             float devx = devpos.x, devy = devpos.y;


 797          boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
 798                                                rotation, awScale);
 799          if (!setFont) {
 800              super.drawString(str, userx, usery, font, frc, targetW);
 801              return;
 802          }
 803 
 804          float[] glyphPos = null;
 805          if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
 806              /* If there is a 1:1 char->glyph mapping then char positions
 807               * are the same as glyph positions and we can tell GDI
 808               * where to place the glyphs.
 809               * On drawing we remove control chars so these need to be
 810               * removed now so the string and positions are the same length.
 811               * For other cases we need to pass glyph codes to GDI.
 812               */
 813              str = wPrinterJob.removeControlChars(str);
 814              char[] chars = str.toCharArray();
 815              int len = chars.length;
 816              GlyphVector gv = null;
 817              if (!FontUtilities.isComplexText(chars, 0, len)) {
 818                  gv = font.createGlyphVector(frc, str);
 819              }
 820              if (gv == null) {
 821                  super.drawString(str, userx, usery, font, frc, targetW);
 822                  return;
 823              }
 824              glyphPos = gv.getGlyphPositions(0, len, null);
 825              Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
 826 
 827              /* GDI advances must not include device space rotation.
 828               * See earlier comment in printGlyphVector() for details.
 829               */
 830              AffineTransform advanceTransform =
 831                new AffineTransform(deviceTransform);
 832              advanceTransform.rotate(rotation*Math.PI/1800.0);
 833              float[] glyphAdvPos = new float[glyphPos.length];
 834 
 835              advanceTransform.transform(glyphPos, 0,         //source
 836                                         glyphAdvPos, 0,      //destination
 837                                         glyphPos.length/2);  //num points