2370N/A/*
2685N/A * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2370N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2370N/A *
2370N/A * This code is free software; you can redistribute it and/or modify it
2370N/A * under the terms of the GNU General Public License version 2 only, as
2685N/A * published by the Free Software Foundation. Oracle designates this
2370N/A * particular file as subject to the "Classpath" exception as provided
2685N/A * by Oracle in the LICENSE file that accompanied this code.
2370N/A *
2370N/A * This code is distributed in the hope that it will be useful, but WITHOUT
2370N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2370N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2370N/A * version 2 for more details (a copy is included in the LICENSE file that
2370N/A * accompanied this code).
2370N/A *
2370N/A * You should have received a copy of the GNU General Public License version
2370N/A * 2 along with this work; if not, write to the Free Software Foundation,
2370N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2370N/A *
2685N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2685N/A * or visit www.oracle.com if you need additional information or have any
2685N/A * questions.
2370N/A */
2370N/A
2370N/Apackage sun.java2d.jules;
2370N/A
2370N/Aimport java.awt.*;
2370N/Aimport java.awt.geom.*;
2370N/Aimport sun.awt.X11GraphicsEnvironment;
2370N/Aimport sun.java2d.pipe.*;
2370N/Aimport sun.java2d.xr.*;
2370N/A
2370N/Apublic class JulesPathBuf {
2370N/A static final double[] emptyDash = new double[0];
2370N/A
2370N/A private static final byte CAIRO_PATH_OP_MOVE_TO = 0;
2370N/A private static final byte CAIRO_PATH_OP_LINE_TO = 1;
2370N/A private static final byte CAIRO_PATH_OP_CURVE_TO = 2;
2370N/A private static final byte CAIRO_PATH_OP_CLOSE_PATH = 3;
2370N/A
2370N/A private static final int CAIRO_FILL_RULE_WINDING = 0;
2370N/A private static final int CAIRO_FILL_RULE_EVEN_ODD = 1;
2370N/A
2370N/A GrowablePointArray points = new GrowablePointArray(128);
2370N/A GrowableByteArray ops = new GrowableByteArray(1, 128);
2370N/A int[] xTrapArray = new int[512];
2370N/A
2370N/A private static final boolean isCairoAvailable;
2370N/A
2370N/A static {
2370N/A isCairoAvailable =
2370N/A java.security.AccessController.doPrivileged(
2370N/A new java.security.PrivilegedAction<Boolean>() {
2370N/A public Boolean run() {
2370N/A boolean loadSuccess = false;
2370N/A if (X11GraphicsEnvironment.isXRenderAvailable()) {
2370N/A try {
2370N/A System.loadLibrary("jules");
2370N/A loadSuccess = true;
2370N/A if (X11GraphicsEnvironment.isXRenderVerbose()) {
2370N/A System.out.println(
2370N/A "Xrender: INFO: Jules library loaded");
2370N/A }
2370N/A } catch (UnsatisfiedLinkError ex) {
2370N/A loadSuccess = false;
2370N/A if (X11GraphicsEnvironment.isXRenderVerbose()) {
2370N/A System.out.println(
2370N/A "Xrender: INFO: Jules library not installed.");
2370N/A }
2370N/A }
2370N/A }
2370N/A return Boolean.valueOf(loadSuccess);
2370N/A }
2370N/A });
2370N/A }
2370N/A
2370N/A public static boolean isCairoAvailable() {
2370N/A return isCairoAvailable;
2370N/A }
2370N/A
2370N/A public TrapezoidList tesselateFill(Shape s, AffineTransform at, Region clip) {
2370N/A int windingRule = convertPathData(s, at);
2370N/A xTrapArray[0] = 0;
2370N/A
2370N/A xTrapArray = tesselateFillNative(points.getArray(), ops.getArray(),
2370N/A points.getSize(), ops.getSize(),
2370N/A xTrapArray, xTrapArray.length,
2370N/A getCairoWindingRule(windingRule),
2370N/A clip.getLoX(), clip.getLoY(),
2370N/A clip.getHiX(), clip.getHiY());
2370N/A
2370N/A return new TrapezoidList(xTrapArray);
2370N/A }
2370N/A
2370N/A public TrapezoidList tesselateStroke(Shape s, BasicStroke bs, boolean thin,
2370N/A boolean adjust, boolean antialias,
2370N/A AffineTransform at, Region clip) {
2370N/A
2370N/A float lw;
2370N/A if (thin) {
2370N/A if (antialias) {
2370N/A lw = 0.5f;
2370N/A } else {
2370N/A lw = 1.0f;
2370N/A }
2370N/A } else {
2370N/A lw = bs.getLineWidth();
2370N/A }
2370N/A
2370N/A convertPathData(s, at);
2370N/A
2370N/A double[] dashArray = floatToDoubleArray(bs.getDashArray());
2370N/A xTrapArray[0] = 0;
2370N/A
2370N/A xTrapArray =
2370N/A tesselateStrokeNative(points.getArray(), ops.getArray(),
2370N/A points.getSize(), ops.getSize(),
2370N/A xTrapArray, xTrapArray.length, lw,
2370N/A bs.getEndCap(), bs.getLineJoin(),
2370N/A bs.getMiterLimit(), dashArray,
2370N/A dashArray.length, bs.getDashPhase(),
2370N/A 1, 0, 0, 0, 1, 0,
2370N/A clip.getLoX(), clip.getLoY(),
2370N/A clip.getHiX(), clip.getHiY());
2370N/A
2370N/A return new TrapezoidList(xTrapArray);
2370N/A }
2370N/A
2370N/A protected double[] floatToDoubleArray(float[] dashArrayFloat) {
2370N/A double[] dashArrayDouble = emptyDash;
2370N/A if (dashArrayFloat != null) {
2370N/A dashArrayDouble = new double[dashArrayFloat.length];
2370N/A
2370N/A for (int i = 0; i < dashArrayFloat.length; i++) {
2370N/A dashArrayDouble[i] = dashArrayFloat[i];
2370N/A }
2370N/A }
2370N/A
2370N/A return dashArrayDouble;
2370N/A }
2370N/A
2370N/A protected int convertPathData(Shape s, AffineTransform at) {
2370N/A PathIterator pi = s.getPathIterator(at);
2370N/A
2370N/A double[] coords = new double[6];
2370N/A double currX = 0;
2370N/A double currY = 0;
2370N/A
2370N/A while (!pi.isDone()) {
2370N/A int curOp = pi.currentSegment(coords);
2370N/A
2370N/A int pointIndex;
2370N/A switch (curOp) {
2370N/A
2370N/A case PathIterator.SEG_MOVETO:
2370N/A ops.addByte(CAIRO_PATH_OP_MOVE_TO);
2370N/A pointIndex = points.getNextIndex();
2370N/A points.setX(pointIndex, DoubleToCairoFixed(coords[0]));
2370N/A points.setY(pointIndex, DoubleToCairoFixed(coords[1]));
2370N/A currX = coords[0];
2370N/A currY = coords[1];
2370N/A break;
2370N/A
2370N/A case PathIterator.SEG_LINETO:
2370N/A ops.addByte(CAIRO_PATH_OP_LINE_TO);
2370N/A pointIndex = points.getNextIndex();
2370N/A points.setX(pointIndex, DoubleToCairoFixed(coords[0]));
2370N/A points.setY(pointIndex, DoubleToCairoFixed(coords[1]));
2370N/A currX = coords[0];
2370N/A currY = coords[1];
2370N/A break;
2370N/A
2370N/A /**
2370N/A * q0 = p0
2370N/A * q1 = (p0+2*p1)/3
2370N/A * q2 = (p2+2*p1)/3
2370N/A * q3 = p2
2370N/A */
2370N/A case PathIterator.SEG_QUADTO:
2370N/A double x1 = coords[0];
2370N/A double y1 = coords[1];
2370N/A double x2, y2;
2370N/A double x3 = coords[2];
2370N/A double y3 = coords[3];
2370N/A
2370N/A x2 = x1 + (x3 - x1) / 3;
2370N/A y2 = y1 + (y3 - y1) / 3;
2370N/A x1 = currX + 2 * (x1 - currX) / 3;
2370N/A y1 =currY + 2 * (y1 - currY) / 3;
2370N/A
2370N/A ops.addByte(CAIRO_PATH_OP_CURVE_TO);
2370N/A pointIndex = points.getNextIndex();
2370N/A points.setX(pointIndex, DoubleToCairoFixed(x1));
2370N/A points.setY(pointIndex, DoubleToCairoFixed(y1));
2370N/A pointIndex = points.getNextIndex();
2370N/A points.setX(pointIndex, DoubleToCairoFixed(x2));
2370N/A points.setY(pointIndex, DoubleToCairoFixed(y2));
2370N/A pointIndex = points.getNextIndex();
2370N/A points.setX(pointIndex, DoubleToCairoFixed(x3));
2370N/A points.setY(pointIndex, DoubleToCairoFixed(y3));
2370N/A currX = x3;
2370N/A currY = y3;
2370N/A break;
2370N/A
2370N/A case PathIterator.SEG_CUBICTO:
2370N/A ops.addByte(CAIRO_PATH_OP_CURVE_TO);
2370N/A pointIndex = points.getNextIndex();
2370N/A points.setX(pointIndex, DoubleToCairoFixed(coords[0]));
2370N/A points.setY(pointIndex, DoubleToCairoFixed(coords[1]));
2370N/A pointIndex = points.getNextIndex();
2370N/A points.setX(pointIndex, DoubleToCairoFixed(coords[2]));
2370N/A points.setY(pointIndex, DoubleToCairoFixed(coords[3]));
2370N/A pointIndex = points.getNextIndex();
2370N/A points.setX(pointIndex, DoubleToCairoFixed(coords[4]));
2370N/A points.setY(pointIndex, DoubleToCairoFixed(coords[5]));
2370N/A currX = coords[4];
2370N/A currY = coords[5];
2370N/A break;
2370N/A
2370N/A case PathIterator.SEG_CLOSE:
2370N/A ops.addByte(CAIRO_PATH_OP_CLOSE_PATH);
2370N/A break;
2370N/A }
2370N/A
2370N/A pi.next();
2370N/A }
2370N/A
2370N/A return pi.getWindingRule();
2370N/A }
2370N/A
2370N/A private static native int[]
2370N/A tesselateStrokeNative(int[] pointArray, byte[] ops,
2370N/A int pointCnt, int opCnt,
2370N/A int[] xTrapArray, int xTrapArrayLength,
2370N/A double lineWidth, int lineCap, int lineJoin,
2370N/A double miterLimit, double[] dashArray,
2370N/A int dashCnt, double offset,
2370N/A double m00, double m01, double m02,
2370N/A double m10, double m11, double m12,
2370N/A int clipLowX, int clipLowY,
2370N/A int clipWidth, int clipHeight);
2370N/A
2370N/A private static native int[]
2370N/A tesselateFillNative(int[] pointArray, byte[] ops, int pointCnt,
2370N/A int opCnt, int[] xTrapArray, int xTrapArrayLength,
2370N/A int windingRule, int clipLowX, int clipLowY, int clipWidth, int clipHeight);
2370N/A
2370N/A public void clear() {
2370N/A points.clear();
2370N/A ops.clear();
2370N/A xTrapArray[0] = 0;
2370N/A }
2370N/A
2370N/A private static int DoubleToCairoFixed(double dbl) {
2370N/A return (int) (dbl * 256);
2370N/A }
2370N/A
2370N/A private static int getCairoWindingRule(int j2dWindingRule) {
2370N/A switch(j2dWindingRule) {
2370N/A case PathIterator.WIND_EVEN_ODD:
2370N/A return CAIRO_FILL_RULE_EVEN_ODD;
2370N/A
2370N/A case PathIterator.WIND_NON_ZERO:
2370N/A return CAIRO_FILL_RULE_WINDING;
2370N/A
2370N/A default:
2370N/A throw new IllegalArgumentException("Illegal Java2D winding rule specified");
2370N/A }
2370N/A }
2370N/A}