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

Print this page




 477             float translateY = (float)(fontTx.getTranslateY());
 478             if (Math.abs(translateX) < 0.00001) translateX = 0f;
 479             if (Math.abs(translateY) < 0.00001) translateY = 0f;
 480             userpos.x += translateX; userpos.y += translateY;
 481         }
 482         deviceTransform.transform(userpos, devpos);
 483 
 484         if (getClip() != null) {
 485             deviceClip(getClip().getPathIterator(deviceTransform));
 486         }
 487 
 488         /* Get the font size in device coordinates.
 489          * The size needed is the font height scaled to device space.
 490          * Although we have already tested that there is no shear,
 491          * there may be a non-uniform scale, so the width of the font
 492          * does not scale equally with the height. That is handled
 493          * by specifying an 'average width' scale to GDI.
 494          */
 495         float fontSize = font.getSize2D();
 496 


















 497         Point2D.Double pty = new Point2D.Double(0.0, 1.0);
 498         fontTransform.deltaTransform(pty, pty);
 499         double scaleFactorY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
 500         float scaledFontSizeY = (float)(fontSize * scaleFactorY);
 501 
 502         Point2D.Double ptx = new Point2D.Double(1.0, 0.0);
 503         fontTransform.deltaTransform(ptx, ptx);
 504         double scaleFactorX = Math.sqrt(ptx.x*ptx.x+ptx.y*ptx.y);
 505         float scaledFontSizeX = (float)(fontSize * scaleFactorX);
 506 
 507         float awScale = getAwScale(scaleFactorX, scaleFactorY);
 508         int iangle = getAngle(ptx);
 509 







 510         Font2D font2D = FontUtilities.getFont2D(font);
 511         if (font2D instanceof TrueTypeFont) {
 512             textOut(str, font, (TrueTypeFont)font2D, frc,
 513                     scaledFontSizeY, iangle, awScale,
 514                     deviceTransform, scaleFactorX,
 515                     x, y, devpos.x, devpos.y, targetW);
 516         } else if (font2D instanceof CompositeFont) {
 517             /* Composite fonts are made up of multiple fonts and each
 518              * substring that uses a particular component font needs to
 519              * be separately sent to GDI.
 520              * This works for standard composite fonts, alternate ones,
 521              * Fonts that are a physical font backed by a standard composite,
 522              * and with fallback fonts.
 523              */
 524             CompositeFont compFont = (CompositeFont)font2D;
 525             float userx = x, usery = y;
 526             float devx = devpos.x, devy = devpos.y;
 527             char[] chars = str.toCharArray();
 528             int len = chars.length;
 529             int[] glyphs = new int[len];
 530             compFont.getMapper().charsToGlyphs(len, chars, glyphs);
 531 
 532             int startChar = 0, endChar = 0, slot = 0;
 533             while (endChar < len) {
 534 
 535                 startChar = endChar;
 536                 slot = glyphs[startChar] >>> 24;
 537 
 538                 while (endChar < len && ((glyphs[endChar] >>> 24) == slot)) {
 539                     endChar++;
 540                 }
 541                 String substr = new String(chars, startChar,endChar-startChar);
 542                 PhysicalFont slotFont = compFont.getSlotFont(slot);
 543                 textOut(substr, font, slotFont, frc,
 544                         scaledFontSizeY, iangle, awScale,
 545                         deviceTransform, scaleFactorX,
 546                         userx, usery, devx, devy, 0f);
 547                 Rectangle2D bds = font.getStringBounds(substr, frc);
 548                 float xAdvance = (float)bds.getWidth();
 549                 userx += xAdvance;
 550                 userpos.x += xAdvance;
 551                 deviceTransform.transform(userpos, devpos);
 552                 devx = devpos.x;
 553                 devy = devpos.y;
 554             }
 555         } else {
 556             super.drawString(str, x, y, font, frc, targetW);
 557         }
 558     }
 559 
 560     /** return true if the Graphics instance can directly print
 561      * this glyphvector
 562      */
 563     @Override
 564     protected boolean printGlyphVector(GlyphVector gv, float x, float y) {
 565         /* We don't want to try to handle per-glyph transforms. GDI can't


 618             float translateY = (float)(fontTx.getTranslateY());
 619             if (Math.abs(translateX) < 0.00001) translateX = 0f;
 620             if (Math.abs(translateY) < 0.00001) translateY = 0f;
 621             userpos.x += translateX; userpos.y += translateY;
 622         }
 623         deviceTransform.transform(userpos, devpos);
 624 
 625         if (getClip() != null) {
 626             deviceClip(getClip().getPathIterator(deviceTransform));
 627         }
 628 
 629         /* Get the font size in device coordinates.
 630          * The size needed is the font height scaled to device space.
 631          * Although we have already tested that there is no shear,
 632          * there may be a non-uniform scale, so the width of the font
 633          * does not scale equally with the height. That is handled
 634          * by specifying an 'average width' scale to GDI.
 635          */
 636         float fontSize = font.getSize2D();
 637 


















 638         Point2D.Double pty = new Point2D.Double(0.0, 1.0);
 639         fontTransform.deltaTransform(pty, pty);
 640         double scaleFactorY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
 641         float scaledFontSizeY = (float)(fontSize * scaleFactorY);
 642 
 643         Point2D.Double pt = new Point2D.Double(1.0, 0.0);
 644         fontTransform.deltaTransform(pt, pt);
 645         double scaleFactorX = Math.sqrt(pt.x*pt.x+pt.y*pt.y);
 646         float scaledFontSizeX = (float)(fontSize * scaleFactorX);
 647 
 648         float awScale = getAwScale(scaleFactorX, scaleFactorY);
 649         int iangle = getAngle(pt);







 650 
 651         int numGlyphs = gv.getNumGlyphs();
 652         int[] glyphCodes = gv.getGlyphCodes(0, numGlyphs, null);
 653         float[] glyphPos = gv.getGlyphPositions(0, numGlyphs, null);
 654 
 655         /* layout replaces glyphs which have been combined away
 656          * with 0xfffe or 0xffff. These are supposed to be invisible
 657          * and we need to handle this here as GDI will interpret it
 658          * as a missing glyph. We'll do it here by compacting the
 659          * glyph codes array, but we have to do it in conjunction with
 660          * compacting the positions/advances arrays too AND updating
 661          * the number of glyphs ..
 662          * Note that since the slot number for composites is in the
 663          * significant byte we need to mask out that for comparison of
 664          * the invisible glyph.
 665          */
 666         int invisibleGlyphCnt = 0;
 667         for (int gc=0; gc<numGlyphs; gc++) {
 668             if ((glyphCodes[gc] & 0xffff) >=
 669                 CharToGlyphMapper.INVISIBLE_GLYPHS) {


 688             glyphCodes = visibleGlyphCodes;
 689             glyphPos = visiblePositions;
 690         }
 691 
 692         /* To get GDI to rotate glyphs we need to specify the angle
 693          * of rotation to GDI when creating the HFONT. This implicitly
 694          * also rotates the baseline, and this adjusts the X & Y advances
 695          * of the glyphs accordingly.
 696          * When we specify the advances, they are in device space, so
 697          * we don't want any further interpretation applied by GDI, but
 698          * since as noted the advances are interpreted in the HFONT's
 699          * coordinate space, our advances would be rotated again.
 700          * We don't have any way to tell GDI to rotate only the glyphs and
 701          * not the advances, so we need to account for this in the advances
 702          * we supply, by supplying unrotated advances.
 703          * Note that "iangle" is in the opposite direction to 2D's normal
 704          * direction of rotation, so this rotation inverts the
 705          * rotation element of the deviceTransform.
 706          */
 707         AffineTransform advanceTransform =
 708             new AffineTransform(deviceTransform);
 709         advanceTransform.rotate(iangle*Math.PI/1800.0);
 710         float[] glyphAdvPos = new float[glyphPos.length];
 711 
 712         advanceTransform.transform(glyphPos, 0,         //source
 713                                    glyphAdvPos, 0,      //destination
 714                                    glyphPos.length/2);  //num points
 715 
 716         Font2D font2D = FontUtilities.getFont2D(font);
 717         if (font2D instanceof TrueTypeFont) {
 718             String family = font2D.getFamilyName(null);
 719             int style = font.getStyle() | font2D.getStyle();
 720             if (!wPrinterJob.setFont(family, scaledFontSizeY, style,
 721                                      iangle, awScale)) {
 722                 return false;
 723             }
 724             wPrinterJob.glyphsOut(glyphCodes, devpos.x, devpos.y, glyphAdvPos);
 725 
 726         } else if (font2D instanceof CompositeFont) {
 727             /* Composite fonts are made up of multiple fonts and each
 728              * substring that uses a particular component font needs to
 729              * be separately sent to GDI.


 767                 if (start != 0) {
 768                     Point2D.Float p =
 769                         new Point2D.Float(x+glyphPos[start*2],
 770                                           y+glyphPos[start*2+1]);
 771                     deviceTransform.transform(p, p);
 772                     devx = p.x;
 773                     devy = p.y;
 774                 }
 775                 wPrinterJob.glyphsOut(glyphs, devx, devy, posns);
 776             }
 777         } else {
 778             return false;
 779         }
 780         return true;
 781     }
 782 
 783     private void textOut(String str,
 784                           Font font, PhysicalFont font2D,
 785                           FontRenderContext frc,
 786                           float deviceSize, int rotation, float awScale,
 787                           AffineTransform deviceTransform,
 788                           double scaleFactorX,
 789                           float userx, float usery,
 790                           float devx, float devy, float targetW) {
 791 
 792          String family = font2D.getFamilyName(null);
 793          int style = font.getStyle() | font2D.getStyle();
 794          WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
 795          boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
 796                                                rotation, awScale);
 797          if (!setFont) {
 798              super.drawString(str, userx, usery, font, frc, targetW);
 799              return;
 800          }
 801 
 802          float[] glyphPos = null;
 803          if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
 804              /* If there is a 1:1 char->glyph mapping then char positions
 805               * are the same as glyph positions and we can tell GDI
 806               * where to place the glyphs.
 807               * On drawing we remove control chars so these need to be
 808               * removed now so the string and positions are the same length.
 809               * For other cases we need to pass glyph codes to GDI.
 810               */
 811              str = wPrinterJob.removeControlChars(str);
 812              char[] chars = str.toCharArray();
 813              int len = chars.length;
 814              GlyphVector gv = null;
 815              if (!FontUtilities.isComplexText(chars, 0, len)) {
 816                  gv = font.createGlyphVector(frc, str);
 817              }
 818              if (gv == null) {
 819                  super.drawString(str, userx, usery, font, frc, targetW);
 820                  return;
 821              }
 822              glyphPos = gv.getGlyphPositions(0, len, null);
 823              Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
 824 
 825              /* GDI advances must not include device space rotation.
 826               * See earlier comment in printGlyphVector() for details.
 827               */
 828              AffineTransform advanceTransform =
 829                new AffineTransform(deviceTransform);
 830              advanceTransform.rotate(rotation*Math.PI/1800.0);
 831              float[] glyphAdvPos = new float[glyphPos.length];
 832 
 833              advanceTransform.transform(glyphPos, 0,         //source
 834                                         glyphAdvPos, 0,      //destination
 835                                         glyphPos.length/2);  //num points
 836              glyphPos = glyphAdvPos;
 837          }
 838          wPrinterJob.textOut(str, devx, devy, glyphPos);
 839      }
 840 
 841      /* If 2D and GDI agree on the advance of the string we do not
 842       * need to explicitly assign glyph positions.
 843       * If we are to use the GDI advance, require it to agree with
 844       * JDK to a precision of <= 0.2% - ie 1 pixel in 500
 845       * discrepancy after rounding the 2D advance to the
 846       * nearest pixel and is greater than one pixel in total.
 847       * ie strings < 500 pixels in length will be OK so long
 848       * as they differ by only 1 pixel even though that is > 0.02%
 849       * The bounds from 2D are in user space so need to
 850       * be scaled to device space for comparison with GDI.
 851       * scaleX is the scale from user space to device space needed for this.
 852       */
 853      private boolean okGDIMetrics(String str, Font font,
 854                                   FontRenderContext frc, double scaleX) {
 855 
 856          Rectangle2D bds = font.getStringBounds(str, frc);
 857          double jdkAdvance = bds.getWidth();
 858          jdkAdvance = Math.round(jdkAdvance*scaleX);
 859          int gdiAdvance = ((WPrinterJob)getPrinterJob()).getGDIAdvance(str);
 860          if (jdkAdvance > 0 && gdiAdvance > 0) {
 861              double diff = Math.abs(gdiAdvance-jdkAdvance);
 862              double ratio = gdiAdvance/jdkAdvance;
 863              if (ratio < 1) {
 864                  ratio = 1/ratio;
 865              }
 866              return diff <= 1 || ratio < 1.002;
 867          }
 868          return true;
 869      }
 870 
 871     /**
 872      * The various <code>drawImage()</code> methods for
 873      * <code>WPathGraphics</code> are all decomposed
 874      * into an invocation of <code>drawImageToPlatform</code>.
 875      * The portion of the passed in image defined by
 876      * <code>srcX, srcY, srcWidth, and srcHeight</code>
 877      * is transformed by the supplied AffineTransform and
 878      * drawn using GDI to the printer context.
 879      *
 880      * @param   img     The image to be drawn.
 881      * @param   xform   Used to transform the image before drawing.
 882      *                  This can be null.
 883      * @param   bgcolor This color is drawn where the image has transparent
 884      *                  pixels. If this parameter is null then the
 885      *                  pixels already in the destination should show
 886      *                  through.




 477             float translateY = (float)(fontTx.getTranslateY());
 478             if (Math.abs(translateX) < 0.00001) translateX = 0f;
 479             if (Math.abs(translateY) < 0.00001) translateY = 0f;
 480             userpos.x += translateX; userpos.y += translateY;
 481         }
 482         deviceTransform.transform(userpos, devpos);
 483 
 484         if (getClip() != null) {
 485             deviceClip(getClip().getPathIterator(deviceTransform));
 486         }
 487 
 488         /* Get the font size in device coordinates.
 489          * The size needed is the font height scaled to device space.
 490          * Although we have already tested that there is no shear,
 491          * there may be a non-uniform scale, so the width of the font
 492          * does not scale equally with the height. That is handled
 493          * by specifying an 'average width' scale to GDI.
 494          */
 495         float fontSize = font.getSize2D();
 496 
 497         double devResX = wPrinterJob.getXRes();
 498         double devResY = wPrinterJob.getYRes();
 499 
 500         double fontDevScaleY = devResY / DEFAULT_USER_RES;
 501 
 502         int orient = getPageFormat().getOrientation();
 503         if (orient == PageFormat.LANDSCAPE ||
 504             orient == PageFormat.REVERSE_LANDSCAPE)
 505         {
 506             double tmp = devResX;
 507             devResX = devResY;
 508             devResY = tmp;
 509         }
 510 
 511         double devScaleX = devResX / DEFAULT_USER_RES;
 512         double devScaleY = devResY / DEFAULT_USER_RES;
 513         fontTransform.scale(1.0/devScaleX, 1.0/devScaleY);
 514 
 515         Point2D.Double pty = new Point2D.Double(0.0, 1.0);
 516         fontTransform.deltaTransform(pty, pty);
 517         double scaleFactorY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
 518         float scaledFontSizeY = (float)(fontSize * scaleFactorY * fontDevScaleY);
 519 
 520         Point2D.Double ptx = new Point2D.Double(1.0, 0.0);
 521         fontTransform.deltaTransform(ptx, ptx);
 522         double scaleFactorX = Math.sqrt(ptx.x*ptx.x+ptx.y*ptx.y);

 523 
 524         float awScale = getAwScale(scaleFactorX, scaleFactorY);
 525         int iangle = getAngle(ptx);
 526 
 527         ptx = new Point2D.Double(1.0, 0.0);
 528         deviceTransform.deltaTransform(ptx, ptx);
 529         double advanceScaleX = Math.sqrt(ptx.x*ptx.x+ptx.y*ptx.y);
 530         pty = new Point2D.Double(0.0, 1.0);
 531         deviceTransform.deltaTransform(pty, pty);
 532         double advanceScaleY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
 533 
 534         Font2D font2D = FontUtilities.getFont2D(font);
 535         if (font2D instanceof TrueTypeFont) {
 536             textOut(str, font, (TrueTypeFont)font2D, frc,
 537                     scaledFontSizeY, iangle, awScale,
 538                     advanceScaleX, advanceScaleY,
 539                     x, y, devpos.x, devpos.y, targetW);
 540         } else if (font2D instanceof CompositeFont) {
 541             /* Composite fonts are made up of multiple fonts and each
 542              * substring that uses a particular component font needs to
 543              * be separately sent to GDI.
 544              * This works for standard composite fonts, alternate ones,
 545              * Fonts that are a physical font backed by a standard composite,
 546              * and with fallback fonts.
 547              */
 548             CompositeFont compFont = (CompositeFont)font2D;
 549             float userx = x, usery = y;
 550             float devx = devpos.x, devy = devpos.y;
 551             char[] chars = str.toCharArray();
 552             int len = chars.length;
 553             int[] glyphs = new int[len];
 554             compFont.getMapper().charsToGlyphs(len, chars, glyphs);
 555 
 556             int startChar = 0, endChar = 0, slot = 0;
 557             while (endChar < len) {
 558 
 559                 startChar = endChar;
 560                 slot = glyphs[startChar] >>> 24;
 561 
 562                 while (endChar < len && ((glyphs[endChar] >>> 24) == slot)) {
 563                     endChar++;
 564                 }
 565                 String substr = new String(chars, startChar,endChar-startChar);
 566                 PhysicalFont slotFont = compFont.getSlotFont(slot);
 567                 textOut(substr, font, slotFont, frc,
 568                         scaledFontSizeY, iangle, awScale,
 569                         advanceScaleX, advanceScaleY,
 570                         userx, usery, devx, devy, 0f);
 571                 Rectangle2D bds = font.getStringBounds(substr, frc);
 572                 float xAdvance = (float)bds.getWidth();
 573                 userx += xAdvance;
 574                 userpos.x += xAdvance;
 575                 deviceTransform.transform(userpos, devpos);
 576                 devx = devpos.x;
 577                 devy = devpos.y;
 578             }
 579         } else {
 580             super.drawString(str, x, y, font, frc, targetW);
 581         }
 582     }
 583 
 584     /** return true if the Graphics instance can directly print
 585      * this glyphvector
 586      */
 587     @Override
 588     protected boolean printGlyphVector(GlyphVector gv, float x, float y) {
 589         /* We don't want to try to handle per-glyph transforms. GDI can't


 642             float translateY = (float)(fontTx.getTranslateY());
 643             if (Math.abs(translateX) < 0.00001) translateX = 0f;
 644             if (Math.abs(translateY) < 0.00001) translateY = 0f;
 645             userpos.x += translateX; userpos.y += translateY;
 646         }
 647         deviceTransform.transform(userpos, devpos);
 648 
 649         if (getClip() != null) {
 650             deviceClip(getClip().getPathIterator(deviceTransform));
 651         }
 652 
 653         /* Get the font size in device coordinates.
 654          * The size needed is the font height scaled to device space.
 655          * Although we have already tested that there is no shear,
 656          * there may be a non-uniform scale, so the width of the font
 657          * does not scale equally with the height. That is handled
 658          * by specifying an 'average width' scale to GDI.
 659          */
 660         float fontSize = font.getSize2D();
 661 
 662         double devResX = wPrinterJob.getXRes();
 663         double devResY = wPrinterJob.getYRes();
 664 
 665         double fontDevScaleY = devResY / DEFAULT_USER_RES;
 666 
 667         int orient = getPageFormat().getOrientation();
 668         if (orient == PageFormat.LANDSCAPE ||
 669             orient == PageFormat.REVERSE_LANDSCAPE)
 670         {
 671             double tmp = devResX;
 672             devResX = devResY;
 673             devResY = tmp;
 674         }
 675 
 676         double devScaleX = devResX / DEFAULT_USER_RES;
 677         double devScaleY = devResY / DEFAULT_USER_RES;
 678         fontTransform.scale(1.0/devScaleX, 1.0/devScaleY);
 679 
 680         Point2D.Double pty = new Point2D.Double(0.0, 1.0);
 681         fontTransform.deltaTransform(pty, pty);
 682         double scaleFactorY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
 683         float scaledFontSizeY = (float)(fontSize * scaleFactorY * fontDevScaleY);
 684 
 685         Point2D.Double ptx = new Point2D.Double(1.0, 0.0);
 686         fontTransform.deltaTransform(ptx, ptx);
 687         double scaleFactorX = Math.sqrt(ptx.x*ptx.x+ptx.y*ptx.y);

 688 
 689         float awScale = getAwScale(scaleFactorX, scaleFactorY);
 690         int iangle = getAngle(ptx);
 691 
 692         ptx = new Point2D.Double(1.0, 0.0);
 693         deviceTransform.deltaTransform(ptx, ptx);
 694         double advanceScaleX = Math.sqrt(ptx.x*ptx.x+ptx.y*ptx.y);
 695         pty = new Point2D.Double(0.0, 1.0);
 696         deviceTransform.deltaTransform(pty, pty);
 697         double advanceScaleY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
 698 
 699         int numGlyphs = gv.getNumGlyphs();
 700         int[] glyphCodes = gv.getGlyphCodes(0, numGlyphs, null);
 701         float[] glyphPos = gv.getGlyphPositions(0, numGlyphs, null);
 702 
 703         /* layout replaces glyphs which have been combined away
 704          * with 0xfffe or 0xffff. These are supposed to be invisible
 705          * and we need to handle this here as GDI will interpret it
 706          * as a missing glyph. We'll do it here by compacting the
 707          * glyph codes array, but we have to do it in conjunction with
 708          * compacting the positions/advances arrays too AND updating
 709          * the number of glyphs ..
 710          * Note that since the slot number for composites is in the
 711          * significant byte we need to mask out that for comparison of
 712          * the invisible glyph.
 713          */
 714         int invisibleGlyphCnt = 0;
 715         for (int gc=0; gc<numGlyphs; gc++) {
 716             if ((glyphCodes[gc] & 0xffff) >=
 717                 CharToGlyphMapper.INVISIBLE_GLYPHS) {


 736             glyphCodes = visibleGlyphCodes;
 737             glyphPos = visiblePositions;
 738         }
 739 
 740         /* To get GDI to rotate glyphs we need to specify the angle
 741          * of rotation to GDI when creating the HFONT. This implicitly
 742          * also rotates the baseline, and this adjusts the X & Y advances
 743          * of the glyphs accordingly.
 744          * When we specify the advances, they are in device space, so
 745          * we don't want any further interpretation applied by GDI, but
 746          * since as noted the advances are interpreted in the HFONT's
 747          * coordinate space, our advances would be rotated again.
 748          * We don't have any way to tell GDI to rotate only the glyphs and
 749          * not the advances, so we need to account for this in the advances
 750          * we supply, by supplying unrotated advances.
 751          * Note that "iangle" is in the opposite direction to 2D's normal
 752          * direction of rotation, so this rotation inverts the
 753          * rotation element of the deviceTransform.
 754          */
 755         AffineTransform advanceTransform =
 756            AffineTransform.getScaleInstance(advanceScaleX, advanceScaleY);

 757         float[] glyphAdvPos = new float[glyphPos.length];
 758 
 759         advanceTransform.transform(glyphPos, 0,         //source
 760                                    glyphAdvPos, 0,      //destination
 761                                    glyphPos.length/2);  //num points
 762 
 763         Font2D font2D = FontUtilities.getFont2D(font);
 764         if (font2D instanceof TrueTypeFont) {
 765             String family = font2D.getFamilyName(null);
 766             int style = font.getStyle() | font2D.getStyle();
 767             if (!wPrinterJob.setFont(family, scaledFontSizeY, style,
 768                                      iangle, awScale)) {
 769                 return false;
 770             }
 771             wPrinterJob.glyphsOut(glyphCodes, devpos.x, devpos.y, glyphAdvPos);
 772 
 773         } else if (font2D instanceof CompositeFont) {
 774             /* Composite fonts are made up of multiple fonts and each
 775              * substring that uses a particular component font needs to
 776              * be separately sent to GDI.


 814                 if (start != 0) {
 815                     Point2D.Float p =
 816                         new Point2D.Float(x+glyphPos[start*2],
 817                                           y+glyphPos[start*2+1]);
 818                     deviceTransform.transform(p, p);
 819                     devx = p.x;
 820                     devy = p.y;
 821                 }
 822                 wPrinterJob.glyphsOut(glyphs, devx, devy, posns);
 823             }
 824         } else {
 825             return false;
 826         }
 827         return true;
 828     }
 829 
 830     private void textOut(String str,
 831                           Font font, PhysicalFont font2D,
 832                           FontRenderContext frc,
 833                           float deviceSize, int rotation, float awScale,
 834                           double scaleFactorX, double scaleFactorY,

 835                           float userx, float usery,
 836                           float devx, float devy, float targetW) {
 837 
 838          String family = font2D.getFamilyName(null);
 839          int style = font.getStyle() | font2D.getStyle();
 840          WPrinterJob wPrinterJob = (WPrinterJob)getPrinterJob();
 841          boolean setFont = wPrinterJob.setFont(family, deviceSize, style,
 842                                                rotation, awScale);
 843          if (!setFont) {
 844              super.drawString(str, userx, usery, font, frc, targetW);
 845              return;
 846          }
 847 
 848          float[] glyphPos = null;
 849          if (!okGDIMetrics(str, font, frc, scaleFactorX)) {
 850              /* If there is a 1:1 char->glyph mapping then char positions
 851               * are the same as glyph positions and we can tell GDI
 852               * where to place the glyphs.
 853               * On drawing we remove control chars so these need to be
 854               * removed now so the string and positions are the same length.
 855               * For other cases we need to pass glyph codes to GDI.
 856               */
 857              str = wPrinterJob.removeControlChars(str);
 858              char[] chars = str.toCharArray();
 859              int len = chars.length;
 860              GlyphVector gv = null;
 861              if (!FontUtilities.isComplexText(chars, 0, len)) {
 862                  gv = font.createGlyphVector(frc, str);
 863              }
 864              if (gv == null) {
 865                  super.drawString(str, userx, usery, font, frc, targetW);
 866                  return;
 867              }
 868              glyphPos = gv.getGlyphPositions(0, len, null);
 869              Point2D gvAdvPt = gv.getGlyphPosition(gv.getNumGlyphs());
 870 
 871              /* GDI advances must not include device space rotation.
 872               * See earlier comment in printGlyphVector() for details.
 873               */
 874              AffineTransform advanceTransform =
 875                 AffineTransform.getScaleInstance(scaleFactorX, scaleFactorY);

 876              float[] glyphAdvPos = new float[glyphPos.length];
 877 
 878              advanceTransform.transform(glyphPos, 0,         //source
 879                                         glyphAdvPos, 0,      //destination
 880                                         glyphPos.length/2);  //num points
 881              glyphPos = glyphAdvPos;
 882          }
 883          wPrinterJob.textOut(str, devx, devy, glyphPos);
 884      }
 885 
 886      /* If 2D and GDI agree on the advance of the string we do not
 887       * need to explicitly assign glyph positions.
 888       * If we are to use the GDI advance, require it to agree with
 889       * JDK to a precision of <= 1.0% - ie 1 pixel in 100
 890       * discrepancy after rounding the 2D advance to the
 891       * nearest pixel and is greater than one pixel in total.
 892       * ie strings < 100 pixels in length will be OK so long
 893       * as they differ by only 1 pixel even though that is > 1%
 894       * The bounds from 2D are in user space so need to
 895       * be scaled to device space for comparison with GDI.
 896       * scaleX is the scale from user space to device space needed for this.
 897       */
 898      private boolean okGDIMetrics(String str, Font font,
 899                                   FontRenderContext frc, double scaleX) {
 900 
 901          Rectangle2D bds = font.getStringBounds(str, frc);
 902          double jdkAdvance = bds.getWidth();
 903          jdkAdvance = Math.round(jdkAdvance*scaleX);
 904          int gdiAdvance = ((WPrinterJob)getPrinterJob()).getGDIAdvance(str);
 905          if (jdkAdvance > 0 && gdiAdvance > 0) {
 906              double diff = Math.abs(gdiAdvance-jdkAdvance);
 907              double ratio = gdiAdvance/jdkAdvance;
 908              if (ratio < 1) {
 909                  ratio = 1/ratio;
 910              }
 911              return diff <= 1 || ratio < 1.01;
 912          }
 913          return true;
 914      }
 915 
 916     /**
 917      * The various <code>drawImage()</code> methods for
 918      * <code>WPathGraphics</code> are all decomposed
 919      * into an invocation of <code>drawImageToPlatform</code>.
 920      * The portion of the passed in image defined by
 921      * <code>srcX, srcY, srcWidth, and srcHeight</code>
 922      * is transformed by the supplied AffineTransform and
 923      * drawn using GDI to the printer context.
 924      *
 925      * @param   img     The image to be drawn.
 926      * @param   xform   Used to transform the image before drawing.
 927      *                  This can be null.
 928      * @param   bgcolor This color is drawn where the image has transparent
 929      *                  pixels. If this parameter is null then the
 930      *                  pixels already in the destination should show
 931      *                  through.