src/java.desktop/unix/classes/sun/java2d/jules/JulesPathBuf.java
changeset 48128 2d91c9a4f409
parent 48127 efc459cf351e
parent 48125 4e5124dacf91
child 48129 c134a8bee21a
equal deleted inserted replaced
48127:efc459cf351e 48128:2d91c9a4f409
     1 /*
       
     2  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.java2d.jules;
       
    27 
       
    28 import java.awt.*;
       
    29 import java.awt.geom.*;
       
    30 import sun.awt.X11GraphicsEnvironment;
       
    31 import sun.java2d.pipe.*;
       
    32 import sun.java2d.xr.*;
       
    33 
       
    34 public class JulesPathBuf {
       
    35     static final double[] emptyDash = new double[0];
       
    36 
       
    37     private static final byte CAIRO_PATH_OP_MOVE_TO = 0;
       
    38     private static final byte CAIRO_PATH_OP_LINE_TO = 1;
       
    39     private static final byte CAIRO_PATH_OP_CURVE_TO = 2;
       
    40     private static final byte CAIRO_PATH_OP_CLOSE_PATH = 3;
       
    41 
       
    42     private static final int  CAIRO_FILL_RULE_WINDING = 0;
       
    43     private static final int CAIRO_FILL_RULE_EVEN_ODD = 1;
       
    44 
       
    45     GrowablePointArray points = new GrowablePointArray(128);
       
    46     GrowableByteArray ops = new GrowableByteArray(1, 128);
       
    47     int[] xTrapArray = new int[512];
       
    48 
       
    49     private static final boolean isCairoAvailable;
       
    50 
       
    51     static {
       
    52         isCairoAvailable =
       
    53            java.security.AccessController.doPrivileged(
       
    54                           new java.security.PrivilegedAction<Boolean>() {
       
    55             public Boolean run() {
       
    56                 boolean loadSuccess = false;
       
    57                 if (X11GraphicsEnvironment.isXRenderAvailable()) {
       
    58                     try {
       
    59                         System.loadLibrary("jules");
       
    60                         loadSuccess = true;
       
    61                         if (X11GraphicsEnvironment.isXRenderVerbose()) {
       
    62                             System.out.println(
       
    63                                        "Xrender: INFO: Jules library loaded");
       
    64                         }
       
    65                     } catch (UnsatisfiedLinkError ex) {
       
    66                         loadSuccess = false;
       
    67                         if (X11GraphicsEnvironment.isXRenderVerbose()) {
       
    68                             System.out.println(
       
    69                                 "Xrender: INFO: Jules library not installed.");
       
    70                         }
       
    71                     }
       
    72                 }
       
    73                 return Boolean.valueOf(loadSuccess);
       
    74             }
       
    75         });
       
    76     }
       
    77 
       
    78     public static boolean isCairoAvailable() {
       
    79         return isCairoAvailable;
       
    80     }
       
    81 
       
    82     public TrapezoidList tesselateFill(Shape s, AffineTransform at, Region clip) {
       
    83         int windingRule = convertPathData(s, at);
       
    84         xTrapArray[0] = 0;
       
    85 
       
    86         xTrapArray = tesselateFillNative(points.getArray(), ops.getArray(),
       
    87                                          points.getSize(), ops.getSize(),
       
    88                                          xTrapArray, xTrapArray.length,
       
    89                                          getCairoWindingRule(windingRule),
       
    90                                          clip.getLoX(), clip.getLoY(),
       
    91                                          clip.getHiX(), clip.getHiY());
       
    92 
       
    93         return new TrapezoidList(xTrapArray);
       
    94     }
       
    95 
       
    96     public TrapezoidList tesselateStroke(Shape s, BasicStroke bs, boolean thin,
       
    97                                          boolean adjust, boolean antialias,
       
    98                                          AffineTransform at, Region clip) {
       
    99 
       
   100         float lw;
       
   101         if (thin) {
       
   102             if (antialias) {
       
   103                 lw = 0.5f;
       
   104             } else {
       
   105                 lw = 1.0f;
       
   106             }
       
   107         } else {
       
   108             lw = bs.getLineWidth();
       
   109         }
       
   110 
       
   111         convertPathData(s, at);
       
   112 
       
   113         double[] dashArray = floatToDoubleArray(bs.getDashArray());
       
   114         xTrapArray[0] = 0;
       
   115 
       
   116         xTrapArray =
       
   117              tesselateStrokeNative(points.getArray(), ops.getArray(),
       
   118                                    points.getSize(), ops.getSize(),
       
   119                                    xTrapArray, xTrapArray.length, lw,
       
   120                                    bs.getEndCap(), bs.getLineJoin(),
       
   121                                    bs.getMiterLimit(), dashArray,
       
   122                                    dashArray.length, bs.getDashPhase(),
       
   123                                    1, 0, 0, 0, 1, 0,
       
   124                                    clip.getLoX(), clip.getLoY(),
       
   125                                    clip.getHiX(), clip.getHiY());
       
   126 
       
   127         return new TrapezoidList(xTrapArray);
       
   128     }
       
   129 
       
   130     protected double[] floatToDoubleArray(float[] dashArrayFloat) {
       
   131         double[] dashArrayDouble = emptyDash;
       
   132         if (dashArrayFloat != null) {
       
   133             dashArrayDouble = new double[dashArrayFloat.length];
       
   134 
       
   135             for (int i = 0; i < dashArrayFloat.length; i++) {
       
   136                 dashArrayDouble[i] = dashArrayFloat[i];
       
   137             }
       
   138         }
       
   139 
       
   140         return dashArrayDouble;
       
   141     }
       
   142 
       
   143     protected int convertPathData(Shape s, AffineTransform at) {
       
   144         PathIterator pi = s.getPathIterator(at);
       
   145 
       
   146         double[] coords = new double[6];
       
   147         double currX = 0;
       
   148         double currY = 0;
       
   149 
       
   150         while (!pi.isDone()) {
       
   151             int curOp = pi.currentSegment(coords);
       
   152 
       
   153             int pointIndex;
       
   154             switch (curOp) {
       
   155 
       
   156             case PathIterator.SEG_MOVETO:
       
   157                 ops.addByte(CAIRO_PATH_OP_MOVE_TO);
       
   158                 pointIndex = points.getNextIndex();
       
   159                 points.setX(pointIndex, DoubleToCairoFixed(coords[0]));
       
   160                 points.setY(pointIndex, DoubleToCairoFixed(coords[1]));
       
   161                 currX = coords[0];
       
   162                 currY = coords[1];
       
   163                 break;
       
   164 
       
   165             case PathIterator.SEG_LINETO:
       
   166                 ops.addByte(CAIRO_PATH_OP_LINE_TO);
       
   167                 pointIndex = points.getNextIndex();
       
   168                 points.setX(pointIndex, DoubleToCairoFixed(coords[0]));
       
   169                 points.setY(pointIndex, DoubleToCairoFixed(coords[1]));
       
   170                 currX = coords[0];
       
   171                 currY = coords[1];
       
   172                 break;
       
   173 
       
   174                 /**
       
   175                  *    q0 = p0
       
   176                  *    q1 = (p0+2*p1)/3
       
   177                  *    q2 = (p2+2*p1)/3
       
   178                  *    q3 = p2
       
   179                  */
       
   180             case PathIterator.SEG_QUADTO:
       
   181                 double x1 = coords[0];
       
   182                 double y1 = coords[1];
       
   183                 double x2, y2;
       
   184                 double x3 = coords[2];
       
   185                 double y3 = coords[3];
       
   186 
       
   187                 x2 = x1 + (x3 - x1) / 3;
       
   188                 y2 = y1 + (y3 - y1) / 3;
       
   189                 x1 = currX + 2 * (x1 - currX) / 3;
       
   190                 y1 =currY + 2 * (y1 - currY) / 3;
       
   191 
       
   192                 ops.addByte(CAIRO_PATH_OP_CURVE_TO);
       
   193                 pointIndex = points.getNextIndex();
       
   194                 points.setX(pointIndex, DoubleToCairoFixed(x1));
       
   195                 points.setY(pointIndex, DoubleToCairoFixed(y1));
       
   196                 pointIndex = points.getNextIndex();
       
   197                 points.setX(pointIndex, DoubleToCairoFixed(x2));
       
   198                 points.setY(pointIndex, DoubleToCairoFixed(y2));
       
   199                 pointIndex = points.getNextIndex();
       
   200                 points.setX(pointIndex, DoubleToCairoFixed(x3));
       
   201                 points.setY(pointIndex, DoubleToCairoFixed(y3));
       
   202                 currX = x3;
       
   203                 currY = y3;
       
   204                 break;
       
   205 
       
   206             case PathIterator.SEG_CUBICTO:
       
   207                 ops.addByte(CAIRO_PATH_OP_CURVE_TO);
       
   208                 pointIndex = points.getNextIndex();
       
   209                 points.setX(pointIndex, DoubleToCairoFixed(coords[0]));
       
   210                 points.setY(pointIndex, DoubleToCairoFixed(coords[1]));
       
   211                 pointIndex = points.getNextIndex();
       
   212                 points.setX(pointIndex, DoubleToCairoFixed(coords[2]));
       
   213                 points.setY(pointIndex, DoubleToCairoFixed(coords[3]));
       
   214                 pointIndex = points.getNextIndex();
       
   215                 points.setX(pointIndex, DoubleToCairoFixed(coords[4]));
       
   216                 points.setY(pointIndex, DoubleToCairoFixed(coords[5]));
       
   217                 currX = coords[4];
       
   218                 currY = coords[5];
       
   219                 break;
       
   220 
       
   221             case PathIterator.SEG_CLOSE:
       
   222                 ops.addByte(CAIRO_PATH_OP_CLOSE_PATH);
       
   223                 break;
       
   224             }
       
   225 
       
   226             pi.next();
       
   227         }
       
   228 
       
   229         return pi.getWindingRule();
       
   230     }
       
   231 
       
   232     private static native int[]
       
   233          tesselateStrokeNative(int[] pointArray, byte[] ops,
       
   234                                int pointCnt, int opCnt,
       
   235                                int[] xTrapArray, int xTrapArrayLength,
       
   236                                double lineWidth, int lineCap, int lineJoin,
       
   237                                double miterLimit, double[] dashArray,
       
   238                                int dashCnt, double offset,
       
   239                                double m00, double m01, double m02,
       
   240                                double m10, double m11, double m12,
       
   241                                int clipLowX, int clipLowY,
       
   242                                int clipWidth, int clipHeight);
       
   243 
       
   244     private static native int[]
       
   245         tesselateFillNative(int[] pointArray, byte[] ops, int pointCnt,
       
   246                             int opCnt, int[] xTrapArray, int xTrapArrayLength,
       
   247                             int windingRule, int clipLowX, int clipLowY,                                    int clipWidth, int clipHeight);
       
   248 
       
   249     public void clear() {
       
   250         points.clear();
       
   251         ops.clear();
       
   252         xTrapArray[0] = 0;
       
   253     }
       
   254 
       
   255     private static int DoubleToCairoFixed(double dbl) {
       
   256         return (int) (dbl * 256);
       
   257     }
       
   258 
       
   259     private static int getCairoWindingRule(int j2dWindingRule) {
       
   260         switch(j2dWindingRule) {
       
   261         case PathIterator.WIND_EVEN_ODD:
       
   262             return CAIRO_FILL_RULE_EVEN_ODD;
       
   263 
       
   264         case PathIterator.WIND_NON_ZERO:
       
   265             return CAIRO_FILL_RULE_WINDING;
       
   266 
       
   267             default:
       
   268                 throw new IllegalArgumentException("Illegal Java2D winding rule specified");
       
   269         }
       
   270     }
       
   271 }