RenderingEngine.java 17.5 KB
Newer Older
D
duke 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
/*
 * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package sun.java2d.pipe;

import java.awt.Shape;
import java.awt.BasicStroke;
import java.awt.geom.PathIterator;
import java.awt.geom.AffineTransform;

import java.security.PrivilegedAction;
import java.security.AccessController;
import java.util.ServiceLoader;
import sun.security.action.GetPropertyAction;

import sun.awt.geom.PathConsumer2D;

/**
 * This class abstracts a number of features for which the Java 2D
 * implementation relies on proprietary licensed software libraries.
 * Access to those features is now achieved by retrieving the singleton
 * instance of this class and calling the appropriate methods on it.
 * The 3 primary features abstracted here include:
 * <dl>
 * <dt>Shape createStrokedShape(Shape, [BasicStroke attributes]);
 * <dd>This method implements the functionality of the method of the
 * same name on the {@link BasicStroke} class.
 * <dt>void strokeTo(Shape, [rendering parameters], PathConsumer2D);
 * <dd>This method performs widening of the source path on the fly
 * and sends the results to the given {@link PathConsumer2D} object.
 * This procedure avoids having to create an intermediate Shape
 * object to hold the results of the {@code createStrokedShape} method.
 * The main user of this method is the Java 2D non-antialiasing renderer.
 * <dt>AATileGenerator getAATileGenerator(Shape, [rendering parameters]);
 * <dd>This method returns an object which can iterate over the
 * specified bounding box and produce tiles of coverage values for
 * antialiased rendering.  The details of the operation of the
 * {@link AATileGenerator} object are explained in its class comments.
 * </dl>
 * Additionally, the following informational method supplies important
 * data about the implementation.
 * <dl>
 * <dt>float getMinimumAAPenSize()
 * <dd>This method provides information on how small the BasicStroke
 * line width can get before dropouts occur.  Rendering with a BasicStroke
 * is defined to never allow the line to have breaks, gaps, or dropouts
 * even if the width is set to 0.0f, so this information allows the
 * {@link SunGraphics2D} class to detect the "thin line" case and set
 * the rendering attributes accordingly.
 * </dl>
 * At startup the runtime will load a single instance of this class.
 * It searches the classpath for a registered provider of this API
 * and returns either the last one it finds, or the instance whose
 * class name matches the value supplied in the System property
 * {@code sun.java2d.renderer}.
 * Additionally, a runtime System property flag can be set to trace
 * all calls to methods on the {@code RenderingEngine} in use by
 * setting the sun.java2d.renderer.trace property to any non-null value.
 * <p>
 * Parts of the system that need to use any of the above features should
 * call {@code RenderingEngine.getInstance()} to obtain the properly
 * registered (and possibly trace-enabled) version of the RenderingEngine.
 */
public abstract class RenderingEngine {
    private static RenderingEngine reImpl;

