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.
|