1 /*
   2  * Copyright (c) 2010, 2016, 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.DMarlinRenderer;
  34 import com.sun.marlin.DMarlinRenderingEngine;
  35 import com.sun.marlin.MaskMarlinAlphaConsumer;
  36 import com.sun.marlin.DRendererContext;
  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 DMarlinRasterizer 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 DRendererContext rdrCtx = DMarlinRenderingEngine.getRendererContext();
  81         DMarlinRenderer renderer = null;
  82         try {
  83             final Rectangle rclip = rdrCtx.clip;
  84             rclip.setBounds(xformBounds);
  85 
  86             if (shape instanceof Path2D) {
  87                 renderer = DMarlinPrismUtils.setupRenderer(rdrCtx, (Path2D) shape, stroke, xform, rclip,
  88                         antialiasedShape);
  89             }
  90             if (renderer == null) {
  91                 renderer = DMarlinPrismUtils.setupRenderer(rdrCtx, shape, stroke, xform, rclip,
  92                         antialiasedShape);
  93             }
  94             final int outpix_xmin = renderer.getOutpixMinX();
  95             final int outpix_xmax = renderer.getOutpixMaxX();
  96             final int outpix_ymin = renderer.getOutpixMinY();
  97             final int outpix_ymax = renderer.getOutpixMaxY();
  98             final int w = outpix_xmax - outpix_xmin;
  99             final int h = outpix_ymax - outpix_ymin;
 100             if ((w <= 0) || (h <= 0)) {
 101                 return EMPTY_MASK;
 102             }
 103 
 104             MaskMarlinAlphaConsumer consumer = rdrCtx.consumer;
 105             if (consumer == null || (w * h) > consumer.getAlphaLength()) {
 106                 final int csize = (w * h + 0xfff) & (~0xfff);
 107                 rdrCtx.consumer = consumer = new MaskMarlinAlphaConsumer(csize);
 108                 if (PrismSettings.verbose) {
 109                     System.out.println("new alphas with length = " + csize);
 110                 }
 111             }
 112             consumer.setBoundsNoClone(outpix_xmin, outpix_ymin, w, h);
 113             renderer.produceAlphas(consumer);
 114             return consumer.getMaskData();
 115         } finally {
 116             if (renderer != null) {
 117                 renderer.dispose();
 118             }
 119             // recycle the RendererContext instance
 120             DMarlinRenderingEngine.returnRendererContext(rdrCtx);
 121         }
 122     }
 123 }