changeset 7890:20ee873c49f1

Fix RT-23822: Support FontSmoothingType in Canvas fillText() Reviewed by: felipe, kcr
author flar <James.Graham@oracle.com>
date Wed, 27 Aug 2014 15:24:38 -0700
parents 99757c39bff9
children 0549284f26c9
files modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGCanvas.java modules/graphics/src/main/java/javafx/scene/canvas/GraphicsContext.java modules/graphics/src/test/java/javafx/scene/canvas/CanvasTest.java
diffstat 3 files changed, 93 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGCanvas.java	Wed Aug 27 22:20:20 2014 +0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGCanvas.java	Wed Aug 27 15:24:38 2014 -0700
@@ -70,6 +70,7 @@
 import com.sun.scenario.effect.impl.prism.PrDrawable;
 import com.sun.scenario.effect.impl.prism.PrFilterContext;
 import com.sun.scenario.effect.impl.prism.PrTexture;
+import javafx.scene.text.FontSmoothingType;
 
 /**
  */
@@ -94,6 +95,7 @@
     public static final byte FILL_RULE     = ATTR_BASE + 16;
     public static final byte DASH_ARRAY    = ATTR_BASE + 17;
     public static final byte DASH_OFFSET   = ATTR_BASE + 18;
+    public static final byte FONT_SMOOTH   = ATTR_BASE + 19;
 
     public static final byte                     OP_BASE = 20;
     public static final byte FILL_RECT         = OP_BASE + 0;
@@ -145,6 +147,9 @@
     public static final byte ARC_CHORD  = 1;
     public static final byte ARC_PIE    = 2;
 
+    public static final byte SMOOTH_GRAY = (byte) FontSmoothingType.GRAY.ordinal();
+    public static final byte SMOOTH_LCD  = (byte) FontSmoothingType.LCD.ordinal();
+
     public static final byte ALIGN_LEFT       = 0;
     public static final byte ALIGN_CENTER     = 1;
     public static final byte ALIGN_RIGHT      = 2;
@@ -325,6 +330,7 @@
     private NGText ngtext;
     private PrismTextLayout textLayout;
     private PGFont pgfont;
+    private int smoothing;
     private int align;
     private int baseline;
     private Affine2D transform;
@@ -370,6 +376,7 @@
         // ngtext stores no state between render operations
         // textLayout stores no state between render operations
         pgfont = (PGFont) Font.getDefault().impl_getNativeFont();
+        smoothing = SMOOTH_GRAY;
         align = ALIGN_LEFT;
         baseline = VPos.BASELINE.ordinal();
         transform.setToScale(highestPixelScale, highestPixelScale);
@@ -979,10 +986,11 @@
                     stroke = null;
                     break;
                 case FONT:
-                {
                     pgfont = (PGFont) buf.getObject();
                     break;
-                }
+                case FONT_SMOOTH:
+                    smoothing = buf.getUByte();
+                    break;
                 case TEXT_ALIGN:
                     align = buf.getUByte();
                     break;