    /**
     * Returns an instance of {@code RenderingEngine} as determined
     * by the installation environment and runtime flags.
     * <p>
     * A specific instance of the {@code RenderingEngine} can be
     * chosen by specifying the runtime flag:
     * <pre>
     *     java -Dsun.java2d.renderer=&lt;classname&gt;
     * </pre>
98 99 100 101 102
     *
     * If no specific {@code RenderingEngine} is specified on the command
     * or Ductus renderer is specified, it will attempt loading the
     * sun.dc.DuctusRenderingEngine class using Class.forName as a fastpath;
     * if not found, use the ServiceLoader.
D
duke 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
     * If no specific {@code RenderingEngine} is specified on the command
     * line then the last one returned by enumerating all subclasses of
     * {@code RenderingEngine} known to the ServiceLoader is used.
     * <p>
     * Runtime tracing of the actions of the {@code RenderingEngine}
     * can be enabled by specifying the runtime flag:
     * <pre>
     *     java -Dsun.java2d.renderer.trace=&lt;any string&gt;
     * </pre>
     * @return an instance of {@code RenderingEngine}
     * @since 1.7
     */
    public static synchronized RenderingEngine getInstance() {
        if (reImpl != null) {
            return reImpl;
        }

        reImpl = (RenderingEngine)
            AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
123
                    final String ductusREClass = "sun.dc.DuctusRenderingEngine";
D
duke 已提交
124
                    String reClass =
125 126 127 128 129 130 131 132 133 134 135 136 137
                        System.getProperty("sun.java2d.renderer", ductusREClass);
                    if (reClass.equals(ductusREClass)) {
                        try {
                            Class cls = Class.forName(ductusREClass);
                            return cls.newInstance();
                        } catch (ClassNotFoundException x) {
                            // not found
                        } catch (IllegalAccessException x) {
                            // should not reach here
                        } catch (InstantiationException x) {
                            // should not reach here
                        }
                    }
D
duke 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397

                    ServiceLoader<RenderingEngine> reLoader =
                        ServiceLoader.loadInstalled(RenderingEngine.class);

                    RenderingEngine service = null;

                    for (RenderingEngine re : reLoader) {
                        service = re;
                        if (re.getClass().getName().equals(reClass)) {
                            break;
                        }
                    }
                    return service;
                }
            });

        if (reImpl == null) {
            throw new InternalError("No RenderingEngine module found");
        }

        GetPropertyAction gpa =
            new GetPropertyAction("sun.java2d.renderer.trace");
        String reTrace = (String) AccessController.doPrivileged(gpa);
        if (reTrace != null) {
            reImpl = new Tracer(reImpl);
        }

        return reImpl;
    }

    /**
     * Create a widened path as specified by the parameters.
     * <p>
     * The specified {@code src} {@link Shape} is widened according
     * to the specified attribute parameters as per the
     * {@link BasicStroke} specification.
     *
     * @param src the source path to be widened
     * @param width the width of the widened path as per {@code BasicStroke}
     * @param caps the end cap decorations as per {@code BasicStroke}
     * @param join the segment join decorations as per {@code BasicStroke}
     * @param miterlimit the miter limit as per {@code BasicStroke}
     * @param dashes the dash length array as per {@code BasicStroke}
     * @param dashphase the initial dash phase as per {@code BasicStroke}
     * @return the widened path stored in a new {@code Shape} object
     * @since 1.7
     */
    public abstract Shape createStrokedShape(Shape src,
                                             float width,
                                             int caps,
                                             int join,
                                             float miterlimit,
                                             float dashes[],
                                             float dashphase);

    /**
     * Sends the geometry for a widened path as specified by the parameters
     * to the specified consumer.
     * <p>
     * The specified {@code src} {@link Shape} is widened according
     * to the parameters specified by the {@link BasicStroke} object.
     * Adjustments are made to the path as appropriate for the
     * {@link VALUE_STROKE_NORMALIZE} hint if the {@code normalize}
     * boolean parameter is true.
     * Adjustments are made to the path as appropriate for the
     * {@link VALUE_ANTIALIAS_ON} hint if the {@code antialias}
     * boolean parameter is true.
     * <p>
     * The geometry of the widened path is forwarded to the indicated
     * {@link PathConsumer2D} object as it is calculated.
     *
     * @param src the source path to be widened
     * @param bs the {@code BasicSroke} object specifying the
     *           decorations to be applied to the widened path
     * @param normalize indicates whether stroke normalization should
     *                  be applied
     * @param antialias indicates whether or not adjustments appropriate
     *                  to antialiased rendering should be applied
     * @param consumer the {@code PathConsumer2D} instance to forward
     *                 the widened geometry to
     * @since 1.7
     */
    public abstract void strokeTo(Shape src,
                                  AffineTransform at,
                                  BasicStroke bs,
                                  boolean thin,
                                  boolean normalize,
                                  boolean antialias,
                                  PathConsumer2D consumer);

    /**
     * Construct an antialiased tile generator for the given shape with
     * the given rendering attributes and store the bounds of the tile
     * iteration in the bbox parameter.
     * The {@code at} parameter specifies a transform that should affect
     * both the shape and the {@code BasicStroke} attributes.
     * The {@code clip} parameter specifies the current clip in effect
     * in device coordinates and can be used to prune the data for the
     * operation, but the renderer is not required to perform any
     * clipping.
     * If the {@code BasicStroke} parameter is null then the shape
     * should be filled as is, otherwise the attributes of the
     * {@code BasicStroke} should be used to specify a draw operation.
     * The {@code thin} parameter indicates whether or not the
     * transformed {@code BasicStroke} represents coordinates smaller
     * than the minimum resolution of the antialiasing rasterizer as
     * specified by the {@code getMinimumAAPenWidth()} method.
     * <p>
     * Upon returning, this method will fill the {@code bbox} parameter
     * with 4 values indicating the bounds of the iteration of the
     * tile generator.
     * The iteration order of the tiles will be as specified by the
     * pseudo-code:
     * <pre>
     *     for (y = bbox[1]; y < bbox[3]; y += tileheight) {
     *         for (x = bbox[0]; x < bbox[2]; x += tilewidth) {
     *         }
     *     }
     * </pre>
     * If there is no output to be rendered, this method may return
     * null.
     *
     * @param s the shape to be rendered (fill or draw)
     * @param at the transform to be applied to the shape and the
     *           stroke attributes
     * @param clip the current clip in effect in device coordinates
     * @param bs if non-null, a {@code BasicStroke} whose attributes
     *           should be applied to this operation
     * @param thin true if the transformed stroke attributes are smaller
     *             than the minimum dropout pen width
     * @param normalize true if the {@code VALUE_STROKE_NORMALIZE}
     *                  {@code RenderingHint} is in effect
     * @param bbox returns the bounds of the iteration
     * @return the {@code AATileGenerator} instance to be consulted
     *         for tile coverages, or null if there is no output to render
     * @since 1.7
     */
    public abstract AATileGenerator getAATileGenerator(Shape s,
                                                       AffineTransform at,
                                                       Region clip,
                                                       BasicStroke bs,
                                                       boolean thin,
                                                       boolean normalize,
                                                       int bbox[]);

    /**
     * Returns the minimum pen width that the antialiasing rasterizer
     * can represent without dropouts occuring.
     * @since 1.7
     */
    public abstract float getMinimumAAPenSize();

    /**
     * Utility method to feed a {@link PathConsumer2D} object from a
     * given {@link PathIterator}.
     * This method deals with the details of running the iterator and
     * feeding the consumer a segment at a time.
     */
    public static void feedConsumer(PathIterator pi, PathConsumer2D consumer) {
        float coords[] = new float[6];
        while (!pi.isDone()) {
            switch (pi.currentSegment(coords)) {
            case PathIterator.SEG_MOVETO:
                consumer.moveTo(coords[0], coords[1]);
                break;
            case PathIterator.SEG_LINETO:
                consumer.lineTo(coords[0], coords[1]);
                break;
            case PathIterator.SEG_QUADTO:
                consumer.quadTo(coords[0], coords[1],
                                coords[2], coords[3]);
                break;
            case PathIterator.SEG_CUBICTO:
                consumer.curveTo(coords[0], coords[1],
                                 coords[2], coords[3],
                                 coords[4], coords[5]);
                break;
            case PathIterator.SEG_CLOSE:
                consumer.closePath();
                break;
            }
            pi.next();
        }
    }

    static class Tracer extends RenderingEngine {
        RenderingEngine target;
        String name;

        public Tracer(RenderingEngine target) {
            this.target = target;
            name = target.getClass().getName();
        }

        public Shape createStrokedShape(Shape src,
                                        float width,
                                        int caps,
                                        int join,
                                        float miterlimit,
                                        float dashes[],
                                        float dashphase)
        {
            System.out.println(name+".createStrokedShape("+
                               src.getClass().getName()+", "+
                               "width = "+width+", "+
                               "caps = "+caps+", "+
                               "join = "+join+", "+
                               "miter = "+miterlimit+", "+
                               "dashes = "+dashes+", "+
                               "dashphase = "+dashphase+")");
            return target.createStrokedShape(src,
                                             width, caps, join, miterlimit,
                                             dashes, dashphase);
        }

        public void strokeTo(Shape src,
                             AffineTransform at,
                             BasicStroke bs,
                             boolean thin,
                             boolean normalize,
                             boolean antialias,
                             PathConsumer2D consumer)
        {
            System.out.println(name+".strokeTo("+
                               src.getClass().getName()+", "+
                               at+", "+
                               bs+", "+
                               (thin ? "thin" : "wide")+", "+
                               (normalize ? "normalized" : "pure")+", "+
                               (antialias ? "AA" : "non-AA")+", "+
                               consumer.getClass().getName()+")");
            target.strokeTo(src, at, bs, thin, normalize, antialias, consumer);
        }

        public float getMinimumAAPenSize() {
            System.out.println(name+".getMinimumAAPenSize()");
            return target.getMinimumAAPenSize();
        }

        public AATileGenerator getAATileGenerator(Shape s,
                                                  AffineTransform at,
                                                  Region clip,
                                                  BasicStroke bs,
                                                  boolean thin,
                                                  boolean normalize,
                                                  int bbox[])
        {
            System.out.println(name+".getAATileGenerator("+
                               s.getClass().getName()+", "+
                               at+", "+
                               clip+", "+
                               bs+", "+
                               (thin ? "thin" : "wide")+", "+
                               (normalize ? "normalized" : "pure")+")");
            return target.getAATileGenerator(s, at, clip,
                                             bs, thin, normalize,
                                             bbox);
        }
    }
}