/*
* Copyright (c) 2010, 2017, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.prism.impl.shape;
import com.sun.javafx.geom.Path2D;
import com.sun.javafx.geom.RectBounds;
import com.sun.javafx.geom.Rectangle;
import com.sun.javafx.geom.Shape;
import com.sun.javafx.geom.transform.BaseTransform;
import com.sun.marlin.MarlinRenderer;
import com.sun.marlin.MarlinRenderingEngine;
import com.sun.marlin.MaskMarlinAlphaConsumer;
import com.sun.marlin.RendererContext;
import com.sun.prism.BasicStroke;
import com.sun.prism.impl.PrismSettings;
Thread-safe Marlin rasterizer (TL or CLQ storage)
/**
* Thread-safe Marlin rasterizer (TL or CLQ storage)
*/
public final class MarlinRasterizer implements ShapeRasterizer {
private static final MaskData EMPTY_MASK = MaskData.create(new byte[1], 0, 0, 1, 1);
@Override
public MaskData getMaskData(Shape shape,
BasicStroke stroke,
RectBounds xformBounds,
BaseTransform xform,
boolean close, boolean antialiasedShape)
{
if (stroke != null && stroke.getType() != BasicStroke.TYPE_CENTERED) {
// RT-27427
// TODO: Optimize the combinatorial strokes for simple
// shapes and/or teach the rasterizer to be able to
// do a "differential fill" between two shapes.
// Note that most simple shapes will use a more optimized path
// than this method for the INNER/OUTER strokes anyway.
shape = stroke.createStrokedShape(shape);
stroke = null;
}
if (xformBounds == null) {
if (stroke != null) {
// Note that all places that pass null for xformbounds also
// pass null for stroke so that the following is not typically
// executed, but just here as a safety net.
shape = stroke.createStrokedShape(shape);
stroke = null;
}
xformBounds = new RectBounds();
//TODO: Need to verify that this is a safe cast ... (RT-27427)
xformBounds = (RectBounds) xform.transform(shape.getBounds(), xformBounds);
}
if (xformBounds.isEmpty()) {
return EMPTY_MASK;
}
final RendererContext rdrCtx = MarlinRenderingEngine.getRendererContext();
MarlinRenderer renderer = null;
try {
final Rectangle rclip = rdrCtx.clip;
rclip.setBounds(xformBounds);
renderer = MarlinPrismUtils.setupRenderer(rdrCtx, shape, stroke, xform, rclip,
antialiasedShape);
final int outpix_xmin = renderer.getOutpixMinX();
final int outpix_xmax = renderer.getOutpixMaxX();
final int outpix_ymin = renderer.getOutpixMinY();
final int outpix_ymax = renderer.getOutpixMaxY();
final int w = outpix_xmax - outpix_xmin;
final int h = outpix_ymax - outpix_ymin;
if ((w <= 0) || (h <= 0)) {
return EMPTY_MASK;
}
MaskMarlinAlphaConsumer consumer = rdrCtx.consumer;
if (consumer == null || (w * h) > consumer.getAlphaLength()) {
final int csize = (w * h + 0xfff) & (~0xfff);
rdrCtx.consumer = consumer = new MaskMarlinAlphaConsumer(csize);
if (PrismSettings.verbose) {
System.out.println("new alphas with length = " + csize);
}
}
consumer.setBoundsNoClone(outpix_xmin, outpix_ymin, w, h);
renderer.produceAlphas(consumer);
return consumer.getMaskData();
} finally {
if (renderer != null) {
renderer.dispose();
}
// recycle the RendererContext instance
MarlinRenderingEngine.returnRendererContext(rdrCtx);
}
}
static Shape createCenteredStrokedShape(Shape s, BasicStroke stroke)
{
final float lw = (stroke.getType() == BasicStroke.TYPE_CENTERED) ?
stroke.getLineWidth() : stroke.getLineWidth() * 2.0f;
final RendererContext rdrCtx = MarlinRenderingEngine.getRendererContext();
try {
// initialize a large copyable Path2D to avoid a lot of array growing:
final Path2D p2d = rdrCtx.getPath2D();
MarlinPrismUtils.strokeTo(rdrCtx, s, stroke, lw,
rdrCtx.transformerPC2D.wrapPath2D(p2d)
);
// Use Path2D copy constructor (trim)
return new Path2D(p2d);
} finally {
// recycle the RendererContext instance
MarlinRenderingEngine.returnRendererContext(rdrCtx);
}
}
}