@@ -1390,14 +1398,15 @@
                     if (token == FILL_TEXT) {
                         ngtext.setMode(NGShape.Mode.FILL);
                         ngtext.setFillPaint(fillPaint);
-                        if (fillPaint.isProportional()) {
+                        if (fillPaint.isProportional() || smoothing == SMOOTH_LCD) {
                             RectBounds textBounds = new RectBounds();
                             computeTextLayoutBounds(textBounds, BaseTransform.IDENTITY_TRANSFORM,
                                                     1, layoutX, layoutY, token);
                             ngtext.setContentBounds(textBounds);
                         }
                     } else {
-                        if (strokePaint.isProportional()) {
+                        // SMOOTH_LCD does not apply to stroked text
+                        if (strokePaint.isProportional() /* || smoothing == SMOOTH_LCD */) {
                             RectBounds textBounds = new RectBounds();
                             computeTextLayoutBounds(textBounds, BaseTransform.IDENTITY_TRANSFORM,
                                                     1, layoutX, layoutY, token);
@@ -1408,6 +1417,7 @@
                         ngtext.setDrawPaint(strokePaint);
                     }
                     ngtext.setFont(pgfont);
+                    ngtext.setFontSmoothingType(smoothing);
                     ngtext.setGlyphs(textLayout.getRuns());
                     ngtext.renderContent(gr);
                 }
--- a/modules/graphics/src/main/java/javafx/scene/canvas/GraphicsContext.java	Wed Aug 27 22:20:20 2014 +0400
+++ b/modules/graphics/src/main/java/javafx/scene/canvas/GraphicsContext.java	Wed Aug 27 15:24:38 2014 -0700
@@ -60,6 +60,7 @@
 import java.nio.IntBuffer;
 import java.util.Arrays;
 import java.util.LinkedList;
+import javafx.scene.text.FontSmoothingType;
 
 /**
  * This class is used to issue draw calls to a {@code Canvas} using a buffer. 
@@ -226,6 +227,14 @@
  * The vertical position of the text relative to the {@code Y} coordinate
  * specified in the text operation.
  * </td></tr>
+ * <tr class="altColor">
+ * <td class="colLast" style="width:15%">{@link #setFontSmoothingType(javafx.scene.text.FontSmoothingType) Font Smoothing}</td>
+ * <td class="colLast" style="width:10%; text-align:center; color:#0c0">Yes</td>
+ * <td class="colLast" style="width:10%; text-align:center">{@link FontSmoothingType#GRAY GRAY}</td>
+ * <td class="colLast">
+ * The type of smoothing (antialiasing) applied to the glyphs in the font
+ * for all fill text operations.
+ * </td></tr>
  * 
  * <tr><th colspan="3"><a name="path-attr"><p align="center">Path Attributes</p></a></th></tr>
  * <tr class="rowColor">
@@ -331,8 +340,8 @@
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
  * </tr>
  * <tr><td colspan="6"><p align="center">
- * <a name="base-fn-1">[1]</a>Only the Transform, Clip, and Effect apply to clearRect()<br>
- * <a name="base-fn-2">[2]</a>Only the Fill Rule applies to fillPolygon(), the current path is left unchanged
+ * <a name="base-fn-1">[1]</a> Only the Transform, Clip, and Effect apply to clearRect()<br>
+ * <a name="base-fn-2">[2]</a> Only the Fill Rule applies to fillPolygon(), the current path is left unchanged
  * </p></td></tr>
  * 
  * <tr><th colspan="1"><p align="center">Text Rendering</p></th></tr>
@@ -346,7 +355,7 @@
  * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes</td>
  * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes</td>
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
- * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes</td>
+ * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes <a href="#text-fn-3">[3]</a></td>
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
  * </tr>
  * <tr class="altColor">
@@ -359,9 +368,12 @@
  * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes</td>
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
  * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes</td>
- * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes</td>
+ * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes <a href="#text-fn-3">[3]</a></td>
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
  * </tr>
+ * <tr><td colspan="6"><p align="center">
+ * <a name="text-fn-3">[3]</a> The Font Smoothing attribute only applies to filled text
+ * </p></td></tr>
  * 
  * <tr><th colspan="1"><p align="center">Path Rendering</p></th></tr>
  * <tr class="rowColor">
@@ -377,7 +389,7 @@
  * {@link #closePath() closePath()},
  * {@link #rect(double, double, double, double) rect()}
  * </td>
- * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes <a href="#path-fn-3">[3]</a></td>
+ * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes <a href="#path-fn-4">[4]</a></td>
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
@@ -389,7 +401,7 @@
  * {@link #fill() fill()}
  * </a>
  * </td>
- * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes <a href="#path-fn-3">[3]</a></td>
+ * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes <a href="#path-fn-4">[4]</a></td>
  * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes</td>
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
@@ -401,11 +413,11 @@
  * {@link #stroke() stroke()}
  * </a>
  * </td>
- * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes <a href="#path-fn-3">[3]</a></td>
+ * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes <a href="#path-fn-4">[4]</a></td>
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
  * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes</td>
  * <td class="colLast" style="width:15%; text-align:center; color:#c00">No</td>
- * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes <a href="#path-fn-4">[4]</a></td>
+ * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes <a href="#path-fn-5">[5]</a></td>
  * </tr>
  * <tr class="altColor">
  * <td class="colLast" style="width:25%">
@@ -420,8 +432,8 @@
  * <td class="colLast" style="width:15%; text-align:center; color:#0c0">Yes</td>
  * </tr>
  * <tr><td colspan="6"><p align="center">
- * <a name="path-fn-3">[3]</a>Transform applied only during path construction<br>
- * <a name="path-fn-4">[4]</a>Fill Rule only used for fill() and clip()
+ * <a name="path-fn-4">[4]</a> Transform applied only during path construction<br>
+ * <a name="path-fn-5">[5]</a> Fill Rule only used for fill() and clip()
  * </p></td></tr>
  * 
  * <tr><th colspan="1"><p align="center">Image Rendering</p></th></tr>
@@ -508,6 +520,7 @@
         double dashOffset;
         int numClipPaths;
         Font font;
+        FontSmoothingType fontsmoothing;
         TextAlignment textalign;
         VPos textbaseline;
         Effect effect;
@@ -523,7 +536,9 @@
                 Color.BLACK, Color.BLACK,
                 1.0, StrokeLineCap.SQUARE, StrokeLineJoin.MITER, 10.0,
                 null, 0.0,
-                0, Font.getDefault(), TextAlignment.LEFT, VPos.BASELINE,
+                0,
+                Font.getDefault(), FontSmoothingType.GRAY,
+                TextAlignment.LEFT, VPos.BASELINE,
                 null, FillRule.NON_ZERO);
         }
 
@@ -534,35 +549,18 @@
                 copy.linewidth, copy.linecap, copy.linejoin, copy.miterlimit,
                 copy.dashes, copy.dashOffset,
                 copy.numClipPaths,
-                copy.font, copy.textalign, copy.textbaseline,
+                copy.font, copy.fontsmoothing, copy.textalign, copy.textbaseline,
                 copy.effect, copy.fillRule);
         }
 
-        State(double globalAlpha, BlendMode blendop,
-                     Affine2D transform, Paint fill, Paint stroke,
-                     double linewidth, StrokeLineCap linecap,
-                     StrokeLineJoin linejoin, double miterlimit,
-                     double dashes[], double dashOffset,
-                     int numClipPaths,
-                     Font font, TextAlignment align, VPos baseline,
-                     Effect effect, FillRule fillRule)
-        {
-            set(globalAlpha, blendop,
-                new Affine2D(transform),
-                fill, stroke,
-                linewidth, linecap, linejoin, miterlimit, dashes, dashOffset,
-                numClipPaths,
-                font, textalign, textbaseline,
-                effect, fillRule);
-        }
-
         final void set(double globalAlpha, BlendMode blendop,
                        Affine2D transform, Paint fill, Paint stroke,
                        double linewidth, StrokeLineCap linecap,
                        StrokeLineJoin linejoin, double miterlimit,
                        double dashes[], double dashOffset,
                        int numClipPaths,
-                       Font font, TextAlignment align, VPos baseline,
+                       Font font, FontSmoothingType smoothing,
+                       TextAlignment align, VPos baseline,
                        Effect effect, FillRule fillRule)
         {
             this.globalAlpha = globalAlpha;
@@ -578,6 +576,7 @@
             this.dashOffset = dashOffset;
             this.numClipPaths = numClipPaths;
             this.font = font;
+            this.fontsmoothing = smoothing;
             this.textalign = align;
             this.textbaseline = baseline;
             this.effect = effect;
@@ -610,6 +609,7 @@
             }
             ctx.setFillRule(fillRule);
             ctx.setFont(font);
+            ctx.setFontSmoothingType(fontsmoothing);
             ctx.setTextAlign(textalign);
             ctx.setTextBaseline(textbaseline);
             ctx.setEffect(effect);
@@ -1496,6 +1496,46 @@
     }
 
     /**
+     * Sets the current Font Smoothing Type.
+     * The default value is {@link FontSmoothingType#GRAY GRAY}.
+     * The font smoothing type is a <a href="#text-attr">text attribute</a>
+     * used for any of the text methods as specified in the
+     * <a href="#attr-ops-table">Rendering Attributes Table</a>.
+     * A {@code null} value will be ignored and the current value will remain unchanged.
+     * <p>
+     * <b>Note</b> that the {@code FontSmoothingType} value of
+     * {@link FontSmoothingType#LCD LCD} is only supported over an opaque
+     * background.  {@code LCD} text will generally appear as {@code GRAY}
+     * text over transparent or partially transparent pixels, and in some
+     * implementations it may not be supported at all on a {@link Canvas}
+     * because the required support does not exist for surfaces which contain
+     * an alpha channel as all {@code Canvas} objects do.
+     * 
+     * @param fontsmoothing the {@link FontSmoothingType} or null
+     * @since JavaFX 8u40
+     */
+    public void setFontSmoothingType(FontSmoothingType fontsmoothing) {
+        if (fontsmoothing != null && fontsmoothing != curState.fontsmoothing) {
+            curState.fontsmoothing = fontsmoothing;
+            writeParam((byte) fontsmoothing.ordinal(), NGCanvas.FONT_SMOOTH);
+        }
+    }
+
+    /**
+     * Gets the current Font Smoothing Type.
+     * The default value is {@link FontSmoothingType#GRAY GRAY}.
+     * The font smoothing type is a <a href="#text-attr">text attribute</a>
+     * used for any of the text methods as specified in the
+     * <a href="#attr-ops-table">Rendering Attributes Table</a>.
+     * 
+     * @return the {@link FontSmoothingType}
+     * @since JavaFX 8u40
+     */
+    public FontSmoothingType getFontSmoothingType() {
+        return curState.fontsmoothing;
+    }
+
+    /**
      * Defines horizontal text alignment, relative to the text {@code x} origin.
      * The default value is {@link TextAlignment#LEFT LEFT}.
      * The text alignment is a <a href="#text-attr">text attribute</a>
--- a/modules/graphics/src/test/java/javafx/scene/canvas/CanvasTest.java	Wed Aug 27 22:20:20 2014 +0400
+++ b/modules/graphics/src/test/java/javafx/scene/canvas/CanvasTest.java	Wed Aug 27 15:24:38 2014 -0700
@@ -35,6 +35,7 @@
 import javafx.scene.shape.StrokeLineCap;
 import javafx.scene.shape.StrokeLineJoin;
 import javafx.scene.text.Font;
+import javafx.scene.text.FontSmoothingType;
 import javafx.scene.text.TextAlignment;
 import javafx.scene.transform.Affine;
 import javafx.scene.transform.Rotate;
@@ -307,6 +308,13 @@
         assertEquals(f, gc.getFont());
     }
 
+    @Test public void testGCState_FontSmoothing_Null() {
+        gc.setFontSmoothingType(FontSmoothingType.GRAY);
+        assertEquals(FontSmoothingType.GRAY, gc.getFontSmoothingType());
+        gc.setFontSmoothingType(null);
+        assertEquals(FontSmoothingType.GRAY, gc.getFontSmoothingType());
+    }
+
     @Test public void testGCState_TextBaseline_Null() {
         gc.setTextBaseline(VPos.BASELINE);
         assertEquals(VPos.BASELINE, gc.getTextBaseline());