You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-dev@xmlgraphics.apache.org by de...@apache.org on 2003/05/08 13:39:13 UTC

cvs commit: xml-batik/sources/org/apache/batik/gvt/text GlyphLayout.java

deweese     2003/05/08 04:39:13

  Modified:    samples/tests/spec/painting text-rendering.svg
               sources/org/apache/batik/bridge CSSUtilities.java
               sources/org/apache/batik/gvt/font AWTGVTGlyphVector.java
               sources/org/apache/batik/gvt/renderer BasicTextPainter.java
                        StrokingTextPainter.java
               sources/org/apache/batik/gvt/text GlyphLayout.java
  Log:
  With JDK 1.4 text-rendering="optimizeSpeed" will render
  non-anti-aliased hinted text (for axially aligned text).
  
  Revision  Changes    Path
  1.3       +16 -9     xml-batik/samples/tests/spec/painting/text-rendering.svg
  
  Index: text-rendering.svg
  ===================================================================
  RCS file: /home/cvs/xml-batik/samples/tests/spec/painting/text-rendering.svg,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- text-rendering.svg	20 Nov 2001 15:08:25 -0000	1.2
  +++ text-rendering.svg	8 May 2003 11:39:12 -0000	1.3
  @@ -32,17 +32,24 @@
   
     <g style="text-anchor:middle;font-size:64;font-weight:bold;fill:gold;stroke:crimson;stroke-width:2">
   
  -  <text x="120" y="180" style="text-rendering:auto">Batik</text>
  -  <text x="330" y="180" style="text-rendering:optimizeSpeed">Batik</text>
  -  <text x="120" y="330" style="text-rendering:optimizeLegibility">Batik</text>
  -  <text x="330" y="330" style="text-rendering:geometricPrecision">Batik</text>
  +  <text x="120" y="130" style="text-rendering:auto">Batik</text>
  +  <text x="330" y="130" style="text-rendering:optimizeSpeed">Batik</text>
  +  <text x="120" y="280" style="text-rendering:optimizeLegibility">Batik</text>
  +  <text x="330" y="280" style="text-rendering:geometricPrecision">Batik</text>
  +  </g>
  +
  +  <g style="text-anchor:middle;font-size:64;font-weight:bold;fill:crimson">
  +      <text x="120" y="200" text-rendering="auto"              >Batik</text>
  +      <text x="330" y="200" text-rendering="optimizeSpeed"     >Batik</text>
  +      <text x="120" y="350" text-rendering="optimizeLegibility">Batik</text>
  +      <text x="330" y="350" text-rendering="geometricPrecision">Batik</text>
     </g>
   
     <g style="font-size:11;fill:black;stroke:none;text-anchor:middle">
  -  <text x="120" y="204">auto</text>
  -  <text x="330" y="204">optimizeSpeed</text>
  -  <text x="120" y="354">optimizeLegibility</text>
  -  <text x="330" y="354">geometricPrecision</text>
  +  <text x="120" y="224" text-rendering="auto"              >auto</text>
  +  <text x="330" y="224" text-rendering="optimizeSpeed"     >optimizeSpeed</text>
  +  <text x="120" y="374" text-rendering="optimizeLegibility">optimizeLegibility</text>
  +  <text x="330" y="374" text-rendering="geometricPrecision">geometricPrecision</text>
     </g>
   </g>
   
  
  
  
  1.42      +8 -8      xml-batik/sources/org/apache/batik/bridge/CSSUtilities.java
  
  Index: CSSUtilities.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/CSSUtilities.java,v
  retrieving revision 1.41
  retrieving revision 1.42
  diff -u -r1.41 -r1.42
  --- CSSUtilities.java	11 Apr 2003 13:54:42 -0000	1.41
  +++ CSSUtilities.java	8 May 2003 11:39:12 -0000	1.42
  @@ -385,26 +385,26 @@
                         RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
               hints.put(RenderingHints.KEY_ANTIALIASING,
                         RenderingHints.VALUE_ANTIALIAS_OFF);
  -            hints.put(RenderingHints.KEY_FRACTIONALMETRICS,
  -                      RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
  +            // hints.put(RenderingHints.KEY_FRACTIONALMETRICS,
  +            //           RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
               break;
           case 'l': // optimizeLegibility
               hints.put(RenderingHints.KEY_RENDERING,
                         RenderingHints.VALUE_RENDER_QUALITY);
               hints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
  -                      RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  +                      RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
               hints.put(RenderingHints.KEY_ANTIALIASING,
                         RenderingHints.VALUE_ANTIALIAS_ON);
  -            hints.put(RenderingHints.KEY_FRACTIONALMETRICS,
  -                      RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
  +            // hints.put(RenderingHints.KEY_FRACTIONALMETRICS,
  +            //           RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
               break;
           case 'c': // geometricPrecision
               hints.put(RenderingHints.KEY_RENDERING,
                         RenderingHints.VALUE_RENDER_QUALITY);
               hints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
  -                      RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
  +                      RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
               hints.put(RenderingHints.KEY_ANTIALIASING,
  -                      RenderingHints.VALUE_ANTIALIAS_DEFAULT);
  +                      RenderingHints.VALUE_ANTIALIAS_ON);
               hints.put(RenderingHints.KEY_FRACTIONALMETRICS,
                         RenderingHints.VALUE_FRACTIONALMETRICS_ON);
               break;
  
  
  
  1.22      +101 -10   xml-batik/sources/org/apache/batik/gvt/font/AWTGVTGlyphVector.java
  
  Index: AWTGVTGlyphVector.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/font/AWTGVTGlyphVector.java,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- AWTGVTGlyphVector.java	11 Apr 2003 13:58:43 -0000	1.21
  +++ AWTGVTGlyphVector.java	8 May 2003 11:39:12 -0000	1.22
  @@ -472,15 +472,19 @@
       }
   
       private static final boolean outlinesPositioned;
  +    private static final boolean glyphVectorTransformWorks;
   
       static {
           String s = System.getProperty("java.specification.version");
           if ("1.4".compareTo(s) <= 0) {
               outlinesPositioned = true;
  +            glyphVectorTransformWorks = true;
           } else if ("Mac OS X".equals(System.getProperty("os.name"))) {
               outlinesPositioned = true;
  +            glyphVectorTransformWorks = false;  // Note sure about this...
           } else {
               outlinesPositioned = false;
  +            glyphVectorTransformWorks = false;
           }
       }
   
  @@ -743,26 +747,113 @@
        */
       public void draw(Graphics2D graphics2D,
                        AttributedCharacterIterator aci) {
  +        int numGlyphs = getNumGlyphs();
   
           aci.first();
  +        Paint fillPaint = (Paint)aci.getAttribute(TextAttribute.FOREGROUND);
  +        Stroke stroke = (Stroke) aci.getAttribute
  +            (GVTAttributedCharacterIterator.TextAttribute.STROKE);
  +        Paint strokePaint = (Paint) aci.getAttribute
  +            (GVTAttributedCharacterIterator.TextAttribute.STROKE_PAINT);
  +        if ((fillPaint == null) && ((strokePaint == null) ||
  +                                    (stroke == null)))
  +            return;
  +
  +        boolean useHinting = true;
  +        if ((stroke != null) && (strokePaint != null))
  +            useHinting = false;
  +
  +        final int typeGRot   = AffineTransform.TYPE_GENERAL_ROTATION;
  +        final int typeGTrans = AffineTransform.TYPE_GENERAL_TRANSFORM;
  +        if (useHinting) {
  +            // Check if usr->dev transform has general rotation,
  +            // or shear..
  +            AffineTransform at = graphics2D.getTransform();
  +            int type = at.getType();
  +            if (((type & typeGTrans) != 0) || ((type & typeGRot)  != 0))
  +                useHinting = false;
  +        }
  +            
  +        if (useHinting) {
  +            double [] mat = new double[4];
  +            for (int i=0; i<numGlyphs; i++) {
  +                if (!glyphVisible[i]) {
  +                    useHinting = false;
  +                    break;
  +                }
  +                AffineTransform at = glyphTransforms[i];
  +                if (at != null) {
  +                    int type = at.getType();
  +                    if ((type & ~AffineTransform.TYPE_TRANSLATION) == 0) {
  +                        // Just translation
  +                    } else if (glyphVectorTransformWorks &&
  +                               ((type & typeGTrans) == 0) &&
  +                               ((type & typeGRot)   == 0)) {
  +                        // It's a simple 90Deg rotate, and we can put
  +                        // it into the GlyphVector.
  +                    } else {
  +                        // we can't (or it doesn't make sense
  +                        // to use the GlyphVector.
  +                        useHinting = false;
  +                        break;
  +                    }
  +                }
  +            }
  +        }
  +
  +        if (useHinting) {
  +            double sf = scaleFactor;
  +            double [] mat = new double[6];
  +            for (int i=0; i< numGlyphs; i++) {
  +                Point2D         pos = glyphPositions[i];
  +                double x = pos.getX();
  +                double y = pos.getY();
  +                AffineTransform at = glyphTransforms[i];
  +                if (at != null) {
  +                    // Scale the translate portion of matrix,
  +                    // and add it into the position.
  +                    at.getMatrix(mat);
  +                    x += mat[4];
  +                    y += mat[5];
  +                    if ((mat[0] != 1) || (mat[1] != 0) ||
  +                        (mat[2] != 0) || (mat[3] != 1)) {
  +                        // More than just translation.
  +                        mat[4] = 0; mat[5] = 0;
  +                        at = new AffineTransform(mat);
  +                    } else {
  +                        at = null;
  +                    }
  +                }
  +                pos = new Point2D.Double(x/sf, y/sf);
  +                awtGlyphVector.setGlyphPosition(i, pos);
  +                awtGlyphVector.setGlyphTransform(i, at);
  +            }
  +            graphics2D.scale(sf, sf);
  +            graphics2D.setPaint(fillPaint);
  +            graphics2D.drawGlyphVector(awtGlyphVector, 0, 0);
  +            graphics2D.scale(1/sf, 1/sf);
  +
  +            for (int i=0; i< numGlyphs; i++) {
  +                Point2D         pos = defaultGlyphPositions[i];
  +                awtGlyphVector.setGlyphPosition(i, pos);
  +                awtGlyphVector.setGlyphTransform(i, null);
  +            }
  +
  +        } else {
           Shape outline = getOutline();
   
           // check if we need to fill this glyph
  -        Paint paint = (Paint) aci.getAttribute(TextAttribute.FOREGROUND);
  -        if (paint != null) {
  -            graphics2D.setPaint(paint);
  +            if (fillPaint != null) {
  +                graphics2D.setPaint(fillPaint);
               graphics2D.fill(outline);
           }
   
           // check if we need to draw the outline of this glyph
  -        Stroke stroke = (Stroke) aci.getAttribute
  -            (GVTAttributedCharacterIterator.TextAttribute.STROKE);
  -        paint = (Paint) aci.getAttribute
  -            (GVTAttributedCharacterIterator.TextAttribute.STROKE_PAINT);
  -        if (stroke != null && paint != null) {
  +            if (stroke != null && strokePaint != null) {
               graphics2D.setStroke(stroke);
  -            graphics2D.setPaint(paint);
  +                graphics2D.setPaint(strokePaint);
               graphics2D.draw(outline);
  +            }
           }
       }
   }
  
  
  
  1.15      +4 -1      xml-batik/sources/org/apache/batik/gvt/renderer/BasicTextPainter.java
  
  Index: BasicTextPainter.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/renderer/BasicTextPainter.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- BasicTextPainter.java	11 Apr 2003 13:58:44 -0000	1.14
  +++ BasicTextPainter.java	8 May 2003 11:39:12 -0000	1.15
  @@ -40,6 +40,9 @@
       protected FontRenderContext fontRenderContext =
   	new FontRenderContext(new AffineTransform(), true, true);
   
  +    protected FontRenderContext aaOffFontRenderContext =
  +	new FontRenderContext(new AffineTransform(), false, true);
  +
       protected TextLayoutFactory getTextLayoutFactory() {
           return textLayoutFactory;
       }
  
  
  
  1.44      +17 -2     xml-batik/sources/org/apache/batik/gvt/renderer/StrokingTextPainter.java
  
  Index: StrokingTextPainter.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/renderer/StrokingTextPainter.java,v
  retrieving revision 1.43
  retrieving revision 1.44
  diff -u -r1.43 -r1.44
  --- StrokingTextPainter.java	11 Apr 2003 13:58:44 -0000	1.43
  +++ StrokingTextPainter.java	8 May 2003 11:39:12 -0000	1.44
  @@ -11,8 +11,10 @@
   import java.awt.Composite;
   import java.awt.Graphics2D;
   import java.awt.Paint;
  +import java.awt.RenderingHints;
   import java.awt.Shape;
   import java.awt.Stroke;
  +import java.awt.font.FontRenderContext;
   import java.awt.font.TextAttribute;
   import java.awt.geom.GeneralPath;
   import java.awt.geom.Point2D;
  @@ -624,8 +626,21 @@
                   subCharMap[i] = charMap[i+start-begin];
               }
   
  +            FontRenderContext frc = fontRenderContext;
  +            RenderingHints rh = node.getRenderingHints();
  +            // Check for optimizeSpeed, optimizeLegibility
  +            // in these cases setup hintedFRC
  +            if ((rh != null) &&
  +                (rh.get(RenderingHints.KEY_TEXT_ANTIALIASING) ==
  +                  RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)) {
  +                // In both these cases we want the non-antialiased
  +                // font render context.
  +                frc = aaOffFontRenderContext;
  +            }
  +
               layout = getTextLayoutFactory().createTextLayout
  -                (runaci, subCharMap, offset, fontRenderContext);
  +                (runaci, subCharMap, offset, frc);
  +
               textRuns.add(new TextRun(layout, runaci, isChunkStart));
               // System.out.println("TextRun: " + start +  "->" + end + 
               //                    " Start: " + isChunkStart);
  
  
  
  1.52      +18 -4     xml-batik/sources/org/apache/batik/gvt/text/GlyphLayout.java
  
  Index: GlyphLayout.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/text/GlyphLayout.java,v
  retrieving revision 1.51
  retrieving revision 1.52
  diff -u -r1.51 -r1.52
  --- GlyphLayout.java	11 Apr 2003 13:58:48 -0000	1.51
  +++ GlyphLayout.java	8 May 2003 11:39:13 -0000	1.52
  @@ -644,8 +644,10 @@
   
           return shape;
       }
  -
       public static final float eps = 0.00001f;
  +    public static boolean epsEQ(double a, double b) {
  +        return ((a+eps > b) && (a-eps < b));
  +    }
   
       public static int makeConvexHull(Point2D.Float [] pts, int numPts) {
           // Sort the Pts in X...
  @@ -1312,12 +1314,24 @@
               }
   
               // rotate the glyph
  -            if (glyphRotation != 0f) {
  +            if (!epsEQ(glyphRotation,0)) {
                   AffineTransform glyphTransform = gv.getGlyphTransform(i);
                   if (glyphTransform == null) {
                       glyphTransform = new AffineTransform();
                   }
  -                glyphTransform.rotate(glyphRotation);
  +                AffineTransform rotAt;
  +                // Make the 90Deg rotations slightly 'snap to'.
  +                // Also use explicit matrix to avoid round-off.
  +                if (epsEQ(glyphRotation, Math.PI/2)) {
  +                    rotAt = new AffineTransform(0, 1, -1, 0, 0, 0);
  +                } else if (epsEQ(glyphRotation, Math.PI)) {
  +                    rotAt = new AffineTransform(-1, 0, 0, -1, 0, 0);
  +                } else if (epsEQ(glyphRotation, 3*Math.PI/2)) {
  +                    rotAt = new AffineTransform(0, -1, 1, 0, 0, 0);
  +                } else {
  +                    rotAt = AffineTransform.getRotateInstance(glyphRotation);
  +                }
  +                glyphTransform.concatenate(rotAt);
                   gv.setGlyphTransform(i, glyphTransform);
               }
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org