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 26package sun.java2d.jules; 27 28import java.awt.*; 29import java.awt.geom.*; 30import sun.awt.X11GraphicsEnvironment; 31import sun.java2d.pipe.*; 32import sun.java2d.xr.*; 33 34public 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} 272