1 /* 2 * Copyright (c) 2010, 2017, 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 com.sun.prism.impl.shape; 27 28 import com.sun.javafx.geom.Path2D; 29 import com.sun.javafx.geom.RectBounds; 30 import com.sun.javafx.geom.Rectangle; 31 import com.sun.javafx.geom.Shape; 32 import com.sun.javafx.geom.transform.BaseTransform; 33 import com.sun.marlin.MarlinRenderer; 34 import com.sun.marlin.MarlinRenderingEngine; 35 import com.sun.marlin.MaskMarlinAlphaConsumer; 36 import com.sun.marlin.RendererContext; 37 import com.sun.prism.BasicStroke; 38 import com.sun.prism.impl.PrismSettings; 39 40 /** 41 * Thread-safe Marlin rasterizer (TL or CLQ storage) 42 */ 43 public final class MarlinRasterizer implements ShapeRasterizer { 44 private static final MaskData EMPTY_MASK = MaskData.create(new byte[1], 0, 0, 1, 1); 45 46 @Override 47 public MaskData getMaskData(Shape shape, 48 BasicStroke stroke, 49 RectBounds xformBounds, 50 BaseTransform xform, 51 boolean close, boolean antialiasedShape) 52 { 53 if (stroke != null && stroke.getType() != BasicStroke.TYPE_CENTERED) { 54 // RT-27427 55 // TODO: Optimize the combinatorial strokes for simple 56 // shapes and/or teach the rasterizer to be able to 57 // do a "differential fill" between two shapes. 58 // Note that most simple shapes will use a more optimized path 59 // than this method for the INNER/OUTER strokes anyway. 60 shape = stroke.createStrokedShape(shape); 61 stroke = null; 62 } 63 if (xformBounds == null) { 64 if (stroke != null) { 65 // Note that all places that pass null for xformbounds also 66 // pass null for stroke so that the following is not typically 67 // executed, but just here as a safety net. 68 shape = stroke.createStrokedShape(shape); 69 stroke = null; 70 } 71 72 xformBounds = new RectBounds(); 73 //TODO: Need to verify that this is a safe cast ... (RT-27427) 74 xformBounds = (RectBounds) xform.transform(shape.getBounds(), xformBounds); 75 } 76 if (xformBounds.isEmpty()) { 77 return EMPTY_MASK; 78 } 79 80 final RendererContext rdrCtx = MarlinRenderingEngine.getRendererContext(); 81 MarlinRenderer renderer = null; 82 try { 83 final Rectangle rclip = rdrCtx.clip; 84 rclip.setBounds(xformBounds); 85 86 renderer = MarlinPrismUtils.setupRenderer(rdrCtx, shape, stroke, xform, rclip, 87 antialiasedShape); 88 89 final int outpix_xmin = renderer.getOutpixMinX(); 90 final int outpix_xmax = renderer.getOutpixMaxX(); 91 final int outpix_ymin = renderer.getOutpixMinY(); 92 final int outpix_ymax = renderer.getOutpixMaxY(); 93 final int w = outpix_xmax - outpix_xmin; 94 final int h = outpix_ymax - outpix_ymin; 95 if ((w <= 0) || (h <= 0)) { 96 return EMPTY_MASK; 97 } 98 99 MaskMarlinAlphaConsumer consumer = rdrCtx.consumer; 100 if (consumer == null || (w * h) > consumer.getAlphaLength()) { 101 final int csize = (w * h + 0xfff) & (~0xfff); 102 rdrCtx.consumer = consumer = new MaskMarlinAlphaConsumer(csize); 103 if (PrismSettings.verbose) { 104 System.out.println("new alphas with length = " + csize); 105 } 106 } 107 consumer.setBoundsNoClone(outpix_xmin, outpix_ymin, w, h); 108 renderer.produceAlphas(consumer); 109 110 return consumer.getMaskData(); 111 } finally { 112 if (renderer != null) { 113 renderer.dispose(); 114 } 115 // recycle the RendererContext instance 116 MarlinRenderingEngine.returnRendererContext(rdrCtx); 117 } 118 } 119 120 static Shape createCenteredStrokedShape(Shape s, BasicStroke stroke) 121 { 122 final float lw = (stroke.getType() == BasicStroke.TYPE_CENTERED) ? 123 stroke.getLineWidth() : stroke.getLineWidth() * 2.0f; 124 125 final RendererContext rdrCtx = MarlinRenderingEngine.getRendererContext(); 126 try { 127 // initialize a large copyable Path2D to avoid a lot of array growing: 128 final Path2D p2d = rdrCtx.getPath2D(); 129 130 MarlinPrismUtils.strokeTo(rdrCtx, s, stroke, lw, 131 rdrCtx.transformerPC2D.wrapPath2d(p2d) 132 ); 133 134 // Use Path2D copy constructor (trim) 135 return new Path2D(p2d); 136 137 } finally { 138 // recycle the RendererContext instance 139 MarlinRenderingEngine.returnRendererContext(rdrCtx); 140 } 141 } 142 }